diff -u --recursive --new-file v2.4.2/linux/CREDITS linux/CREDITS
--- v2.4.2/linux/CREDITS	Wed Feb 21 18:20:08 2001
+++ linux/CREDITS	Sat Mar  3 10:52:18 2001
@@ -316,8 +316,8 @@
 S: Australia
 
 N: Hugh Blemings
-E: hugh@linuxcare.com
-W: http://www.linuxcare.com.au/hugh/
+E: hugh@misc.nu
+W: http://misc.nu/hugh/
 D: Author and maintainer of the Keyspan USB to Serial drivers
 S: Po Box 234
 S: Belconnen ACT 2616
@@ -679,12 +679,8 @@
 
 N: Cort Dougan
 E: cort@fsmlabs.com
-W: http://www.ppc.kernel.org/~cort/
+W: http://www.fsmlabs.com/linuxppcbk.html
 D: PowerPC
-S: Finite State Machine Labs
-S: P.O. 1829
-S: Socorro, New Mexico 87801
-S: USA
 
 N: Oleg Drokin
 E: green@ccssu.crimea.ua
@@ -1026,11 +1022,11 @@
 S: Canada
 
 N: Richard Günther
-E: richard.guenther@student.uni-tuebingen.de
+E: rguenth@tat.physik.uni-tuebingen.de
+W: http://www.tat.physik.uni-tuebingen.de/~rguenth
 P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2  93 7A 32 42 45 37 23 57
 D: binfmt_misc
-S: Fichtenweg 3/511
-S: 72076 Tübingen
+S: 72074 Tübingen
 S: Germany
 
 N: Justin Guyett
@@ -1347,9 +1343,7 @@
 
 N: Dave Jones
 E: davej@suse.de
-E: dave@powertweak.com
-E: djones2@glam.ac.uk
-W: http://powertweak.sourceforge.net
+W: http://www.suse.de/~davej
 D: Moved PCI bridge tuning to userspace (Powertweak).
 D: Centaur/IDT Winchip/Winchip 2 tweaks.
 D: AFFS fixes for 2.3.x
@@ -2191,15 +2185,15 @@
 S: USA
 
 N: Kai Petzke
-E: wpp@marie.physik.tu-berlin.de
-W: http://physik.tu-berlin.de/~wpp
-P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38  2E 3E 31 79 C3 65 5D E1 
+E: petzke@teltarif.de
+W: http://www.teltarif.de/
+P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38  2E 3E 31 79 C3 65 5D E1
 D: Driver for Laser Magnetic Storage CD-ROM
 D: Some kernel bug fixes
 D: Port of the database Postgres
-D: "Unix fuer Jedermann" a German introduction to linux (see my web page)
-S: M"ullerstr. 69
-S: 13349 Berlin
+D: Book: "Linux verstehen und anwenden" (Hanser-Verlag)
+S: Triftstra=DFe 55
+S: 13353 Berlin
 S: Germany
 
 N: Emanuel Pirker
diff -u --recursive --new-file v2.4.2/linux/Documentation/Changes linux/Documentation/Changes
--- v2.4.2/linux/Documentation/Changes	Wed Feb 21 18:20:08 2001
+++ linux/Documentation/Changes	Tue Mar  6 19:44:34 2001
@@ -54,7 +54,7 @@
 o  util-linux             2.10o                   # fdformat --version
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.19                    # tune2fs
-o  reiserfsprogs          3.x.0b                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.x.0d                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -316,7 +316,7 @@
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfs_utils-3.6.25-fsck-3.x.0b.tar.gz>
+o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0d.tar.gz>
 
 LVM toolset
 -----------
diff -u --recursive --new-file v2.4.2/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.2/linux/Documentation/Configure.help	Wed Feb 21 18:20:08 2001
+++ linux/Documentation/Configure.help	Fri Mar 23 11:47:23 2001
@@ -1501,15 +1501,6 @@
 
   If unsure, say Y.
 
-RAID-1/RAID-5 code (DANGEROUS)
-CONFIG_RAID15_DANGEROUS
-  This new RAID1/RAID5 code has been freshly merged, and has not seen
-  enough testing yet. While there are no known bugs in it, it might
-  destroy your filesystems, eat your data and start World War III.
-  You have been warned.
-
-  If unsure, say N.
-
 RAID-1 (mirroring) mode
 CONFIG_MD_RAID1
   A RAID-1 set consists of several disk drives which are exact copies
@@ -1989,6 +1980,40 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+TCPMSS target support
+CONFIG_IP_NF_TARGET_TCPMSS
+  This option adds a `TCPMSS' target, which allows you to alter the
+  MSS value of TCP SYN packets, to control the maximum size for that
+  connection (usually limiting it to your outgoing interface's MTU
+  minus 40).
+
+  This is used to overcome criminally braindead ISPs or servers which
+  block ICMP Fragmentation Needed packets.  The symptoms of this
+  problem are that everything works fine from your Linux
+  firewall/router, but machines behind it can never exchange large
+  packets:
+	1) Web browsers connect, then hang with no data received.
+	2) Small mail works fine, but large emails hang.
+	3) ssh works fine, but scp hangs after initial handshaking.
+
+  Workaround: activate this option and add a rule to your firewall
+  configuration like:
+
+        iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
+		 -j TCPMSS --clamp-mss-to-pmtu
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+tcpmss match support
+CONFIG_IP_NF_MATCH_TCPMSS
+  This option adds a `tcpmss' match, which allows you to examine the
+  MSS value of TCP SYN packets, which control the maximum packet size
+  for that connection.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 LOG target support
 CONFIG_IP_NF_TARGET_LOG
   This option adds a `LOG' target, which allows you to create rules in
@@ -2019,6 +2044,73 @@
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt.  If unsure, say `N'.
 
+IP6 tables support (required for filtering/masq/NAT)
+CONFIG_IP6_NF_IPTABLES
+  ip6tables is a general, extensible packet identification framework.
+  Currently only the packet filtering and packet mangling subsystem
+  for IPv6 use this, but connection tracking is going to follow.
+  Say 'Y' or 'M' here if you want to use either of those.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+IPv6 limit match support
+CONFIG_IP6_NF_MATCH_LIMIT
+  limit matching allows you to control the rate at which a rule can be
+  matched: mainly useful in combination with the LOG target ("LOG
+  target support", below) and to avoid some Denial of Service attacks.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+MAC address match support
+CONFIG_IP6_NF_MATCH_MAC
+  mac matching allows you to match packets based on the source
+  ethernet address of the packet.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+netfilter mark match support
+CONFIG_IP6_NF_MATCH_MARK
+  Netfilter mark matching allows you to match packets based on the
+  `nfmark' value in the packet.  This can be set by the MARK target
+  (see below).
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+Packet filtering
+CONFIG_IP6_NF_FILTER
+  Packet filtering defines a table `filter', which has a series of
+  rules for simple packet filtering at local input, forwarding and
+  local output.  See the man page for iptables(8).
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+Packet mangling
+CONFIG_IP6_NF_MANGLE
+  This option adds a `mangle' table to iptables: see the man page for
+  iptables(8).  This table is used for various packet alterations
+  which can effect how the packet is routed.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+MARK target support
+CONFIG_IP6_NF_TARGET_MARK
+  This option adds a `MARK' target, which allows you to create rules
+  in the `mangle' table which alter the netfilter mark (nfmark) field
+  associated with the packet packet prior to routing. This can change
+  the routing method (see `IP: use netfilter MARK value as routing
+  key') and can also be used by other subsystems to change their
+  behavior.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+
 TCP Explicit Congestion Notification support
 CONFIG_INET_ECN
   Explicit Congestion Notification (ECN) allows routers to notify
@@ -5469,6 +5561,45 @@
 
 Adaptec AIC7xxx chipset SCSI controller support
 CONFIG_SCSI_AIC7XXX
+  This driver supports all of Adaptec's PCI based SCSI controllers (not
+  the hardware RAID controllers though) as well as the aic7770 based
+  EISA and VLB SCSI controllers (the 274x and 284x series).  This is
+  an Adaptec sponsored driver written by Justin Gibbs.  It is intended
+  to replace the previous aic7xxx driver maintained by Doug Ledford since
+  Doug is no longer maintaining that driver.
+
+Default number of TCQ commands per device
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+  Specify the number of commands you would like to allocate per SCSI
+  device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+  This is an upper bound value for the number of tagged transactions
+  to be used for any device.  The aic7xxx driver will automatically
+  vary this number based on device behavior.  For devices with a
+  fixed maximum, the driver will eventually lock to this maximum
+  and display a console message inidicating this value.
+
+  Note: Unless you experience some type of device failure, the default
+	value, no enforced limit, should work for you.
+
+  Default: 253
+
+Initial Bus Reset Settle Delay
+CONFIG_AIC7XXX_RESET_DELAY
+  The number of milliseconds to delay after an initial bus reset.
+  The bus settle delay following all error recovery actions is
+  dictated by the SCSI layer and is not affected by this value.
+
+  Default: 5000 (5 seconds)
+
+Old Adaptec AIC7xxx chipset SCSI controller support
+CONFIG_SCSI_AIC7XXX_OLD
+  WARNING This driver is an older aic7xxx driver and is no longer under
+  active development.  Adaptec, Inc. is writing a new driver to take the
+  place of this one, and it is recommended that whenever possible, people
+  should use the new Adaptec written driver instead of this one.  This
+  driver will eventually be phased out entirely.
+
   This is support for the various aic7xxx based Adaptec SCSI
   controllers. These include the 274x EISA cards; 284x VLB cards;
   2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and
@@ -5490,7 +5621,7 @@
 
   Information on the configuration options for this controller can be
   found by checking the help file for each of the available
-  configuration options. You should read drivers/scsi/README.aic7xxx
+  configuration options. You should read drivers/scsi/aic7xxx_old/README.aic7xxx
   at a minimum before contacting the maintainer with any questions.
   The SCSI-HOWTO, available from
   http://www.linuxdoc.org/docs.html#howto , can also be of great
@@ -5499,10 +5630,10 @@
   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 Documentation/modules.txt. The module will be
-  called aic7xxx.o.
+  called aic7xxx_old.o.
 
 Enable or Disable Tagged Command Queueing by default
-CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
   This option causes the aic7xxx driver to attempt to use Tagged
   Command Queueing (TCQ) on all devices that claim to support it. 
 
@@ -5536,7 +5667,7 @@
   reduce performance.
 
 Default number of TCQ commands per device
-CONFIG_AIC7XXX_CMDS_PER_DEVICE
+CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
   Specify the number of commands you would like to allocate per SCSI
   device when Tagged Command Queueing (TCQ) is enabled on that device.
 
@@ -5557,7 +5688,7 @@
   Default: 8
 
 Collect statistics to report in /proc
-CONFIG_AIC7XXX_PROC_STATS
+CONFIG_AIC7XXX_OLD_PROC_STATS
   This option tells the driver to keep track of how many commands have
   been sent to each particular device and report that information to
   the user via the /proc/scsi/aic7xxx/n file, where n is the number of
@@ -5569,21 +5700,6 @@
 
   If unsure, say N.
 
-Delay in seconds after SCSI bus reset
-CONFIG_AIC7XXX_RESET_DELAY
-  This sets how long the driver will wait after resetting the SCSI bus
-  before attempting to communicate with the devices on the SCSI bus
-  again. This delay will be used during the reset phase at bootup time
-  as well as after any reset that might occur during normal operation.
-  Reasonable numbers range anywhere from 5 to 15 seconds depending on
-  your devices. DAT tape drives are notorious for needing more time
-  after a bus reset to be ready for the next command, but most hard
-  drives and CD-ROM devices are ready in only a few seconds. This
-  option has a maximum upper limit of 20 seconds to avoid bad
-  interactions between the aic7xxx driver and the rest of the Linux
-  kernel. The default value has been reduced to 5 seconds. If this
-  doesn't work with your hardware, try increasing this value.
-
 IBM ServeRAID Support
 CONFIG_SCSI_IPS
   This is support for the IBM ServeRAID hardware RAID controllers.
@@ -7358,6 +7474,18 @@
   location). You also want to check out the PCMCIA-HOWTO, available
   from http://www.linuxdoc.org/docs.html#howto .
 
+Hermes (AT&T/Lucent/Orinoco/3com) wireless support
+CONFIG_PCMCIA_HERMES
+  A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+  as the Lucent/Orinoco cards and the Cabletron RoamAbout. It should
+  also be usable on Prism II based cards such as the Farallon Skyline
+  and the 3Com AirConnect.
+
+  To use your PC-cards, you will need supporting software from David
+  Hinds' pcmcia-cs package (see the file Documentation/Changes for
+  location). You also want to check out the PCMCIA-HOWTO, available
+  from http://www.linuxdoc.org/docs.html#howto .
+
 Aviator/Raytheon 2.4MHz wireless support
 CONFIG_PCMCIA_RAYCS
   Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
@@ -8390,22 +8518,6 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)
-CONFIG_RTL8129
-  This is NOT for RTL-8139 cards.  Instead, select the 8139too driver
-  (CONFIG_8139TOO).
-  This is a driver for the Fast Ethernet PCI network cards based on
-  the RTL8129 chip. If you have one of those, say Y and
-  read the Ethernet-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto .
-
-  Note: the 8029 is a NE2000 PCI clone, you can use the NE2K-PCI driver.
-
-  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 Documentation/modules.txt. This is recommended.
-  The module will be called rtl8129.o.
-
 RealTek RTL-8139 PCI Fast Ethernet Adapter support
 CONFIG_8139TOO
   This is a driver for the Fast Ethernet PCI network cards based on
@@ -8481,7 +8593,7 @@
   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 Documentation/modules.txt. This is recommended.
-  The module will be called starfile.o.
+  The module will be called starfire.o.
   
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
@@ -9399,7 +9511,7 @@
 
   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 will be called olympic.o. If you want to compile it
+  The module will be called olympic.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
   Also read the file Documentation/networking/olympic.txt or check the
@@ -9439,7 +9551,7 @@
 
   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 will be called tms380tr.o. If you want to compile it
+  The module will be called tms380tr.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 Generic TMS380 PCI support
@@ -9454,7 +9566,7 @@
 
   This driver is available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will will be called tmspci.o. If you want to compile it
+  The module will be called tmspci.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 Madge Smart 16/4 PCI Mk2 support
@@ -9464,7 +9576,7 @@
 
   This driver is available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will will be called abyss.o. If you want to compile it
+  The module will be called abyss.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 Madge Smart 16/4 Ringode MicroChannel 
@@ -9474,7 +9586,7 @@
 
   This driver is available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will will be called madgemc.o. If you want to compile it
+  The module will be called madgemc.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 SMC ISA TokenRing adapter support
@@ -9490,7 +9602,7 @@
 
   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 will be called smctr.o. If you want to compile it
+  The module will be called smctr.o. If you want to compile it
   as a module, say M here and read Documentation/modules.txt.
 
 Sun Happy Meal 10/100baseT support
@@ -10514,6 +10626,32 @@
   inserted in and removed from the running kernel whenever you want).
   The module will be called mct_u232.o.  If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
+
+USB Edgeport Serial Driver
+CONFIG_USB_SERIAL_EDGEPORT
+  Say Y here if you want to use any of the following devices from
+  Inside Out Networks (Digi):
+       Edgeport/4
+       Rapidport/4
+       Edgeport/4t
+       Edgeport/2
+       Edgeport/4i
+       Edgeport/2i
+       Edgeport/421
+       Edgeport/21
+       Edgeport/8
+       Edgeport/8 Dual
+       Edgeport/2D8
+       Edgeport/4D8
+       Edgeport/8i
+       Edgeport/2 DIN
+       Edgeport/4 DIN
+       Edgeport/16 Dual
+
+  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 io_edgeport.o.  If you want to compile it 
+  as a module, say M here and read Documentation/modules.txt.
 
 USB Serial Converter verbose debug
 CONFIG_USB_SERIAL_DEBUG
diff -u --recursive --new-file v2.4.2/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
--- v2.4.2/linux/Documentation/DMA-mapping.txt	Mon Dec 11 13:45:42 2000
+++ linux/Documentation/DMA-mapping.txt	Tue Mar  6 22:44:15 2001
@@ -59,7 +59,7 @@
 1) Use some non-DMA mode for data transfer, if possible.
 2) Ignore this device and do not initialize it.
 
-It is recommended that your driver print a kernel KERN_WARN message
+It is recommended that your driver print a kernel KERN_WARNING message
 when you do one of these two things.  In this manner, if a user of
 your driver reports that performance is bad or that the device is not
 even detected, you can ask him for the kernel messages to find out
@@ -71,12 +71,35 @@
 	if (! pci_dma_supported(pdev, 0x00ffffff))
 		goto ignore_this_device;
 
+When DMA is possible for a given mask, the PCI layer must be informed of the
+mask for later allocation operations on the device.  This is achieved by
+setting the dma_mask member of the pci_dev structure, like so:
+
+#define MY_HW_DMA_MASK 0x00ffffff
+
+	if (! pci_dma_supported(pdev, MY_HW_DMA_MASK))
+		goto ignore_this_device;
+
+	pdev->dma_mask = MY_HW_DMA_MASK;
+
+A helper function is provided which performs this common code sequence:
+
+	int pci_set_dma_mask(struct pci_dev *pdev, dma_addr_t device_mask)
+
+Unlike pci_dma_supported(), this returns -EIO when the PCI layer will not be
+able to DMA with addresses restricted by that mask, and returns 0 when DMA
+transfers are possible.  If the call succeeds, the dma_mask will have been
+updated so that your driver need not worry about it.
+
 There is a case which we are aware of at this time, which is worth
 mentioning in this documentation.  If your device supports multiple
 functions (for example a sound card provides playback and record
 functions) and the various different functions have _different_
 DMA addressing limitations, you may wish to probe each mask and
-only provide the functionality which the machine can handle.
+only provide the functionality which the machine can handle.  It
+is important that the last call to pci_set_dma_mask() be for the 
+most specific mask.
+
 Here is pseudo-code showing how this might be done:
 
 	#define PLAYBACK_ADDRESS_BITS	0xffffffff
@@ -86,14 +109,14 @@
 	struct pci_dev *pdev;
 
 	...
-	if (pci_dma_supported(pdev, PLAYBACK_ADDRESS_BITS)) {
+	if (pci_set_dma_mask(pdev, PLAYBACK_ADDRESS_BITS)) {
 		card->playback_enabled = 1;
 	} else {
 		card->playback_enabled = 0;
 		printk(KERN_WARN "%s: Playback disabled due to DMA limitations.\n",
 		       card->name);
 	}
-	if (pci_dma_supported(pdev, RECORD_ADDRESS_BITS)) {
+	if (pci_set_dma_mask(pdev, RECORD_ADDRESS_BITS)) {
 		card->record_enabled = 1;
 	} else {
 		card->record_enabled = 0;
diff -u --recursive --new-file v2.4.2/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl
--- v2.4.2/linux/Documentation/DocBook/kernel-api.tmpl	Sat Dec 30 18:16:13 2000
+++ linux/Documentation/DocBook/kernel-api.tmpl	Fri Mar  2 18:43:10 2001
@@ -34,6 +34,18 @@
  </bookinfo>
 
 <toc></toc>
+
+  <chapter id="Basics">
+     <title>Driver Basic</title>
+     <sect1><title>Driver Entry and Exit points</title>
+!Iinclude/linux/init.h
+     </sect1>
+
+     <sect1><title>Atomics</title>
+!Iinclude/asm-i386/atomic.h
+     </sect1>
+  </chapter>
+
   <chapter id="adt">
      <title>Data Types</title>
      <sect1><title>Doubly Linked Lists</title>
diff -u --recursive --new-file v2.4.2/linux/Documentation/SAK.txt linux/Documentation/SAK.txt
--- v2.4.2/linux/Documentation/SAK.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/SAK.txt	Thu Mar 22 09:20:45 2001
@@ -0,0 +1,88 @@
+Linux 2.4.2 Secure Attention Key (SAK) handling
+18 March 2001, Andrew Morton <andrewm@uow.edu.au>
+
+An operating system's Secure Attention Key is a security tool which is
+provided as protection against trojan password capturing programs.  It
+is an undefeatable way of killing all programs which could be
+masquerading as login applications.  Users need to be taught to enter
+this key sequence before they log in to the system.
+
+From the PC keyboard, Linux has two similar but different ways of
+providing SAK.  One is the ALT-SYSRQ-K sequence.  You shouldn't use
+this sequence.  It is only available if the kernel was compiled with
+sysrq support.
+
+The proper way of generating a SAK is to define the key sequence using
+`loadkeys'.  This will work whether or not sysrq support is compiled
+into the kernel.
+
+SAK works correctly when the keyboard is in raw mode.  This means that
+once defined, SAK will kill a running X server.  If the system is in
+run level 5, the X server will restart.  This is what you want to
+happen.
+
+What key sequence should you use? Well, CTRL-ALT-DEL is used to reboot
+the machine.  CTRL-ALT-BACKSPACE is magical to the X server.  We'll
+choose CTRL-ALT-PAUSE.
+
+In your rc.sysinit (or rc.local) file, add the command
+
+	echo "control alt keycode 101 = SAK" | /bin/loadkeys
+
+And that's it!  Only the superuser may reprogram the SAK key.
+
+
+NOTES
+=====
+
+1: Linux SAK is said to be not a "true SAK" as is required by
+   systems which implement C2 level security.  This author does not
+   know why.
+
+
+2: On the PC keyboard, SAK kills all applications which have
+   /dev/console opened.
+
+   Unfortunately this includes a number of things which you don't
+   actually want killed.  This is because these appliccaitons are
+   incorrectly holding /dev/console open.  Be sure to complain to your
+   Linux distributor about this!
+
+   You can identify processes which will be killed by SAK with the
+   command
+
+	# ls -l /proc/[0-9]*/fd/* | grep console
+	l-wx------    1 root     root           64 Mar 18 00:46 /proc/579/fd/0 -> /dev/console
+
+   Then:
+
+	# ps aux|grep 579
+	root       579  0.0  0.1  1088  436 ?        S    00:43   0:00 gpm -t ps/2
+
+   So `gpm' will be killed by SAK.  This is a bug in gpm.  It should
+   be closing standard input.  You can work around this by finding the
+   initscript which launches gpm and changing it thusly:
+
+   Old:
+
+	daemon gpm
+
+   New:
+
+	daemon gpm < /dev/null
+
+   Vixie cron also seems to have this problem, and needs the same treatment.
+
+   Also, one prominent Linux distribution has the following three
+   lines in its rc.sysinit and rc scripts:
+
+	exec 3<&0
+	exec 4>&1
+	exec 5>&2
+
+   These commands cause *all* daemons which are launched by the
+   initscripts to have file descriptors 3, 4 and 5 attached to
+   /dev/console.  So SAK kills them all.  A workaround is to simply
+   delete these lines, but this may cause system management
+   applications to malfunction - test everything well.
+
diff -u --recursive --new-file v2.4.2/linux/Documentation/arm/SA1100/Brutus linux/Documentation/arm/SA1100/Brutus
--- v2.4.2/linux/Documentation/arm/SA1100/Brutus	Fri May 12 11:21:20 2000
+++ linux/Documentation/arm/SA1100/Brutus	Fri Mar  2 11:12:06 2001
@@ -3,7 +3,7 @@
 
 http://developer.intel.com/design/strong/applnots/sa1100lx/getstart.htm
 
-To compile for Brutus, you must issue the following comands:
+To compile for Brutus, you must issue the following commands:
 
 	make brutus_config
 	make config
diff -u --recursive --new-file v2.4.2/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt
--- v2.4.2/linux/Documentation/binfmt_misc.txt	Tue Apr 28 14:22:03 1998
+++ linux/Documentation/binfmt_misc.txt	Fri Mar  2 18:38:37 2001
@@ -81,6 +81,6 @@
 
 
 There is a web page about binfmt_misc at
-http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html
+http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html
 
-Richard Günther, richard.guenther@student.uni-tuebingen.de
+Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
diff -u --recursive --new-file v2.4.2/linux/Documentation/dnotify.txt linux/Documentation/dnotify.txt
--- v2.4.2/linux/Documentation/dnotify.txt	Tue Nov 14 10:54:07 2000
+++ linux/Documentation/dnotify.txt	Fri Mar  2 18:38:37 2001
@@ -28,7 +28,7 @@
 information.  However, if the F_SETSIG fcntl(2) call is used to let the
 kernel know which signal to deliver, a siginfo structure will be passed to
 the signal handler and the si_fd member of that structure will contain the
-file descriptor associated with the direcory in which the event occured.
+file descriptor associated with the directory in which the event occurred.
 
 Preferably the application will choose one of the real time signals
 (SIGRTMIN + <n>) so that the notifications may be queued.  This is
diff -u --recursive --new-file v2.4.2/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.4.2/linux/Documentation/ioctl-number.txt	Wed Feb 21 18:20:09 2001
+++ linux/Documentation/ioctl-number.txt	Fri Mar  2 17:50:22 2001
@@ -92,6 +92,7 @@
 					<http://linux01.gwdg.de/~alatham/ppdd.html>
 'M'	all	linux/soundcard.h	conflict!
 'M'	00-1F	linux/isicom.h		conflict!
+'N'	00-1F	drivers/usb/scanner.h
 'P'	all	linux/soundcard.h
 'Q'	all	linux/soundcard.h
 'R'	00-1F	linux/random.h
diff -u --recursive --new-file v2.4.2/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE
--- v2.4.2/linux/Documentation/isdn/INTERFACE	Wed Feb 21 18:20:09 2001
+++ linux/Documentation/isdn/INTERFACE	Fri Mar  2 18:38:37 2001
@@ -1,4 +1,4 @@
-$Id: INTERFACE,v 1.15 1999/08/25 20:02:13 werner Exp $
+$Id: INTERFACE,v 1.15.8.1 2001/02/16 16:43:22 kai Exp $
 
 Description of the Interface between Linklevel and Hardwarelevel
   of isdn4linux:
@@ -481,7 +481,7 @@
       driver      = driver-Id
       command     = ISDN_CMD_PROT_IO
       arg         = The lower 8 Bits define the addressed protocol as defined
-                    in ISDN_PTYPE..., the upper bits are used to differenciate
+                    in ISDN_PTYPE..., the upper bits are used to differentiate
                     the protocol specific CMD.  
       
       para        = protocol and function specific. See isdnif.h for detail.
diff -u --recursive --new-file v2.4.2/linux/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon
--- v2.4.2/linux/Documentation/isdn/README.eicon	Sat Nov 11 18:58:02 2000
+++ linux/Documentation/isdn/README.eicon	Fri Mar  2 11:12:12 2001
@@ -100,17 +100,6 @@
 the necessary D-Channel traces for isdnlog.
 
 
-FILECHECK:
-A part of the eicon driver source code files are provided
-by Eicon Technology. In order to get the best support from Eicon,
-these files are tested with a checksum, just to know if the files
-were modified. This does *not* mean, you are not allowed to modify the
-driver. If you want to improve the driver or you fix a bug, please do
-so and let me (or Eicon) know, about the necessary changes. So
-every user knows, if the driver he uses is modified or checked with
-Eicon files. When the driver has been loaded, in the syslog you will
-find something like "verified" or "modified" right after the version.
-
 
 Thanks to 
 	Deutsche Mailbox Saar-Lor-Lux GmbH
diff -u --recursive --new-file v2.4.2/linux/Documentation/isdn/README.hysdn linux/Documentation/isdn/README.hysdn
--- v2.4.2/linux/Documentation/isdn/README.hysdn	Wed Feb 21 18:20:09 2001
+++ linux/Documentation/isdn/README.hysdn	Fri Mar  2 11:12:12 2001
@@ -1,4 +1,4 @@
-$Id: README.hysdn,v 1.3 2000/08/06 09:22:51 armin Exp $
+$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $
 The hysdn driver has been written by
 by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) 
 for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
diff -u --recursive --new-file v2.4.2/linux/Documentation/kernel-doc-nano-HOWTO.txt linux/Documentation/kernel-doc-nano-HOWTO.txt
--- v2.4.2/linux/Documentation/kernel-doc-nano-HOWTO.txt	Mon Jun 19 12:56:07 2000
+++ linux/Documentation/kernel-doc-nano-HOWTO.txt	Fri Mar  2 18:43:11 2001
@@ -57,7 +57,8 @@
 If you want to see man pages instead, you can do this:
 
 $ cd linux
-$ scripts/kernel-doc -man $(find -name '*.c' '*.h') | split-man.pl /tmp/man
+$ scripts/kernel-doc -man $(find -name '*.c') | split-man.pl /tmp/man
+$ scripts/kernel-doc -man $(find -name '*.h') | split-man.pl /tmp/man
 
 Here is split-man.pl:
 
@@ -68,7 +69,7 @@
    die "where do I put the results?\n";
 }
 
-mkdir $ARGV[0],0777 or die "Can't create $ARGV[0]: $!\n";
+mkdir $ARGV[0],0777;
 $state = 0;
 while (<STDIN>) {
     if (/^\.TH \"[^\"]*\" 4 \"([^\"]*)\"/) {
diff -u --recursive --new-file v2.4.2/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.4.2/linux/Documentation/kernel-parameters.txt	Sat Dec 30 11:23:13 2000
+++ linux/Documentation/kernel-parameters.txt	Fri Mar  2 11:02:15 2001
@@ -188,8 +188,10 @@
 
 	es1371=		[HW,SOUND]
  
-	ether=		[HW,NET] Ethernet cards parameters (iomem, irq,
-			dev_name).
+	ether=		[HW,NET] Ethernet cards parameters (irq,
+			base_io_addr, mem_start, mem_end, name.
+			(mem_start is often overloaded to mean something
+			different and driver-specific).
 
 	fd_mcs=		[HW,SCSI]
 
@@ -328,7 +330,11 @@
 
 	ncr53c8xx=	[HW,SCSI]
 
-	netdev=		[NET]
+	netdev=		[NET] Ethernet cards parameters (irq,
+			base_io_addr, mem_start, mem_end, name.
+			(mem_start is often overloaded to mean something
+			different and driver-specific).
+			(cf: ether=)
  
 	nfsaddrs=	[NFS]
 
diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt
--- v2.4.2/linux/Documentation/networking/8139too.txt	Mon Oct 30 12:54:42 2000
+++ linux/Documentation/networking/8139too.txt	Fri Mar  2 11:02:14 2001
@@ -180,6 +180,52 @@
 Change History
 --------------
 
+Version 0.9.15 - February 20, 2001
+
+* Call pci_enable_device to wake up/assign resource to device,
+  before actually using it.
+* Support wacky clone PCI ids (report from Norival Toniato Junior)
+* Text spelling corrections
+* Make sure tp->phys[] is signed
+* Always wake queue after hw restart, in tx_timeout
+* Record time of last received packet
+
+
+Version 0.9.14 - January 11, 2001
+
+* Merge some changes from Becker version 1.13:
+	* Add DFE 538TX PCI id
+	* MII read/write functions updated
+	* Cfg93[45]6 lock/unlock fix
+	* RTL-8129 (MII) support
+* Clean up spinlocking
+
+
+Version 0.9.13 - December, 2000
+
+* Clear blocked signals, avoid buffer overrun setting current->comm
+* Remove bogus PCI BAR length assertions
+* Remove unused 'debug' module parameter
+
+
+Version 0.9.12 - November 23, 2000
+
+* Kill major Tx stop/wake queue race
+* Use SET_MODULE_OWNER and fix module unload race
+* Fix cable length ("Twister") tuning
+* Proper media[] array length checking
+* Replace timer with kernel thread for twister tuning state machine
+  and media checking.  Fixes mdio_xxx locking, now mdio_xxx is always
+  protected by rtnl_lock semaphore.
+* Correct some sledgehammer a.k.a. overzealous spin-locks
+* Performance: Eliminate atomic_t for Tx counters, we don't need it
+* Performance: Don't copy Tx buffer if the rare case occurs where it
+  is aligned perfectly for us.
+* Eliminate needless casting of dev->priv
+* PIO mode selection and Twister tuning are now CONFIG_xxx options
+  (though purposefully not in net/Config.in... yet)
+
+
 Version 0.9.11 - October 28, 2000
 
 * Do not fail when PIO and MMIO region lengths do not match.
diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/tlan.txt linux/Documentation/networking/tlan.txt
--- v2.4.2/linux/Documentation/networking/tlan.txt	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/networking/tlan.txt	Tue Mar  6 19:44:34 2001
@@ -1,11 +1,11 @@
 (C) 1997-1998 Caldera, Inc.
 (C) 1998 James Banks
-(C) 1999-2000 Torben Mathiasen <tmm@image.dk, torben.mathiasen@compaq.com>
+(C) 1999-2001 Torben Mathiasen <tmm@image.dk, torben.mathiasen@compaq.com>
 
-For driver information/updates visit http://tlan.kernel.dk
+For driver information/updates visit http://opensource.compaq.com
 
 
-TLAN driver for Linux, version 1.8a
+TLAN driver for Linux, version 1.14a
 README
 
 
@@ -94,6 +94,16 @@
 	   speeds with kernel-parameters. 
 	   ether=0,0,0x12,0,eth0 will force link to 100Mbps Half-Duplex.
 
+	7. If you have more than one tlan adapter in your system, you can
+	   use the above options on a per adapter basis. To force a 100Mbit/HD
+	   link with your eth1 adapter use:
+	   
+	   insmod tlan speed=0,100 duplex=0,1
+
+	   Now eth0 will use auto-neg and eth1 will be forced to 100Mbit/HD.
+	   Note that the tlan driver supports a maximum of 8 adapters.
+
+
 III.  Things to try if you have problems.
 	1. Make sure your card's PCI id is among those listed in
 	   section I, above.
@@ -103,5 +113,5 @@
 
 There is also a tlan mailing list which you can join by sending "subscribe tlan"
 in the body of an email to majordomo@vuser.vu.union.edu.
-There is also a tlan website at http://tlan.kernel.dk
+There is also a tlan website at http://opensource.compaq.com
 
diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt
--- v2.4.2/linux/Documentation/networking/tulip.txt	Tue Nov  7 11:08:09 2000
+++ linux/Documentation/networking/tulip.txt	Fri Mar  2 11:02:14 2001
@@ -148,6 +148,17 @@
 
 Version history
 ===============
+0.9.14 (February 20, 2000):
+* Fix PNIC problems (Manfred Spraul)
+* Add new PCI id for Accton comet
+* Support Davicom tulips
+* Fix oops in eeprom parsing
+* Enable workarounds for early PCI chipsets
+* IA64, hppa csr0 support
+* Support media types 5, 6
+* Interpret a bit more of the 21142 SROM extended media type 3
+* Add missing delay in eeprom reading
+
 0.9.11 (November 3, 2000):
 * Eliminate extra bus accesses when sharing interrupts (prumpf)
 * Barrier following ownership descriptor bit flip (prumpf)
diff -u --recursive --new-file v2.4.2/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt
--- v2.4.2/linux/Documentation/networking/vortex.txt	Fri Sep 15 16:28:25 2000
+++ linux/Documentation/networking/vortex.txt	Tue Mar  6 19:13:51 2001
@@ -6,7 +6,7 @@
 This document describes the usage and errata of the 3Com "Vortex" device
 driver for Linux, 3c59x.c.
 
-The driver was written by Donald Becker <becker@cesdis.gsfc.nasa.gov>
+The driver was written by Donald Becker <becker@scyld.com>
 
 Don is no longer the prime maintainer of this version of the driver. 
 Please report problems to one or more of:
@@ -34,6 +34,7 @@
    3c900 Boomerang 10baseT
    3c900 Boomerang 10Mbps Combo
    3c900 Cyclone 10Mbps TPO
+   3c900B Cyclone 10Mbps T
    3c900 Cyclone 10Mbps Combo
    3c900 Cyclone 10Mbps TPC
    3c900B-FL Cyclone 10base-FL
@@ -116,7 +117,11 @@
 full_duplex=N1,N2,N3...
 
   Similar to bit 9 of 'options'.  Forces the corresponding card into
-  full-duplex mode.
+  full-duplex mode.  Please use this in preference to the `options'
+  parameter.
+
+  In fact, please don't use this at all! You're better off getting
+  autonegotiation working properly.
 
 flow_ctrl=N1,N2,N3...
 
@@ -156,6 +161,33 @@
   is exceeded the interrupt service routine gives up and generates a
   warning message "eth0: Too much work in interrupt".
 
+hw_checksums=N1,N2,N3,...
+
+  Recent 3com NICs are able to generate IPv4, TCP and UDP checksums
+  in hardware.  Linux has used the Rx checksumming for a long time. 
+  The "zero copy" patch which is planned for the 2.4 kernel series
+  allows you to make use of the NIC's DMA scatter/gather and transmit
+  checksumming as well.
+
+  The driver is set up so that, when the zerocopy patch is applied,
+  all Tornado and Cyclone devices will use S/G and Tx checksums.
+
+  This module parameter has been provided so you can override this
+  decision.  If you think that Tx checksums are causing a problem, you
+  may disable the feature with `hw_checksums=0'.
+
+  If you think your NIC should be performing Tx checksumming and the
+  driver isn't enabling it, you can force the use of hardware Tx
+  checksumming with `hw_checksums=1'.
+
+  The driver drops a message in the logfiles to indicate whether or
+  not it is using hardware scatter/gather and hardware Tx checksums.
+
+  Scatter/gather and hardware checksums provide considerable
+  performance improvement for the sendfile() system call, but a small
+  decrease in throughput for send().  There is no effect upon receive
+  efficiency.
+
 compaq_ioaddr=N
 compaq_irq=N
 compaq_device_id=N
@@ -168,7 +200,35 @@
   decides that the transmitter has become stuck and needs to be reset. 
   This is mainly for debugging purposes, although it may be advantageous
   to increase this value on LANs which have very high collision rates.
-  The default value is 400 (0.4 seconds).
+  The default value is 5000 (5.0 seconds).
+
+enable_wol=N1,N2,N3,...
+
+  Enable Wake-on-LAN support for the relevant interface.  Donald
+  Becker's `ether-wake' application may be used to wake suspended
+  machines.
+
+
+Media selection
+---------------
+
+A number of the older NICs such as the 3c590 and 3c900 series have
+10base2 and AUI interfaces.
+
+Prior to January, 2001 this driver would autoeselect the 10base2 or AUI
+port if it didn't detect activity on the 10baseT port.  It would then
+get stuck on the 10base2 port and a driver reload was necessary to
+switch back to 10baseT.  This behaviour could not be prevented with a
+module option override.
+
+Later (current) versions of the driver _do_ support locking of the
+media type.  So if you load the driver module with
+
+	modprobe 3c59x options=0
+
+it will permanently select the 10baseT port.  Automatic selection of
+other media types does not occur.
+
 
 Additional resources
 --------------------
@@ -177,31 +237,36 @@
 
 Additional documentation is available at Don Becker's Linux Drivers site:
 
-  http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html
+  http://www.scyld.com/network/vortex.html
 
 Donald Becker's driver development site:
 
-     http://www.scyld.com
-     http://cesdis.gsfc.nasa.gov/linux/
+     http://www.scyld.com/network
 
-Don's vortex-diag program is useful for inspecting the NIC's state:
+Donald's vortex-diag program is useful for inspecting the NIC's state:
 
      http://www.scyld.com/diag/#pci-diags
-     http://cesdis.gsfc.nasa.gov/linux/diag/vortex-diag.c
 
-Don's mii-diag program may be used for inspecting and manipulating the
-NIC's Media Independent Interface subsystem:
+Donald's mii-diag program may be used for inspecting and manipulating
+the NIC's Media Independent Interface subsystem:
 
      http://www.scyld.com/diag/#mii-diag
-     http://cesdis.gsfc.nasa.gov/linux/diag/#mii-diag
+
+Donald's wake-on-LAN page:
+
+     http://www.scyld.com/expert/wake-on-lan.html
 
 3Com's documentation for many NICs, including the ones supported by
 this driver is available at 
 
      http://support.3com.com/partners/developer/developer_form.html
 
-A detailed changelog for the modifications which were made for 2.3
-series kernel is available at
+3Com's DOS-based application for setting up the NICs EEPROMs:
+
+	ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
+
+Driver updates and a detailed changelog for the modifications which
+were made for the 2.3/2,4 series kernel is available at
 
      http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3
 
@@ -222,6 +287,21 @@
   tree parameter for the port the machine is plugged into to 'portfast'
   mode.  Otherwise, the negotiation fails.  This has been an issue
   we've noticed for a while but haven't had the time to track down.
+
+  Cisco switches    (Jeff Busch <jbusch@deja.com>)
+
+    My "standard config" for ports to which PC's/servers connect directly:
+
+        interface FastEthernet0/N
+        description machinename
+        load-interval 30
+        spanning-tree portfast
+
+    If autonegotiation is a problem, you may need to specify "speed
+    100" and "duplex full" as well (or "speed 10" and "duplex half").
+
+    WARNING: DO NOT hook up hubs/switches/bridges to these
+    specially-configured ports! The switch will become very confused.
 
 
 Reporting and diagnosing problems
diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/ppc_htab.txt linux/Documentation/powerpc/ppc_htab.txt
--- v2.4.2/linux/Documentation/powerpc/ppc_htab.txt	Wed Mar 10 21:49:10 1999
+++ linux/Documentation/powerpc/ppc_htab.txt	Sat Mar  3 10:52:23 2001
@@ -2,7 +2,7 @@
 =====================================================================
 
 This document and the related code was written by me (Cort Dougan), please
-email me (cort@cs.nmt.edu) if you have questions, comments or corrections.
+email me (cort@fsmlabs.com) if you have questions, comments or corrections.
 
 Last Change: 2.16.98
 
diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/smp.txt linux/Documentation/powerpc/smp.txt
--- v2.4.2/linux/Documentation/powerpc/smp.txt	Thu Apr 29 12:39:07 1999
+++ linux/Documentation/powerpc/smp.txt	Sat Mar  3 10:52:27 2001
@@ -2,7 +2,7 @@
 =====================================================================
 
 This document and the related code was written by me
-(Cort Dougan, cort@cs.nmt.edu) please email me if you have questions,
+(Cort Dougan, cort@fsmlabs.com) please email me if you have questions,
 comments or corrections.
 
 Last Change: 3.31.99
diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt
--- v2.4.2/linux/Documentation/powerpc/sound.txt	Mon Jun 28 13:40:39 1999
+++ linux/Documentation/powerpc/sound.txt	Sat Mar  3 10:52:30 2001
@@ -1,7 +1,7 @@
             Information about PowerPC Sound support
 =====================================================================
 
-Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
+Please mail me (Cort Dougan, cort@fsmlabs.com) if you have questions,
 comments or corrections.
 
 Last Change: 6.16.99
diff -u --recursive --new-file v2.4.2/linux/Documentation/powerpc/zImage_layout.txt linux/Documentation/powerpc/zImage_layout.txt
--- v2.4.2/linux/Documentation/powerpc/zImage_layout.txt	Sat Oct 10 09:53:24 1998
+++ linux/Documentation/powerpc/zImage_layout.txt	Sat Mar  3 10:52:32 2001
@@ -1,7 +1,7 @@
           Information about the Linux/PPC kernel images
 =====================================================================
 
-Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
+Please mail me (Cort Dougan, cort@fsmlabs.com) if you have questions,
 comments or corrections.
 
 This document is meant to answer several questions I've had about how
diff -u --recursive --new-file v2.4.2/linux/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt
--- v2.4.2/linux/Documentation/s390/cds.txt	Wed Feb 21 18:20:09 2001
+++ linux/Documentation/s390/cds.txt	Fri Mar  2 11:12:06 2001
@@ -241,7 +241,7 @@
 
 The get_dev_info_by_irq() / get_dev_info_by_devno() functions return:
 
-      0 - sucessful completion
+      0 - successful completion
 -ENODEV - irq or devno don't specify a known subchannel or device
           number.
 -EINVAL - invalid devinfo value.
@@ -317,7 +317,7 @@
       0 - successful completion
 -ENODEV - irq doesn't specify a valid subchannel number
 -EINVAL - an invalid parameter was detected
--EBUSY  - an irrecoverable I/O error occured or the device is not
+-EBUSY  - an irrecoverable I/O error occurred or the device is not
           operational.
 
 Usage Notes :
@@ -568,7 +568,7 @@
 
 The do_IO() function returns :
 
-      0 - successful completion or request successfuly initiated
+      0 - successful completion or request successfully initiated
 -EBUSY  - the do_io() function was caled out of sequence. The
           device is currently processing a previous I/O request
 -ENODEV - irq doesn't specify a valid subchannel, the device is
@@ -777,7 +777,7 @@
 
 The halt_IO() function returns :
 
-      0 - successful completion or request successfuly initiated
+      0 - successful completion or request successfully initiated
 -EBUSY  - the device is currently performing a synchronous I/O
           operation : do_IO() with flag DOIO_WAIT_FOR_INTERRUPT
           or an error was encountered and the device is currently
diff -u --recursive --new-file v2.4.2/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt
--- v2.4.2/linux/Documentation/sysctl/vm.txt	Mon Aug  7 23:01:34 2000
+++ linux/Documentation/sysctl/vm.txt	Wed Mar 14 14:39:07 2001
@@ -32,7 +32,7 @@
 
 This file controls the operation of the bdflush kernel
 daemon. The source code to this struct can be found in
-linux/mm/buffer.c. It currently contains 9 integer values,
+linux/fs/buffer.c. It currently contains 9 integer values,
 of which 6 are actually used by the kernel.
 
 From linux/fs/buffer.c:
diff -u --recursive --new-file v2.4.2/linux/Documentation/sysrq.txt linux/Documentation/sysrq.txt
--- v2.4.2/linux/Documentation/sysrq.txt	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/sysrq.txt	Thu Mar 22 09:20:45 2001
@@ -29,6 +29,8 @@
            You send a BREAK, then within 5 seconds a command key. Sending
            BREAK twice is interpreted as a normal BREAK.
 
+On Mac   - Press 'Keypad+-F13-<command key>'
+
 On other - If you know of the key combos for other architectures, please
            let me know so I can add them to this section. 
 
diff -u --recursive --new-file v2.4.2/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- v2.4.2/linux/Documentation/usb/usb-serial.txt	Wed Feb 21 18:20:09 2001
+++ linux/Documentation/usb/usb-serial.txt	Mon Mar 19 17:21:54 2001
@@ -223,6 +223,28 @@
  this driver. Also, D-Link's DU-H3SP USB BAY also works with this driver.
 
 
+Inside Out Networks Edgeport Driver
+
+  This driver supports all devices made by Inside Out Networks, specifically
+  the following models:
+       Edgeport/4
+       Rapidport/4
+       Edgeport/4t
+       Edgeport/2
+       Edgeport/4i
+       Edgeport/2i
+       Edgeport/421
+       Edgeport/21
+       Edgeport/8
+       Edgeport/8 Dual
+       Edgeport/2D8
+       Edgeport/4D8
+       Edgeport/8i
+       Edgeport/2 DIN
+       Edgeport/4 DIN
+       Edgeport/16 Dual
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
diff -u --recursive --new-file v2.4.2/linux/Documentation/vm/locking linux/Documentation/vm/locking
--- v2.4.2/linux/Documentation/vm/locking	Fri Oct 13 12:10:30 2000
+++ linux/Documentation/vm/locking	Mon Mar 19 12:35:11 2001
@@ -4,7 +4,7 @@
 from different people about how locking and synchronization is done 
 in the Linux vm code.
 
-page_table_lock
+page_table_lock & mmap_sem
 --------------------------------------
 
 Page stealers pick processes out of the process pool and scan for 
@@ -23,29 +23,23 @@
 
 Any code that modifies the vmlist, or the vm_start/vm_end/
 vm_flags:VM_LOCKED/vm_next of any vma *in the list* must prevent 
-kswapd from looking at the chain. This does not include driver mmap() 
-methods, for example, since the vma is still not in the list.
+kswapd from looking at the chain.
 
 The rules are:
-1. To modify the vmlist (add/delete or change fields in an element), 
-you must hold mmap_sem to guard against clones doing mmap/munmap/faults, 
-(ie all vm system calls and faults), and from ptrace, swapin due to 
-swap deletion etc.
-2. To modify the vmlist (add/delete or change fields in an element), 
-you must also hold page_table_lock, to guard against page stealers 
-scanning the list.
-3. To scan the vmlist (find_vma()), you must either 
-        a. grab mmap_sem, which should be done by all cases except 
-	   page stealer.
-or
-        b. grab page_table_lock, only done by page stealer.
-4. While holding the page_table_lock, you must be able to guarantee
-that no code path will lead to page stealing. A better guarantee is
-to claim non sleepability, which ensures that you are not sleeping
-for a lock, whose holder might in turn be doing page stealing.
+1. To scan the vmlist (look but don't touch) you must hold the
+   mmap_sem with read bias, i.e. down_read(&mm->mmap_sem)
+2. To modify the vmlist you need to hold the mmap_sem with
+   read&write bias, i.e. down_write(&mm->mmap_sem)  *AND*
+   you need to take the page_table_lock.
+3. The swapper takes _just_ the page_table_lock, this is done
+   because the mmap_sem can be an extremely long lived lock
+   and the swapper just cannot sleep on that.
+4. The exception to this rule is expand_stack, which just
+   takes the read lock and the page_table_lock, this is ok
+   because it doesn't really modify fields anybody relies on.
 5. You must be able to guarantee that while holding page_table_lock
-or page_table_lock of mm A, you will not try to get either lock
-for mm B.
+   or page_table_lock of mm A, you will not try to get either lock
+   for mm B.
 
 The caveats are:
 1. find_vma() makes use of, and updates, the mmap_cache pointer hint.
diff -u --recursive --new-file v2.4.2/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.2/linux/MAINTAINERS	Wed Feb 21 18:20:09 2001
+++ linux/MAINTAINERS	Sat Mar  3 10:52:14 2001
@@ -745,7 +745,7 @@
 LINUX FOR POWERPC
 P:	Cort Dougan
 M:	cort@fsmlabs.com
-W:	http://www.ppc.kernel.org/
+W:	http://www.fsmlabs.com/linuxppcbk.html
 S:	Maintained
 
 LINUX FOR POWER MACINTOSH
diff -u --recursive --new-file v2.4.2/linux/Makefile linux/Makefile
--- v2.4.2/linux/Makefile	Wed Feb 21 18:20:09 2001
+++ linux/Makefile	Tue Mar 20 23:12:05 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 2
-EXTRAVERSION =
+SUBLEVEL = 3
+EXTRAVERSION =-pre7
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -10,7 +10,7 @@
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
 	  else if [ -x /bin/bash ]; then echo /bin/bash; \
 	  else echo sh; fi ; fi)
-TOPDIR	:= $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)
+TOPDIR	:= $(shell /bin/pwd)
 
 HPATH   	= $(TOPDIR)/include
 FINDHPATH	= $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net
@@ -144,6 +144,7 @@
 DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
 DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o
 DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
+DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o
 DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
 
 ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
@@ -440,8 +441,8 @@
 	find . -type f -print | sort | xargs sum > .SUMS
 
 dep-files: scripts/mkdep archdep include/linux/version.h
-	scripts/mkdep init/*.c > .depend
-	scripts/mkdep `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
+	scripts/mkdep -- init/*.c > .depend
+	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
diff -u --recursive --new-file v2.4.2/linux/Rules.make linux/Rules.make
--- v2.4.2/linux/Rules.make	Fri Dec 29 14:07:19 2000
+++ linux/Rules.make	Tue Mar  6 19:31:01 2001
@@ -123,7 +123,7 @@
 # This make dependencies quickly
 #
 fastdep: dummy
-	$(TOPDIR)/scripts/mkdep $(wildcard *.[chS] local.h.master) > .depend
+	$(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- $(wildcard *.[chS]) > .depend
 ifdef ALL_SUB_DIRS
 	$(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
 endif
@@ -150,7 +150,7 @@
 #
 ALL_MOBJS = $(filter-out $(obj-y), $(obj-m))
 ifneq "$(strip $(ALL_MOBJS))" ""
-PDWN=$(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
+MOD_DESTDIR := $(shell $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
 endif
 
 unexport MOD_DIRS
@@ -172,8 +172,8 @@
 .PHONY: _modinst__
 _modinst__: dummy
 ifneq "$(strip $(ALL_MOBJS))" ""
-	mkdir -p $(MODLIB)/kernel/$(PDWN)
-	cp $(ALL_MOBJS) $(MODLIB)/kernel/$(PDWN)
+	mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR)
+	cp $(ALL_MOBJS) $(MODLIB)/kernel/$(MOD_DESTDIR)$(MOD_TARGET)
 endif
 
 .PHONY: modules_install
@@ -222,9 +222,9 @@
 
 $(MODINCL)/%.ver: %.c
 	@if [ ! -r $(MODINCL)/$*.stamp -o $(MODINCL)/$*.stamp -ot $< ]; then \
-		echo '$(CC) $(CFLAGS) -E -D__GENKSYMS__ $<'; \
+		echo '$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $<'; \
 		echo '| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp'; \
-		$(CC) $(CFLAGS) -E -D__GENKSYMS__ $< \
+		$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< \
 		| $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp; \
 		if [ -r $@ ] && cmp -s $@ $@.tmp; then echo $@ is unchanged; rm -f $@.tmp; \
 		else echo mv $@.tmp $@; mv -f $@.tmp $@; fi; \
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.4.2/linux/arch/alpha/defconfig	Mon Oct 16 15:38:41 2000
+++ linux/arch/alpha/defconfig	Sun Mar  4 14:30:18 2001
@@ -285,10 +285,8 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
-CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_PROC_STATS=y
-CONFIG_AIC7XXX_RESET_DELAY=5
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY=5000
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.4.2/linux/arch/alpha/kernel/alpha_ksyms.c	Wed Feb 21 18:20:09 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Fri Mar  2 11:15:47 2001
@@ -235,3 +235,4 @@
 EXPORT_SYMBOL_NOVERS(memset);
 
 EXPORT_SYMBOL(get_wchan);
+EXPORT_SYMBOL(flush_tlb_page);
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/console.c linux/arch/alpha/kernel/console.c
--- v2.4.2/linux/arch/alpha/kernel/console.c	Mon Jun 19 17:59:32 2000
+++ linux/arch/alpha/kernel/console.c	Fri Mar  2 11:12:07 2001
@@ -21,8 +21,8 @@
 unsigned long __vga_hose_io_base = 0;	/* base for default hose */
 unsigned long __vga_hose_mem_base = 0;	/* base for default hose */
 
-static struct pci_controler * __init 
-default_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2)
+static struct pci_controller * __init 
+default_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
 {
 	if (h2->index < h1->index)
 		return h2;
@@ -31,7 +31,7 @@
 }
 
 void __init 
-set_vga_hose(struct pci_controler *hose)
+set_vga_hose(struct pci_controller *hose)
 {
 	if (hose) {
 		__vga_hose_io_base = hose->io_space->start;
@@ -42,7 +42,7 @@
 void __init 
 locate_and_init_vga(void *(*sel_func)(void *, void *))
 {
-	struct pci_controler *hose = NULL;
+	struct pci_controller *hose = NULL;
 	struct pci_dev *dev = NULL;
 
 	if (!sel_func) sel_func = (void *)default_vga_hose_select;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c
--- v2.4.2/linux/arch/alpha/kernel/core_apecs.c	Tue Mar 21 10:46:21 2000
+++ linux/arch/alpha/kernel/core_apecs.c	Fri Mar  2 11:12:07 2001
@@ -357,7 +357,7 @@
 };
 
 void
-apecs_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+apecs_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	wmb();
 	*(vip)APECS_IOC_TBIA = 0;
@@ -367,13 +367,13 @@
 void __init
 apecs_init_arch(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	/*
 	 * Create our single hose.
 	 */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- v2.4.2/linux/arch/alpha/kernel/core_cia.c	Mon Dec 11 13:46:26 2000
+++ linux/arch/alpha/kernel/core_cia.c	Fri Mar  2 11:12:07 2001
@@ -299,7 +299,7 @@
  */
 
 void
-cia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+cia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	wmb();
 	*(vip)CIA_IOC_PCI_TBIA = 3;	/* Flush all locked and unlocked.  */
@@ -314,7 +314,7 @@
  */
 
 static void
-cia_pci_tbi_try1(struct pci_controler *hose,
+cia_pci_tbi_try1(struct pci_controller *hose,
 		 dma_addr_t start, dma_addr_t end)
 {
 	wmb();
@@ -359,7 +359,7 @@
 }
 
 static void
-cia_pci_tbi_try2(struct pci_controler *hose,
+cia_pci_tbi_try2(struct pci_controller *hose,
 		 dma_addr_t start, dma_addr_t end)
 {
 	unsigned long flags;
@@ -595,7 +595,7 @@
 static void __init
 do_init_arch(int is_pyxis)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	int temp;
 	int cia_rev;
 
@@ -628,7 +628,7 @@
 	*(vip)CIA_IOC_HAE_IO = 0;
 
 	/* For PYXIS, we always use BWX bus and i/o accesses.  To that end,
-	   make sure they're enabled on the controler.  */
+	   make sure they're enabled on the controller.  */
 	if (is_pyxis) {
 		temp = *(vip)CIA_IOC_CIA_CNFG;
 		temp |= CIA_CNFG_IOA_BWEN;
@@ -643,7 +643,7 @@
 	 * Create our single hose.
 	 */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c
--- v2.4.2/linux/arch/alpha/kernel/core_irongate.c	Mon Aug 28 21:21:57 2000
+++ linux/arch/alpha/kernel/core_irongate.c	Fri Mar  2 11:12:07 2001
@@ -367,7 +367,7 @@
 void __init
 irongate_init_arch(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
 	irongate_pci_clr_err();
@@ -377,7 +377,7 @@
 	 * Create our single hose.
 	 */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c
--- v2.4.2/linux/arch/alpha/kernel/core_lca.c	Tue Mar 21 10:46:21 2000
+++ linux/arch/alpha/kernel/core_lca.c	Fri Mar  2 11:12:07 2001
@@ -279,7 +279,7 @@
 };
 
 void
-lca_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+lca_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	wmb();
 	*(vip)LCA_IOC_TBIA = 0;
@@ -289,13 +289,13 @@
 void __init
 lca_init_arch(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	/*
 	 * Create our single hose.
 	 */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c
--- v2.4.2/linux/arch/alpha/kernel/core_mcpcia.c	Wed Jun 21 22:30:59 2000
+++ linux/arch/alpha/kernel/core_mcpcia.c	Fri Mar  2 11:12:07 2001
@@ -89,7 +89,7 @@
 
 static unsigned int
 conf_read(unsigned long addr, unsigned char type1,
-	  struct pci_controler *hose)
+	  struct pci_controller *hose)
 {
 	unsigned long flags;
 	unsigned long mid = MCPCIA_HOSE2MID(hose->index);
@@ -137,7 +137,7 @@
 
 static void
 conf_write(unsigned long addr, unsigned int value, unsigned char type1,
-	   struct pci_controler *hose)
+	   struct pci_controller *hose)
 {
 	unsigned long flags;
 	unsigned long mid = MCPCIA_HOSE2MID(hose->index);
@@ -171,7 +171,7 @@
 }
 
 static int
-mk_conf_addr(struct pci_dev *dev, int where, struct pci_controler *hose,
+mk_conf_addr(struct pci_dev *dev, int where, struct pci_controller *hose,
 	     unsigned long *pci_addr, unsigned char *type1)
 {
 	u8 bus = dev->bus->number;
@@ -199,7 +199,7 @@
 static int
 mcpcia_read_config_byte(struct pci_dev *dev, int where, u8 *value)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr, w;
 	unsigned char type1;
 
@@ -215,7 +215,7 @@
 static int
 mcpcia_read_config_word(struct pci_dev *dev, int where, u16 *value)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr, w;
 	unsigned char type1;
 
@@ -231,7 +231,7 @@
 static int
 mcpcia_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr;
 	unsigned char type1;
 
@@ -246,7 +246,7 @@
 static int
 mcpcia_write_config(struct pci_dev *dev, int where, u32 value, long mask)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr;
 	unsigned char type1;
 
@@ -288,7 +288,7 @@
 };
 
 void
-mcpcia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+mcpcia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	wmb();
 	*(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0;
@@ -333,11 +333,11 @@
 static void __init
 mcpcia_new_hose(int h)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct resource *io, *mem, *hae_mem;
 	int mid = MCPCIA_HOSE2MID(h);
 
-	hose = alloc_pci_controler();
+	hose = alloc_pci_controller();
 	if (h == 0)
 		pci_isa_hose = hose;
 	io = alloc_resource();
@@ -386,7 +386,7 @@
 }
 
 static void __init
-mcpcia_startup_hose(struct pci_controler *hose)
+mcpcia_startup_hose(struct pci_controller *hose)
 {
 	int mid = MCPCIA_HOSE2MID(hose->index);
 	unsigned int tmp;
@@ -464,7 +464,7 @@
 void __init
 mcpcia_init_hoses(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	int hose_count;
 	int h;
 
@@ -561,7 +561,7 @@
 mcpcia_print_system_area(unsigned long la_ptr)
 {
 	struct el_common *frame;
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	struct IOD_subpacket {
 	  unsigned long base;
@@ -638,7 +638,7 @@
 	    {
 		/* FIXME: how do we figure out which hose the
 		   error was on?  */	
-		struct pci_controler *hose;
+		struct pci_controller *hose;
 		for (hose = hose_head; hose; hose = hose->next)
 			mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index));
 		break;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c
--- v2.4.2/linux/arch/alpha/kernel/core_polaris.c	Tue Mar 21 10:46:21 2000
+++ linux/arch/alpha/kernel/core_polaris.c	Fri Mar  2 11:12:07 2001
@@ -178,7 +178,7 @@
 void __init
 polaris_init_arch(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	/* May need to initialize error reporting (see PCICTL0/1), but
 	 * for now assume that the firmware has done the right thing
@@ -192,7 +192,7 @@
 	 * Create our single hose.
 	 */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c
--- v2.4.2/linux/arch/alpha/kernel/core_t2.c	Tue Mar 21 10:46:21 2000
+++ linux/arch/alpha/kernel/core_t2.c	Fri Mar  2 11:12:07 2001
@@ -324,7 +324,7 @@
 void __init
 t2_init_arch(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	unsigned int i;
 
 	for (i = 0; i < NR_CPUS; i++) {
@@ -384,7 +384,7 @@
 	 * Create our single hose.
 	 */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_titan.c linux/arch/alpha/kernel/core_titan.c
--- v2.4.2/linux/arch/alpha/kernel/core_titan.c	Tue Jul 18 22:58:28 2000
+++ linux/arch/alpha/kernel/core_titan.c	Fri Mar  2 11:12:07 2001
@@ -83,7 +83,7 @@
 mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
 	     unsigned char *type1)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr;
 	u8 bus = dev->bus->number;
 	u8 device_fn = dev->devfn;
@@ -200,7 +200,7 @@
 
 
 void
-titan_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+titan_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	titan_pachip *pachip = 
 	  (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0;
@@ -243,7 +243,7 @@
 
 }
 static void __init
-titan_init_agp(titan_pachip_port *port, struct pci_controler *hose)
+titan_init_agp(titan_pachip_port *port, struct pci_controller *hose)
 {
 	union TPAchipPCTL pctl;
 
@@ -276,9 +276,9 @@
 static void __init
 titan_init_one_pachip_port(titan_pachip_port *port, int index)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
-	hose = alloc_pci_controler();
+	hose = alloc_pci_controller();
 	if (index == 0)
 		pci_isa_hose = hose;
 	hose->io_space = alloc_resource();
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.4.2/linux/arch/alpha/kernel/core_tsunami.c	Mon Jun 19 17:59:32 2000
+++ linux/arch/alpha/kernel/core_tsunami.c	Fri Mar  2 11:12:07 2001
@@ -90,7 +90,7 @@
 mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
 	     unsigned char *type1)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr;
 	u8 bus = dev->bus->number;
 	u8 device_fn = dev->devfn;
@@ -206,7 +206,7 @@
 };
 
 void
-tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+tsunami_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0;
 	volatile unsigned long *csr;
@@ -280,12 +280,12 @@
 static void __init
 tsunami_init_one_pchip(tsunami_pchip *pchip, int index)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	if (tsunami_probe_read(&pchip->pctl.csr) == 0)
 		return;
 
-	hose = alloc_pci_controler();
+	hose = alloc_pci_controller();
 	if (index == 0)
 		pci_isa_hose = hose;
 	hose->io_space = alloc_resource();
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/core_wildfire.c linux/arch/alpha/kernel/core_wildfire.c
--- v2.4.2/linux/arch/alpha/kernel/core_wildfire.c	Mon Jun 19 17:59:32 2000
+++ linux/arch/alpha/kernel/core_wildfire.c	Fri Mar  2 11:12:07 2001
@@ -64,10 +64,10 @@
 void __init
 wildfire_init_hose(int qbbno, int hoseno)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	wildfire_pci *pci;
 
-	hose = alloc_pci_controler();
+	hose = alloc_pci_controller();
 	hose->io_space = alloc_resource();
 	hose->mem_space = alloc_resource();
 
@@ -346,7 +346,7 @@
 }
 
 void
-wildfire_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+wildfire_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
 {
 	int qbbno = hose->index >> 3;
 	int hoseno = hose->index & 7;
@@ -360,7 +360,7 @@
 mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
 	     unsigned char *type1)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long addr;
 	u8 bus = dev->bus->number;
 	u8 device_fn = dev->devfn;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.4.2/linux/arch/alpha/kernel/osf_sys.c	Wed Feb 21 18:20:10 2001
+++ linux/arch/alpha/kernel/osf_sys.c	Mon Mar 19 12:35:09 2001
@@ -242,9 +242,9 @@
 			goto out;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	ret = do_mmap(file, addr, len, prot, flags, off);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if (file)
 		fput(file);
 out:
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci-noop.c linux/arch/alpha/kernel/pci-noop.c
--- v2.4.2/linux/arch/alpha/kernel/pci-noop.c	Wed Feb 21 18:20:10 2001
+++ linux/arch/alpha/kernel/pci-noop.c	Fri Mar  2 11:12:07 2001
@@ -14,17 +14,17 @@
 
 
 /*
- * The PCI controler list.
+ * The PCI controller list.
  */
 
-struct pci_controler *hose_head, **hose_tail = &hose_head;
-struct pci_controler *pci_isa_hose;
+struct pci_controller *hose_head, **hose_tail = &hose_head;
+struct pci_controller *pci_isa_hose;
 
 
-struct pci_controler * __init
-alloc_pci_controler(void)
+struct pci_controller * __init
+alloc_pci_controller(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	hose = alloc_bootmem(sizeof(*hose));
 
@@ -47,7 +47,7 @@
 asmlinkage long
 sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct pci_dev *dev;
 
 	/* from hose or from bus.devfn */
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- v2.4.2/linux/arch/alpha/kernel/pci.c	Mon Dec 11 13:46:26 2000
+++ linux/arch/alpha/kernel/pci.c	Fri Mar  2 11:12:07 2001
@@ -43,11 +43,11 @@
 
 
 /*
- * The PCI controler list.
+ * The PCI controller list.
  */
 
-struct pci_controler *hose_head, **hose_tail = &hose_head;
-struct pci_controler *pci_isa_hose;
+struct pci_controller *hose_head, **hose_tail = &hose_head;
+struct pci_controller *pci_isa_hose;
 
 /*
  * Quirks.
@@ -136,7 +136,7 @@
 pcibios_align_resource(void *data, struct resource *res, unsigned long size)
 {
 	struct pci_dev *dev = data;
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	unsigned long alignto;
 	unsigned long start = res->start;
 
@@ -224,7 +224,7 @@
 pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
 {
 	/* Update device resources.  */
-	struct pci_controler *hose = (struct pci_controler *)bus->sysdata;
+	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
 	int i;
 
 	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
@@ -244,7 +244,7 @@
 {
 	/* Propogate hose info into the subordinate devices.  */
 
-	struct pci_controler *hose = bus->sysdata;
+	struct pci_controller *hose = bus->sysdata;
 	struct list_head *ln;
 	struct pci_dev *dev = bus->self;
 
@@ -284,7 +284,7 @@
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			struct resource *res, int resource)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int where;
 	u32 reg;
 
@@ -328,7 +328,7 @@
 u8 __init
 common_swizzle(struct pci_dev *dev, u8 *pinp)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 
 	if (dev->bus->number != hose->first_busno) {
 		u8 pin = *pinp;
@@ -349,7 +349,7 @@
 pcibios_fixup_pbus_ranges(struct pci_bus * bus,
 			  struct pbus_set_ranges_data * ranges)
 {
-	struct pci_controler *hose = (struct pci_controler *)bus->sysdata;
+	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
 
 	ranges->io_start -= hose->io_space->start;
 	ranges->io_end -= hose->io_space->start;
@@ -383,11 +383,11 @@
 void __init
 common_init_pci(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct pci_bus *bus;
 	int next_busno;
 
-	/* Scan all of the recorded PCI controlers.  */
+	/* Scan all of the recorded PCI controllers.  */
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
 		hose->first_busno = next_busno;
 		hose->last_busno = 0xff;
@@ -402,10 +402,10 @@
 }
 
 
-struct pci_controler * __init
-alloc_pci_controler(void)
+struct pci_controller * __init
+alloc_pci_controller(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	hose = alloc_bootmem(sizeof(*hose));
 
@@ -432,7 +432,7 @@
 asmlinkage long
 sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct pci_dev *dev;
 
 	/* from hose or from bus.devfn */
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h
--- v2.4.2/linux/arch/alpha/kernel/pci_impl.h	Thu Mar 16 14:08:32 2000
+++ linux/arch/alpha/kernel/pci_impl.h	Fri Mar  2 11:12:07 2001
@@ -6,7 +6,7 @@
  */
 
 struct pci_dev;
-struct pci_controler;
+struct pci_controller;
 struct pci_iommu_arena;
 
 /*
@@ -133,7 +133,7 @@
 struct pci_iommu_arena
 {
 	spinlock_t lock;
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	unsigned long *ptes;
 	dma_addr_t dma_base;
 	unsigned int size;
@@ -143,15 +143,15 @@
 
 
 /* The hose list.  */
-extern struct pci_controler *hose_head, **hose_tail;
-extern struct pci_controler *pci_isa_hose;
+extern struct pci_controller *hose_head, **hose_tail;
+extern struct pci_controller *pci_isa_hose;
 
 extern void common_init_pci(void);
 extern u8 common_swizzle(struct pci_dev *, u8 *);
-extern struct pci_controler *alloc_pci_controler(void);
+extern struct pci_controller *alloc_pci_controller(void);
 extern struct resource *alloc_resource(void);
 
-extern struct pci_iommu_arena *iommu_arena_new(struct pci_controler *,
+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);
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c
--- v2.4.2/linux/arch/alpha/kernel/pci_iommu.c	Mon Dec 11 13:46:26 2000
+++ linux/arch/alpha/kernel/pci_iommu.c	Fri Mar  2 11:12:07 2001
@@ -43,7 +43,7 @@
 }
 
 struct pci_iommu_arena *
-iommu_arena_new(struct pci_controler *hose, dma_addr_t base,
+iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
 		unsigned long window_size, unsigned long align)
 {
 	unsigned long mem_size;
@@ -147,7 +147,7 @@
 dma_addr_t
 pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction)
 {
-	struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
+	struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose;
 	dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff;
 	struct pci_iommu_arena *arena;
 	long npages, dma_ofs, i;
@@ -215,7 +215,7 @@
 pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size,
 		 int direction)
 {
-	struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose;
+	struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose;
 	struct pci_iommu_arena *arena;
 	long dma_ofs, npages;
 
@@ -454,7 +454,7 @@
 	   int direction)
 {
 	struct scatterlist *start, *end, *out;
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct pci_iommu_arena *arena;
 	dma_addr_t max_dma;
 
@@ -528,7 +528,7 @@
 pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
 	     int direction)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct pci_iommu_arena *arena;
 	struct scatterlist *end;
 	dma_addr_t max_dma;
@@ -596,7 +596,7 @@
 int
 pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	struct pci_iommu_arena *arena;
 
 #if !DEBUG_NODIRECT
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.4.2/linux/arch/alpha/kernel/proto.h	Mon Jun 19 17:59:32 2000
+++ linux/arch/alpha/kernel/proto.h	Fri Mar  2 11:12:07 2001
@@ -10,14 +10,14 @@
 struct pt_regs;
 struct task_struct;
 struct pci_dev;
-struct pci_controler;
+struct pci_controller;
 
 /* core_apecs.c */
 extern struct pci_ops apecs_pci_ops;
 extern void apecs_init_arch(void);
 extern void apecs_pci_clr_err(void);
 extern void apecs_machine_check(u64, u64, struct pt_regs *);
-extern void apecs_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_cia.c */
 extern struct pci_ops cia_pci_ops;
@@ -25,7 +25,7 @@
 extern void cia_init_arch(void);
 extern void pyxis_init_arch(void);
 extern void cia_machine_check(u64, u64, struct pt_regs *);
-extern void cia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_irongate.c */
 extern struct pci_ops irongate_pci_ops;
@@ -38,14 +38,14 @@
 extern struct pci_ops lca_pci_ops;
 extern void lca_init_arch(void);
 extern void lca_machine_check(u64, u64, struct pt_regs *);
-extern void lca_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_mcpcia.c */
 extern struct pci_ops mcpcia_pci_ops;
 extern void mcpcia_init_arch(void);
 extern void mcpcia_init_hoses(void);
 extern void mcpcia_machine_check(u64, u64, struct pt_regs *);
-extern void mcpcia_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_polaris.c */
 extern struct pci_ops polaris_pci_ops;
@@ -66,21 +66,21 @@
 extern void titan_init_arch(void);
 extern void titan_kill_arch(int);
 extern void titan_machine_check(u64, u64, struct pt_regs *);
-extern void titan_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_tsunami.c */
 extern struct pci_ops tsunami_pci_ops;
 extern void tsunami_init_arch(void);
 extern void tsunami_kill_arch(int);
 extern void tsunami_machine_check(u64, u64, struct pt_regs *);
-extern void tsunami_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* core_wildfire.c */
 extern struct pci_ops wildfire_pci_ops;
 extern void wildfire_init_arch(void);
 extern void wildfire_kill_arch(int);
 extern void wildfire_machine_check(u64, u64, struct pt_regs *);
-extern void wildfire_pci_tbi(struct pci_controler *, dma_addr_t, dma_addr_t);
+extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
 
 /* setup.c */
 extern unsigned long srm_hae;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.4.2/linux/arch/alpha/kernel/setup.c	Wed Feb 21 18:20:10 2001
+++ linux/arch/alpha/kernel/setup.c	Fri Mar  2 11:12:07 2001
@@ -201,7 +201,7 @@
 	long i;
 
 	if (hose_head) {
-		struct pci_controler *hose;
+		struct pci_controller *hose;
 		for (hose = hose_head; hose; hose = hose->next)
 			if (hose->index == 0) {
 				io = hose->io_space;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.4.2/linux/arch/alpha/kernel/sys_dp264.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_dp264.c	Fri Mar  2 11:12:07 2001
@@ -404,13 +404,13 @@
 	};
 	const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5;
 
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int irq = COMMON_TABLE_LOOKUP;
 
 	if (irq > 0) {
 		irq += 16 * hose->index;
 	} else {
-		/* ??? The Contaq IDE controler on the ISA bridge uses
+		/* ??? The Contaq IDE controller on the ISA bridge uses
 		   "legacy" interrupts 14 and 15.  I don't know if anything
 		   can wind up at the same slot+pin on hose1, so we'll
 		   just have to trust whatever value the console might
@@ -455,7 +455,7 @@
 static u8 __init
 monet_swizzle(struct pci_dev *dev, u8 *pinp)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int slot, pin = *pinp;
 
 	if (hose->first_busno == dev->bus->number) {
@@ -521,7 +521,7 @@
 	};
 	const long min_idsel = 1, max_idsel = 7, irqs_per_slot = 5;
 
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int irq = COMMON_TABLE_LOOKUP;
 
 	if (irq > 0)
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_eiger.c linux/arch/alpha/kernel/sys_eiger.c
--- v2.4.2/linux/arch/alpha/kernel/sys_eiger.c	Thu Mar 16 14:07:09 2000
+++ linux/arch/alpha/kernel/sys_eiger.c	Fri Mar  2 11:12:07 2001
@@ -177,7 +177,7 @@
 static u8 __init
 eiger_swizzle(struct pci_dev *dev, u8 *pinp)
 {
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int slot, pin = *pinp;
 	int bridge_count = 0;
 
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c
--- v2.4.2/linux/arch/alpha/kernel/sys_jensen.c	Tue Mar 21 10:46:21 2000
+++ linux/arch/alpha/kernel/sys_jensen.c	Fri Mar  2 11:12:07 2001
@@ -124,12 +124,12 @@
 static void __init
 jensen_init_arch(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 
 	/* Create a hose so that we can report i/o base addresses to
 	   userland.  */
 
-	pci_isa_hose = hose = alloc_pci_controler();
+	pci_isa_hose = hose = alloc_pci_controller();
 	hose->io_space = &ioport_resource;
 	hose->mem_space = &iomem_resource;
 	hose->index = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.4.2/linux/arch/alpha/kernel/sys_rawhide.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_rawhide.c	Fri Mar  2 11:12:07 2001
@@ -139,7 +139,7 @@
 static void __init
 rawhide_init_irq(void)
 {
-	struct pci_controler *hose;
+	struct pci_controller *hose;
 	long i;
 
 	mcpcia_init_hoses();
@@ -204,7 +204,7 @@
 	};
 	const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5;
 
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int irq = COMMON_TABLE_LOOKUP;
 	if (irq >= 0)
 		irq += 24 * hose->index;
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_titan.c linux/arch/alpha/kernel/sys_titan.c
--- v2.4.2/linux/arch/alpha/kernel/sys_titan.c	Mon Jun 19 17:59:32 2000
+++ linux/arch/alpha/kernel/sys_titan.c	Fri Mar  2 11:12:07 2001
@@ -321,10 +321,10 @@
 }
 
 #ifdef CONFIG_VGA_HOSE
-static struct pci_controler * __init
-privateer_vga_hose_select(struct pci_controler *h1, struct pci_controler *h2)
+static struct pci_controller * __init
+privateer_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2)
 {
-	struct pci_controler *hose = h1;
+	struct pci_controller *hose = h1;
 	int agp1, agp2;
 
 	/* which hose(s) are agp? */
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/kernel/sys_wildfire.c linux/arch/alpha/kernel/sys_wildfire.c
--- v2.4.2/linux/arch/alpha/kernel/sys_wildfire.c	Mon Oct 30 12:24:22 2000
+++ linux/arch/alpha/kernel/sys_wildfire.c	Fri Mar  2 11:12:07 2001
@@ -315,7 +315,7 @@
 	};
 	const long min_idsel = 0, max_idsel = 7, irqs_per_slot = 5;
 
-	struct pci_controler *hose = dev->sysdata;
+	struct pci_controller *hose = dev->sysdata;
 	int irq = COMMON_TABLE_LOOKUP;
 
 	if (irq > 0) {
diff -u --recursive --new-file v2.4.2/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.4.2/linux/arch/alpha/mm/fault.c	Fri Dec 29 14:07:19 2000
+++ linux/arch/alpha/mm/fault.c	Mon Mar 19 12:35:09 2001
@@ -113,7 +113,7 @@
 		goto vmalloc_fault;
 #endif
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -146,7 +146,7 @@
 	 * the fault.
 	 */
 	fault = handle_mm_fault(mm, vma, address, cause > 0);
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	if (fault < 0)
 		goto out_of_memory;
@@ -160,7 +160,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
 		force_sig(SIGSEGV, current);
diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S
--- v2.4.2/linux/arch/arm/kernel/entry-armo.S	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/kernel/entry-armo.S	Tue Mar  6 19:44:35 2001
@@ -29,13 +29,12 @@
 #include <linux/config.h>
 
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/errno.h>
 #include <asm/hardware.h>
 
-#include "../lib/constants.h"
-
 		.macro	zero_fp
-#ifdef CONFIG_FRAME_POINTER
+#ifndef CONFIG_NO_FRAME_POINTER
 		mov	fp, #0
 #endif
 		.endm
diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.4.2/linux/arch/arm/kernel/entry-armv.S	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/kernel/entry-armv.S	Tue Mar  6 19:44:35 2001
@@ -17,19 +17,19 @@
 #include <linux/linkage.h>
 
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/errno.h>
 #include <asm/hardware.h>
 #include <asm/arch/irqs.h>
 #include <asm/proc-fns.h>
 
-#include "../lib/constants.h"
 
 #ifndef MODE_SVC
 #define MODE_SVC 0x13
 #endif
 
 		.macro	zero_fp
-#ifdef CONFIG_FRAME_POINTER
+#ifndef CONFIG_NO_FRAME_POINTER
 		mov	fp, #0
 #endif
 		.endm
@@ -611,9 +611,9 @@
 #else
 wfs_mask_data:	.word	0x0e200110			@ WFS/RFS
 		.word	0x0fef0fff
-		.word	0x0d0d0100			@ LDF [sp]/STF [sp]
-		.word	0x0d0b0100			@ LDF [fp]/STF [fp]
-		.word	0x0f0f0f00
+		.word	0x0d000100			@ LDF [sp]/STF [sp]
+		.word	0x0d000100			@ LDF [fp]/STF [fp]
+		.word	0x0f000f00
 
 /* We get here if an undefined instruction happens and the floating
  * point emulator is not present.  If the offending instruction was
diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.4.2/linux/arch/arm/kernel/entry-common.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/kernel/entry-common.S	Tue Mar  6 19:44:35 2001
@@ -215,7 +215,7 @@
 sys_mmap2:
 #if PAGE_SHIFT > 12
 		tst	r5, #PGOFF_MASK
-		moveq	r5, r5, lsr #PGOFF_SHIFT
+		moveq	r5, r5, lsr #PAGE_SHIFT - 12
 		streq	r5, [sp, #4]
 		beq	do_mmap2
 		mov	r0, #-EINVAL
diff -u --recursive --new-file v2.4.2/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.4.2/linux/arch/arm/kernel/sys_arm.c	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/kernel/sys_arm.c	Mon Mar 19 12:35:10 2001
@@ -65,9 +65,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.4.2/linux/arch/arm/lib/Makefile	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/lib/Makefile	Tue Mar  6 19:44:35 2001
@@ -54,9 +54,3 @@
 endif
 
 include $(TOPDIR)/Rules.make
-
-constants.h: getconsdata.o extractconstants.pl
-	$(PERL) extractconstants.pl $(OBJDUMP) > $@
-
-getconsdata.o: getconsdata.c
-	$(CC) $(CFLAGS) -c getconsdata.c
diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/copy_page.S linux/arch/arm/lib/copy_page.S
--- v2.4.2/linux/arch/arm/lib/copy_page.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/copy_page.S	Tue Mar  6 19:44:35 2001
@@ -11,7 +11,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include "constants.h"
+#include <asm/constants.h>
 
 		.text
 		.align	5
diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S
--- v2.4.2/linux/arch/arm/lib/csumpartialcopyuser.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/csumpartialcopyuser.S	Tue Mar  6 19:44:35 2001
@@ -11,7 +11,7 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/errno.h>
-#include "constants.h"
+#include <asm/constants.h>
 
 		.text
 
diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/extractconstants.pl linux/arch/arm/lib/extractconstants.pl
--- v2.4.2/linux/arch/arm/lib/extractconstants.pl	Sat Jul 18 11:55:23 1998
+++ linux/arch/arm/lib/extractconstants.pl	Wed Dec 31 16:00:00 1969
@@ -1,46 +0,0 @@
-#!/usr/bin/perl
-
-$OBJDUMP=$ARGV[0];
-
-sub swapdata {
-	local ($num) = @_;
-
-	return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2);
-}
-
-open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') ||
-	die ('Cant objdump!');
-while (<DATA>) {
-	($addr, $data0, $data1, $data2, $data3) = split (' ');
-	$dat[hex($addr)] = hex(&swapdata($data0));
-	$dat[hex($addr)+4] = hex(&swapdata($data1));
-	$dat[hex($addr)+8] = hex(&swapdata($data2));
-	$dat[hex($addr)+12] = hex(&swapdata($data3));
-}
-close (DATA);
-
-open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!');
-while (<DATA>) {
-	/elf32/ && ( $elf = 1 );
-	/a.out/ && ( $aout = 1 );
-	next if ($aout && ! / 07 /);
-	next if ($elf && ! (/^0*0...... g/ && /.data/));
-	next if (!$aout && !$elf);
-
-	if ($aout) {
-		($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ');
-		$nam[hex($addr)] = substr($name, 1);
-	}
-	if ($elf) {
-		chomp;
-		$addr = substr ($_, 0, index($_, " "));
-		$name = substr ($_, rindex($_, " ") + 1);
-		$nam[hex($addr)] = $name;
-	}
-}
-close (DATA);
-
-print "/*\n * *** This file is automatically generated from getconsdata.c.  Do not edit! ***\n */\n";
-for ($i = 0; $i < hex($addr)+4; $i += 4) {
-	print "#define $nam[$i] $dat[$i]\n";
-}
diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c
--- v2.4.2/linux/arch/arm/lib/getconsdata.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/getconsdata.c	Wed Dec 31 16:00:00 1969
@@ -1,95 +0,0 @@
-/*
- *  linux/arch/arm/lib/getconsdata.c
- *
- *  Copyright (C) 1995-2000 Russell King
- *
- * 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/sched.h>
-#include <linux/mm.h>
-
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-/*
- * Make sure that the compiler and target are compatible
- */
-#if (defined(__APCS_32__) && defined(CONFIG_CPU_26))
-#error Your compiler targets APCS-32 but this kernel requires APCS-26.
-#endif
-#if (defined(__APCS_26__) && defined(CONFIG_CPU_32))
-#error Your compiler targets APCS-26 but this kernel requires APCS-32.
-#endif
-
-#undef PAGE_READONLY
-
-#define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n)
-#define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n)
-
-unsigned long TSK_SIGPENDING = OFF_TSK(sigpending);
-unsigned long TSK_ADDR_LIMIT = OFF_TSK(addr_limit);
-unsigned long TSK_NEED_RESCHED = OFF_TSK(need_resched);
-unsigned long TSK_PTRACE = OFF_TSK(ptrace);
-unsigned long TSK_USED_MATH = OFF_TSK(used_math);
-
-unsigned long TSS_SAVE = OFF_TSK(thread.save);
-unsigned long TSS_FPESAVE = OFF_TSK(thread.fpstate.soft.save);
-#ifdef CONFIG_CPU_32
-unsigned long TSS_DOMAIN = OFF_TSK(thread.domain);
-#endif
-
-#ifdef _PAGE_PRESENT
-unsigned long PAGE_PRESENT = _PAGE_PRESENT;
-#endif
-#ifdef _PAGE_RW
-unsigned long PAGE_RW = _PAGE_RW;
-#endif
-#ifdef _PAGE_USER
-unsigned long PAGE_USER = _PAGE_USER;
-#endif
-#ifdef _PAGE_ACCESSED
-unsigned long PAGE_ACCESSED = _PAGE_ACCESSED;
-#endif
-#ifdef _PAGE_DIRTY
-unsigned long PAGE_DIRTY = _PAGE_DIRTY;
-#endif
-#ifdef _PAGE_READONLY
-unsigned long PAGE_READONLY = _PAGE_READONLY;
-#endif
-#ifdef _PAGE_NOT_USER
-unsigned long PAGE_NOT_USER = _PAGE_NOT_USER;
-#endif
-#ifdef _PAGE_OLD
-unsigned long PAGE_OLD = _PAGE_OLD;
-#endif
-#ifdef _PAGE_CLEAN
-unsigned long PAGE_CLEAN = _PAGE_CLEAN;
-#endif
-
-#ifdef PTE_TYPE_SMALL
-unsigned long HPTE_TYPE_SMALL = PTE_TYPE_SMALL;
-unsigned long HPTE_AP_READ    = PTE_AP_READ;
-unsigned long HPTE_AP_WRITE   = PTE_AP_WRITE;
-#endif
-
-#ifdef L_PTE_PRESENT
-unsigned long LPTE_PRESENT    = L_PTE_PRESENT;
-unsigned long LPTE_YOUNG      = L_PTE_YOUNG;
-unsigned long LPTE_BUFFERABLE = L_PTE_BUFFERABLE;
-unsigned long LPTE_CACHEABLE  = L_PTE_CACHEABLE;
-unsigned long LPTE_USER       = L_PTE_USER;
-unsigned long LPTE_WRITE      = L_PTE_WRITE;
-unsigned long LPTE_EXEC       = L_PTE_EXEC;
-unsigned long LPTE_DIRTY      = L_PTE_DIRTY;
-#endif
-
-unsigned long PAGE_SZ = PAGE_SIZE;
-
-unsigned long KSWI_BASE = 0x900000;
-unsigned long KSWI_SYS_BASE = 0x9f0000;
-unsigned long SYS_ERROR0 = 0x9f0000;
-unsigned long PGOFF_SHIFT = PAGE_SHIFT - 12;
-unsigned long PGOFF_MASK = (1 << (PAGE_SHIFT - 12)) - 1;
diff -u --recursive --new-file v2.4.2/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S
--- v2.4.2/linux/arch/arm/lib/memcpy.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/lib/memcpy.S	Tue Mar  6 19:44:35 2001
@@ -11,7 +11,6 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include "constants.h"
 
 		.text
 
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/Makefile linux/arch/arm/mach-integrator/Makefile
--- v2.4.2/linux/arch/arm/mach-integrator/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/Makefile	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,24 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+
+USE_STANDARD_AS_RULE := true
+
+O_TARGET		:= integrator.o
+
+# Object file lists.
+
+obj-y			:= arch.o irq.o mm.o time.o
+obj-m			:=
+obj-n			:=
+obj-			:=
+
+export-objs		:= leds.o
+
+obj-$(CONFIG_LEDS)	+= leds.o
+obj-$(CONFIG_PCI)	+= pci_v3.o pci.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/arch.c linux/arch/arm/mach-integrator/arch.c
--- v2.4.2/linux/arch/arm/mach-integrator/arch.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/arch.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,70 @@
+/*
+ *  linux/arch/arm/mach-integrator/arch.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/amba_kmi.h>
+
+extern void integrator_map_io(void);
+extern void integrator_init_irq(void);
+
+#ifdef CONFIG_KMI_KEYB
+static struct kmi_info integrator_keyboard __initdata = {
+	base:	IO_ADDRESS(KMI0_BASE),
+	irq:	IRQ_KMIINT0,
+	divisor: 24 / 8 - 1,
+	type:	KMI_KEYBOARD,
+};
+
+static struct kmi_info integrator_mouse __initdata = {
+	base:	IO_ADDRESS(KMI1_BASE),
+	irq:	IRQ_KMIINT1,
+	divisor: 24 / 8 - 1,
+	type:	KMI_MOUSE,
+};
+#endif
+
+static void __init
+integrator_fixup(struct machine_desc *desc, struct param_struct *params,
+		 char **cmdline, struct meminfo *mi)
+{
+#ifdef CONFIG_KMI_KEYB
+	register_kmi(&integrator_keyboard);
+	register_kmi(&integrator_mouse);
+#endif
+}
+
+MACHINE_START(INTEGRATOR, "ARM-Integrator")
+	MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
+	BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
+	BOOT_PARAMS(0x00000100)
+	FIXUP(integrator_fixup)
+	MAPIO(integrator_map_io)
+	INITIRQ(integrator_init_irq)
+MACHINE_END
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/dma.c linux/arch/arm/mach-integrator/dma.c
--- v2.4.2/linux/arch/arm/mach-integrator/dma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/dma.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,36 @@
+/*
+ *  linux/arch/arm/mach-integrator/dma.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ */
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/dma.h>
+
+void __init arch_dma_init(dma_t *dma)
+{
+}
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/irq.c linux/arch/arm/mach-integrator/irq.c
--- v2.4.2/linux/arch/arm/mach-integrator/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/irq.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,71 @@
+/*
+ *  linux/arch/arm/mach-integrator/irq.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+/* 
+ * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
+ * is the (PA >> 12).
+ *
+ * Setup a VA for the Integrator interrupt controller (for header #0,
+ * just for now).
+ */
+#define VA_IC_BASE              IO_ADDRESS(INTEGRATOR_IC_BASE) 
+#define VA_CMIC_BASE            IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
+
+#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) 
+
+static void sc_mask_irq(unsigned int irq)
+{
+        __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+}
+
+static void sc_unmask_irq(unsigned int irq)
+{
+        __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
+}
+ 
+void __init integrator_init_irq(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < NR_IRQS; i++) {
+	        if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
+		        irq_desc[i].valid	= 1;
+			irq_desc[i].probe_ok	= 1;
+			irq_desc[i].mask_ack	= sc_mask_irq;
+			irq_desc[i].mask	= sc_mask_irq;
+			irq_desc[i].unmask	= sc_unmask_irq;
+		}
+	}
+
+	/* Disable all interrupts initially. */
+	/* Do the core module ones */
+	__raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
+
+	/* do the header card stuff next */
+	__raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
+	__raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
+}
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/leds.c linux/arch/arm/mach-integrator/leds.c
--- v2.4.2/linux/arch/arm/mach-integrator/leds.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/leds.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,94 @@
+/*
+ *  linux/arch/arm/mach-integrator/leds.c
+ *
+ *  Integrator LED control routines
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+static int saved_leds;
+
+static void integrator_leds_event(led_event_t ledevt)
+{
+	unsigned long flags;
+	const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
+	const unsigned int hdr_ctrl = IO_ADDRESS(INTEGRATOR_HDR_BASE) +
+					INTEGRATOR_HDR_CTRL_OFFSET;
+	unsigned int ctrl;
+	unsigned int update_alpha_leds;
+	
+	// yup, change the LEDs
+	local_irq_save(flags);
+	update_alpha_leds = 0;
+
+	switch(ledevt) {
+	case led_idle_start:
+		ctrl = __raw_readl(hdr_ctrl);
+		ctrl &= ~INTEGRATOR_HDR_CTRL_LED;
+		__raw_writel(ctrl, hdr_ctrl);
+		break;
+
+	case led_idle_end:
+		ctrl = __raw_readl(hdr_ctrl);
+		ctrl |= INTEGRATOR_HDR_CTRL_LED;
+		__raw_writel(ctrl, hdr_ctrl);
+		break;
+
+	case led_timer:
+		saved_leds ^= GREEN_LED;
+		update_alpha_leds = 1;
+		break;
+
+	case led_red_on:
+		saved_leds |= RED_LED;
+		update_alpha_leds = 1;
+		break;
+
+	case led_red_off:
+		saved_leds &= ~RED_LED;
+		update_alpha_leds = 1;
+		break;
+
+	default:
+		break;
+	}
+
+	if (update_alpha_leds) {
+		while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
+		__raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
+	}
+	local_irq_restore(flags);
+}
+
+static int __init leds_init(void)
+{
+	if (machine_is_integrator())
+		leds_event = integrator_leds_event;
+
+	return 0;
+}
+
+__initcall(leds_init);
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/mm.c linux/arch/arm/mach-integrator/mm.c
--- v2.4.2/linux/arch/arm/mach-integrator/mm.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/mm.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,78 @@
+/*
+ *  linux/arch/arm/mach-integrator/mm.c
+ *
+ *  Extra MM routines for the ARM Integrator board
+ *
+ *  Copyright (C) 1999,2000 Arm Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+ 
+#include <asm/mach/map.h>
+
+/*
+ * Logical      Physical
+ * e8000000	40000000	PCI memory
+ * ec000000	62000000	PCI config space
+ * ed000000	61000000	PCI V3 regs
+ * ee000000	60000000	PCI IO
+ * ef000000			Cache flush
+ * f1000000	10000000	Core module registers
+ * f1100000	11000000	System controller registers
+ * f1200000	12000000	EBI registers
+ * f1300000	13000000	Counter/Timer
+ * f1400000	14000000	Interrupt controller
+ * f1500000	15000000	RTC
+ * f1600000	16000000	UART 0
+ * f1700000	17000000	UART 1
+ * f1800000	18000000	Keyboard
+ * f1900000	19000000	Mouse
+ * f1a00000	1a000000	Debug LEDs
+ * f1b00000	1b000000	GPIO
+ */
+ 
+static struct map_desc integrator_io_desc[] __initdata = {
+ { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_RTC_BASE),   INTEGRATOR_RTC_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_KBD_BASE),   INTEGRATOR_KBD_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_MOUSE_BASE), INTEGRATOR_MOUSE_BASE, SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
+ { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K     , DOMAIN_IO, 0, 1},
+ { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M    , DOMAIN_IO, 0, 1},
+ { PCI_CONFIG_VADDR,                  PHYS_PCI_CONFIG_BASE,  SZ_16M    , DOMAIN_IO, 0, 1},
+ { PCI_V3_VADDR,                      PHYS_PCI_V3_BASE,      SZ_512K   , DOMAIN_IO, 0, 1},
+ { PCI_IO_VADDR,                      PHYS_PCI_IO_BASE,      SZ_64K    , DOMAIN_IO, 0, 1},
+ LAST_DESC
+};
+
+void __init integrator_map_io(void)
+{
+	iotable_init(integrator_io_desc);
+}
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/pci.c linux/arch/arm/mach-integrator/pci.c
--- v2.4.2/linux/arch/arm/mach-integrator/pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/pci.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,119 @@
+/*
+ *  linux/arch/arm/mach-integrator/pci-integrator.c
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ *
+ *
+ *  PCI functions for Integrator
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach/pci.h>
+
+/* 
+ * A small note about bridges and interrupts.  The DECchip 21050 (and
+ * later) adheres to the PCI-PCI bridge specification.  This says that
+ * the interrupts on the other side of a bridge are swizzled in the
+ * following manner:
+ *
+ * Dev    Interrupt   Interrupt 
+ *        Pin on      Pin on 
+ *        Device      Connector
+ *
+ *   4    A           A
+ *        B           B
+ *        C           C
+ *        D           D
+ * 
+ *   5    A           B
+ *        B           C
+ *        C           D
+ *        D           A
+ *
+ *   6    A           C
+ *        B           D
+ *        C           A
+ *        D           B
+ *
+ *   7    A           D
+ *        B           A
+ *        C           B
+ *        D           C
+ *
+ * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
+ * Thus, each swizzle is ((pin-1) + (device#-4)) % 4
+ *
+ * The following code swizzles for exactly one bridge.  
+ */
+static inline int bridge_swizzle(int pin, unsigned int slot) 
+{
+	return (pin + slot) & 3;
+}
+
+/*
+ * This routine handles multiple bridges.
+ */
+static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+	int pin = *pinp;
+
+	if (pin == 0)
+		pin = 1;
+
+	pin -= 1;
+	while (dev->bus->self) {
+		pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+		/*
+		 * move up the chain of bridges, swizzling as we go.
+		 */
+		dev = dev->bus->self;
+	}
+	*pinp = pin + 1;
+
+	return PCI_SLOT(dev->devfn);
+}
+
+static int irq_tab[4] __initdata = {
+	IRQ_PCIINT0,	IRQ_PCIINT1,	IRQ_PCIINT2,	IRQ_PCIINT3
+};
+
+/*
+ * map the specified device/slot/pin to an IRQ.  This works out such
+ * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
+ */
+static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int intnr = ((slot - 9) + (pin - 1)) & 3;
+
+	return irq_tab[intnr];
+}
+
+extern void pci_v3_init(struct arm_pci_sysdata *);
+
+struct hw_pci integrator_pci __initdata = {
+	init:		pci_v3_init,
+	swizzle:	integrator_swizzle,
+	map_irq:	integrator_map_irq,
+};
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/pci_v3.c linux/arch/arm/mach-integrator/pci_v3.c
--- v2.4.2/linux/arch/arm/mach-integrator/pci_v3.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/pci_v3.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,460 @@
+/*
+ *  linux/arch/arm/mach-integrator/pci_v3.c
+ *
+ *  PCI functions for V3 host PCI bridge
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach/pci.h>
+
+#include <asm/hardware/pci_v3.h>
+
+/*
+ * The V3 PCI interface chip in Integrator provides several windows from
+ * local bus memory into the PCI memory areas.   Unfortunately, there
+ * are not really enough windows for our usage, therefore we reuse 
+ * one of the windows for access to PCI configuration space.  The
+ * memory map is as follows:
+ * 
+ * Local Bus Memory         Usage
+ * 
+ * 40000000 - 4FFFFFFF      PCI memory.  256M non-prefetchable
+ * 50000000 - 5FFFFFFF      PCI memory.  256M prefetchable
+ * 60000000 - 60FFFFFF      PCI IO.  16M
+ * 68000000 - 68FFFFFF      PCI Configuration. 16M
+ * 
+ * There are three V3 windows, each described by a pair of V3 registers.
+ * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
+ * Base0 and Base1 can be used for any type of PCI memory access.   Base2
+ * can be used either for PCI I/O or for I20 accesses.  By default, uHAL
+ * uses this only for PCI IO space.
+ * 
+ * PCI Memory is mapped so that assigned addresses in PCI Memory match
+ * local bus memory addresses.  In other words, if a PCI device is assigned
+ * address 80200000 then that address is a valid local bus address as well
+ * as a valid PCI Memory address.  PCI IO addresses are mapped to start
+ * at zero.  This means that local bus address 60000000 maps to PCI IO address
+ * 00000000 and so on.   Device driver writers need to be aware of this 
+ * distinction.
+ * 
+ * Normally these spaces are mapped using the following base registers:
+ * 
+ * Usage Local Bus Memory         Base/Map registers used
+ * 
+ * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
+ * Mem   50000000 - 5FFFFFFF      LB_BASE1/LB_MAP1
+ * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
+ * Cfg   68000000 - 68FFFFFF      
+ * 
+ * This means that I20 and PCI configuration space accesses will fail.
+ * When PCI configuration accesses are needed (via the uHAL PCI 
+ * configuration space primitives) we must remap the spaces as follows:
+ * 
+ * Usage Local Bus Memory         Base/Map registers used
+ * 
+ * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
+ * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0
+ * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
+ * Cfg   68000000 - 68FFFFFF      LB_BASE1/LB_MAP1
+ * 
+ * To make this work, the code depends on overlapping windows working.
+ * The V3 chip translates an address by checking its range within 
+ * each of the BASE/MAP pairs in turn (in ascending register number
+ * order).  It will use the first matching pair.   So, for example,
+ * if the same address is mapped by both LB_BASE0/LB_MAP0 and
+ * LB_BASE1/LB_MAP1, the V3 will use the translation from 
+ * LB_BASE0/LB_MAP0.
+ * 
+ * To allow PCI Configuration space access, the code enlarges the
+ * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M.  This occludes
+ * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
+ * be remapped for use by configuration cycles.
+ * 
+ * At the end of the PCI Configuration space accesses, 
+ * LB_BASE1/LB_MAP1 is reset to map PCI Memory.  Finally the window
+ * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
+ * reveal the now restored LB_BASE1/LB_MAP1 window.
+ * 
+ * NOTE: We do not set up I2O mapping.  I suspect that this is only
+ * for an intelligent (target) device.  Using I2O disables most of
+ * the mappings into PCI memory.
+ */
+
+// V3 access routines
+#define _V3Write16(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o))
+#define _V3Read16(o)    (__raw_readw(PCI_V3_VADDR + (unsigned int)(o)))
+
+#define _V3Write32(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o))
+#define _V3Read32(o)    (__raw_readl(PCI_V3_VADDR + (unsigned int)(o)))
+
+/*============================================================================
+ *
+ * routine:	uHALir_PCIMakeConfigAddress()
+ *
+ * parameters:	bus = which bus
+ *              device = which device
+ *              function = which function
+ *		offset = configuration space register we are interested in
+ *
+ * description:	this routine will generate a platform dependant config
+ *		address.
+ *
+ * calls:	none
+ *
+ * returns:	configuration address to play on the PCI bus
+ *
+ * To generate the appropriate PCI configuration cycles in the PCI 
+ * configuration address space, you present the V3 with the following pattern 
+ * (which is very nearly a type 1 (except that the lower two bits are 00 and
+ * not 01).   In order for this mapping to work you need to set up one of
+ * the local to PCI aperatures to 16Mbytes in length translating to
+ * PCI configuration space starting at 0x0000.0000.
+ *
+ * PCI configuration cycles look like this:
+ *
+ * Type 0:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:11	Device select bit.
+ * 	10:8	Function number
+ * 	 7:2	Register number
+ *
+ * Type 1:
+ *
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *	31:24	reserved
+ *	23:16	bus number (8 bits = 128 possible buses)
+ *	15:11	Device number (5 bits)
+ *	10:8	function number
+ *	 7:2	register number
+ *  
+ */
+static spinlock_t v3_lock = SPIN_LOCK_UNLOCKED;
+
+#define PCI_BUS_NONMEM_START	0x00000000
+#define PCI_BUS_NONMEM_SIZE	0x10000000
+
+#define PCI_BUS_PREMEM_START	0x10000000
+#define PCI_BUS_PREMEM_SIZE	0x10000000
+
+#if PCI_BUS_NONMEM_START & 0x000fffff
+#error PCI_BUS_NONMEM_START must be megabyte aligned
+#endif
+#if PCI_BUS_PREMEM_START & 0x000fffff
+#error PCI_BUS_PREMEM_START must be megabyte aligned
+#endif
+
+static unsigned long v3_open_config_window(struct pci_dev *dev, int offset)
+{
+	unsigned int address, mapaddress, busnr;
+
+	busnr = dev->bus->number;
+
+	/*
+	 * Trap out illegal values
+	 */
+	if (offset > 255)
+		BUG();
+	if (busnr > 255)
+		BUG();
+	if (dev->devfn > 255)
+		BUG();
+
+	if (busnr == 0) {
+		int slot = PCI_SLOT(dev->devfn);
+
+		/*
+		 * local bus segment so need a type 0 config cycle
+		 *
+		 * build the PCI configuration "address" with one-hot in
+		 * A31-A11
+		 *
+		 * mapaddress:
+		 *  3:1 = config cycle (101)
+		 *  0   = PCI A1 & A0 are 0 (0)
+		 */
+		address = PCI_FUNC(dev->devfn) << 8;
+		mapaddress = 0x0a;
+
+		if (slot > 12)
+			/*
+			 * high order bits are handled by the MAP register
+			 */
+			mapaddress |= 1 << (slot - 4);
+		else
+			/*
+			 * low order bits handled directly in the address
+			 */
+			address |= 1 << (slot + 11);
+	} else {
+        	/*
+		 * not the local bus segment so need a type 1 config cycle
+		 *
+		 * address:
+		 *  23:16 = bus number
+		 *  15:11 = slot number (7:3 of devfn)
+		 *  10:8  = func number (2:0 of devfn)
+		 *
+		 * mapaddress:
+		 *  3:1 = config cycle (101)
+		 *  0   = PCI A1 & A0 from host bus (1)
+		 */
+		mapaddress = 0x0b;
+		address = (busnr << 16) | (dev->devfn << 8);
+	}
+
+	/*
+	 * Set up base0 to see all 512Mbytes of memory space (not prefetchable), this
+	 * frees up base1 for re-use by configuration memory
+	 */
+	_V3Write32(V3_LB_BASE0, (PHYS_PCI_MEM_BASE & 0xFFF00000) | 0x90 | V3_LB_BASE_M_ENABLE);
+
+	/*
+	 * Set up base1/map1 to point into configuration space.
+	 */
+	_V3Write32(V3_LB_BASE1, (PHYS_PCI_CONFIG_BASE & 0xFFF00000) | 0x40 | V3_LB_BASE_M_ENABLE);
+        _V3Write16(V3_LB_MAP1, mapaddress);
+
+	return PCI_CONFIG_VADDR + address + offset;
+}
+
+static void v3_close_config_window(void)
+{
+	/*
+	 * Reassign base1 for use by prefetchable PCI memory
+	 */
+	_V3Write32(V3_LB_BASE1, ((PHYS_PCI_MEM_BASE + SZ_256M) & 0xFFF00000) | 0x84 | V3_LB_BASE_M_ENABLE);
+	_V3Write16(V3_LB_MAP1, ((PCI_BUS_PREMEM_START & 0xFFF00000) >> 16) | 0x0006);
+
+	/*
+	 * And shrink base0 back to a 256M window (NOTE: MAP0 already correct)
+	 */
+	_V3Write32(V3_LB_BASE0, (PHYS_PCI_MEM_BASE & 0xFFF00000) | 0x80 | V3_LB_BASE_M_ENABLE);
+}
+
+static int v3_read_config_byte(struct pci_dev *dev, int where, u8 *val)
+{
+	unsigned long addr;
+	unsigned long flags;
+	u8 v;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(dev, where);
+
+	v = __raw_readb(addr);
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	*val = v;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int v3_read_config_word(struct pci_dev *dev, int where, u16 *val)
+{
+	unsigned long addr;
+	unsigned long flags;
+	u16 v;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(dev, where);
+
+	v = __raw_readw(addr);
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	*val = v;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int v3_read_config_dword(struct pci_dev *dev, int where, u32 *val)
+{
+	unsigned long addr;
+	unsigned long flags;
+	u32 v;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(dev, where);
+
+	v = __raw_readl(addr);
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	*val = v;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int v3_write_config_byte(struct pci_dev *dev, int where, u8 val)
+{
+	unsigned long addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(dev, where);
+
+	__raw_writeb(val, addr);
+	__raw_readb(addr);
+	
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int v3_write_config_word(struct pci_dev *dev, int where, u16 val)
+{
+	unsigned long addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(dev, where);
+
+	__raw_writew(val, addr);
+	__raw_readw(addr);
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int v3_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+	unsigned long addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&v3_lock, flags);
+	addr = v3_open_config_window(dev, where);
+
+	__raw_writel(val, addr);
+	__raw_readl(addr);
+
+	v3_close_config_window();
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_v3_ops = {
+	read_byte:	v3_read_config_byte,
+	read_word:	v3_read_config_word,
+	read_dword:	v3_read_config_dword,
+	write_byte:	v3_write_config_byte,
+	write_word:	v3_write_config_word,
+	write_dword:	v3_write_config_dword,
+};
+
+static struct resource non_mem = {
+	name:	"PCI non-prefetchable",
+	start:	PCI_BUS_NONMEM_START,
+	end:	PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
+	flags:	IORESOURCE_MEM,
+};
+
+static struct resource pre_mem = {
+	name:	"PCI prefetchable",
+	start:	PCI_BUS_PREMEM_START,
+	end:	PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
+	flags:	IORESOURCE_MEM | IORESOURCE_PREFETCH,
+};
+
+/*
+ * V3_LB_BASE? - local bus address
+ * V3_LB_MAP?  - pci bus address
+ */
+void __init pci_v3_init(struct arm_pci_sysdata *sysdata)
+{
+	struct pci_bus *bus;
+	unsigned int pci_cmd;
+	unsigned long flags;
+
+	spin_lock_irqsave(&v3_lock, flags);
+
+	/*
+	 * Setup window 0 - PCI non-prefetchable memory
+	 *  Local: 0x40000000 Bus: 0x00000000 Size: 256MB
+	 */
+	_V3Write32(V3_LB_BASE0, (PHYS_PCI_MEM_BASE & 0xfff00000) | 0x80 | V3_LB_BASE_M_ENABLE);
+	_V3Write16(V3_LB_MAP0, (PCI_BUS_NONMEM_START >> 16) | 0x0006);
+
+	/*
+	 * Setup window 1 - PCI prefetchable memory
+	 *  Local: 0x50000000 Bus: 0x10000000 Size: 256MB
+	 */
+	_V3Write32(V3_LB_BASE1, ((PHYS_PCI_MEM_BASE + SZ_256M) & 0xFFF00000) | 0x84 | V3_LB_BASE_M_ENABLE);
+	_V3Write16(V3_LB_MAP1, (PCI_BUS_PREMEM_START >> 16) | 0x0006);
+
+	/*
+	 * Setup window 2 - PCI IO
+	 */
+//	_V3Write32(V3_LB_BASE2, (PHYS_PCI_IO_BASE & 0xff000000) | V3_LB_BASE_M_ENABLE);
+//	_V3Write16(V3_LB_MAP2, 0);
+
+	spin_unlock_irqrestore(&v3_lock, flags);
+
+	bus = pci_scan_bus(0, &pci_v3_ops, sysdata);
+
+	if (request_resource(&iomem_resource, &non_mem))
+		printk("PCI: unable to allocate non-prefetchable memory region");
+	if (request_resource(&iomem_resource, &pre_mem))
+		printk("PCI: unable to allocate prefetchable memory region");
+
+	/*
+	 * bus->resource[0] is the IO resource for this bus
+	 * bus->resource[1] is the mem resource for this bus
+	 * bus->resource[2] is the prefetch mem resource for this bus
+	 */
+	bus->resource[1] = &non_mem;
+	bus->resource[2] = &pre_mem;
+
+	pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+		  PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+
+	pci_cmd |= sysdata->bus[0].features;
+
+	_V3Write16(V3_PCI_CMD, pci_cmd);
+
+	printk("PCI: Fast back to back transfers %sabled\n",
+	       (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ?
+		"en" : "dis");
+}
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-integrator/time.c linux/arch/arm/mach-integrator/time.c
--- v2.4.2/linux/arch/arm/mach-integrator/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-integrator/time.c	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,45 @@
+/*
+ *  linux/arch/arm/mach-integrator/time.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+
+#define RTC_DR		(*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 0))
+#define RTC_MR		(*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 4))
+#define RTC_STAT	(*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 8))
+#define RTC_EOI		(*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 8))
+#define RTC_LR		(*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 12))
+#define RTC_CR		(*(unsigned long *)(IO_ADDRESS(INTEGRATOR_RTC_BASE) + 16))
+
+#define RTC_CR_MIE	0x00000001
+
+extern int (*set_rtc)(void);
+
+static int integrator_set_rtc(void)
+{
+	RTC_LR = xtime.tv_sec;
+	return 1;
+}
+
+static int integrator_rtc_init(void)
+{
+	RTC_CR = 0;
+	RTC_EOI = 0;
+
+	xtime.tv_sec = RTC_DR;
+
+	set_rtc = integrator_set_rtc;
+
+	return 0;
+}
+
+__initcall(integrator_rtc_init);
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mach-sa1100/arch.c linux/arch/arm/mach-sa1100/arch.c
--- v2.4.2/linux/arch/arm/mach-sa1100/arch.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mach-sa1100/arch.c	Fri Mar  2 11:12:06 2001
@@ -54,7 +54,7 @@
 	if (machine_is_assabet()) {
 		/* 
 		 * On Assabet, we must probe for the Neponset board *before*
-		 * paging_init() has occured to actually determine the amount
+		 * paging_init() has occurred to actually determine the amount
 		 * of RAM available.
 		 */
 		extern void map_sa1100_gpio_regs(void);
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.4.2/linux/arch/arm/mm/fault-common.c	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/mm/fault-common.c	Mon Mar 19 12:35:10 2001
@@ -223,9 +223,9 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	fault = __do_page_fault(mm, addr, mode, tsk);
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 ret:
 	/*
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c
--- v2.4.2/linux/arch/arm/mm/mm-rpc.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-rpc.c	Tue Mar  6 19:44:35 2001
@@ -9,6 +9,7 @@
  *
  *  Extra MM routines for RiscPC architecture
  */
+#include <linux/types.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c
--- v2.4.2/linux/arch/arm/mm/mm-sa1100.c	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/mm-sa1100.c	Fri Mar  2 11:12:06 2001
@@ -199,7 +199,7 @@
   
 /*
  * On Assabet, we must probe for the Neponset board *before* paging_init() 
- * has occured to actually determine the amount of RAM available.  To do so, 
+ * has occurred to actually determine the amount of RAM available.  To do so, 
  * we map the appropriate IO section in the page table here in order to 
  * access GPIO registers.
  */
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S
--- v2.4.2/linux/arch/arm/mm/proc-arm2,3.S	Mon Sep 18 15:15:25 2000
+++ linux/arch/arm/mm/proc-arm2,3.S	Tue Mar  6 19:44:35 2001
@@ -14,8 +14,8 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/procinfo.h>
-#include "../lib/constants.h"
 
 /*
  * MEMC workhorse code.  It's both a horse which things it's a pig.
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.4.2/linux/arch/arm/mm/proc-arm6,7.S	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/mm/proc-arm6,7.S	Tue Mar  6 19:44:35 2001
@@ -12,8 +12,8 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/procinfo.h>
-#include "../lib/constants.h"
 
 /*
  * Function: arm6_7_cache_clean_invalidate_all (void)
@@ -29,10 +29,10 @@
 ENTRY(cpu_arm7_cache_clean_invalidate_all)
 ENTRY(cpu_arm6_cache_clean_invalidate_range)
 ENTRY(cpu_arm7_cache_clean_invalidate_range)
-ENTRY(cpu_arm6_invalidate_icache_range)
-ENTRY(cpu_arm7_invalidate_icache_range)
-ENTRY(cpu_arm6_invalidate_icache_page)
-ENTRY(cpu_arm7_invalidate_icache_page)
+ENTRY(cpu_arm6_icache_invalidate_range)
+ENTRY(cpu_arm7_icache_invalidate_range)
+ENTRY(cpu_arm6_icache_invalidate_page)
+ENTRY(cpu_arm7_icache_invalidate_page)
 ENTRY(cpu_arm6_dcache_clean_range)
 ENTRY(cpu_arm7_dcache_clean_range)
 ENTRY(cpu_arm6_dcache_invalidate_range)
@@ -410,8 +410,8 @@
 		.word	cpu_arm6_dcache_clean_entry
 
 		/* icache */
-		.word	cpu_arm6_invalidate_icache_range
-		.word	cpu_arm6_invalidate_icache_page
+		.word	cpu_arm6_icache_invalidate_range
+		.word	cpu_arm6_icache_invalidate_page
 
 		/* tlb */
 		.word	cpu_arm6_tlb_invalidate_all
@@ -449,8 +449,8 @@
 		.word	cpu_arm7_dcache_clean_entry
 
 		/* icache */
-		.word	cpu_arm7_invalidate_icache_range
-		.word	cpu_arm7_invalidate_icache_page
+		.word	cpu_arm7_icache_invalidate_range
+		.word	cpu_arm7_icache_invalidate_page
 
 		/* tlb */
 		.word	cpu_arm7_tlb_invalidate_all
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S
--- v2.4.2/linux/arch/arm/mm/proc-arm720.S	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/mm/proc-arm720.S	Tue Mar  6 19:44:35 2001
@@ -32,9 +32,9 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/procinfo.h>
 #include <asm/hardware.h>
-#include "../lib/constants.h"
 
 /*
  * Function: arm720_cache_clean_invalidate_all (void)
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-arm920.S linux/arch/arm/mm/proc-arm920.S
--- v2.4.2/linux/arch/arm/mm/proc-arm920.S	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/mm/proc-arm920.S	Tue Mar  6 19:44:35 2001
@@ -25,9 +25,9 @@
 #include <linux/linkage.h>
 #include <linux/config.h>
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/procinfo.h>
 #include <asm/hardware.h>
-#include "../lib/constants.h"
 
 /*
  * This is the maximum size of an area which will be invalidated
diff -u --recursive --new-file v2.4.2/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.4.2/linux/arch/arm/mm/proc-sa110.S	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/mm/proc-sa110.S	Tue Mar  6 19:44:35 2001
@@ -19,9 +19,9 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/constants.h>
 #include <asm/procinfo.h>
 #include <asm/hardware.h>
-#include "../lib/constants.h"
 
 /* This is the maximum size of an area which will be flushed.  If the area
  * is larger than this, then we flush the whole cache
diff -u --recursive --new-file v2.4.2/linux/arch/arm/nwfpe/entry26.S linux/arch/arm/nwfpe/entry26.S
--- v2.4.2/linux/arch/arm/nwfpe/entry26.S	Wed Oct 20 16:29:08 1999
+++ linux/arch/arm/nwfpe/entry26.S	Tue Mar  6 19:44:35 2001
@@ -20,7 +20,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "../lib/constants.h"
+#include <asm/constants.h>
 
 /* This is the kernel's entry point into the floating point emulator.
 It is called from the kernel with code similar to this:
diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/Makefile linux/arch/arm/tools/Makefile
--- v2.4.2/linux/arch/arm/tools/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/tools/Makefile	Tue Mar  6 19:44:35 2001
@@ -0,0 +1,36 @@
+#
+# linux/arch/arm/tools/Makefile
+#
+# Copyright (C) 2001 Russell King
+#
+
+all:	$(TOPDIR)/include/asm-arm/mach-types.h \
+	$(TOPDIR)/include/asm-arm/constants.h
+
+$(TOPDIR)/include/asm-arm/mach-types.h: mach-types gen-mach-types
+	awk -f gen-mach-types mach-types > $@
+
+# Generate the constants.h header file using the compiler.  We get
+# the compiler to spit out assembly code, and then mundge it into
+# what we want.
+
+$(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c
+	$(CC) $(CFLAGS) -S -o - getconstants.c | \
+	 sed 's/^\(#define .* \)#\(.*\)/\1\2/;/^#define/!d' | \
+	 cat constants-hdr - > $@.tmp
+	cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@; $(RM) $@.tmp
+
+# Build our dependencies, and then generate the constants and
+# mach-types header files.  If we do it now, mkdep will pick
+# the dependencies up later on when it runs through the other
+# directories
+
+dep:
+	$(TOPDIR)/scripts/mkdep getconstants.c | sed s,getconstants.o,$(TOPDIR)/include/asm-arm/constants.h, > .depend
+	$(MAKE) all
+
+.PHONY:	all dep
+
+ifneq ($(wildcard .depend),)
+include .depend
+endif
diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/constants-hdr linux/arch/arm/tools/constants-hdr
--- v2.4.2/linux/arch/arm/tools/constants-hdr	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/tools/constants-hdr	Tue Mar  6 19:44:35 2001
@@ -0,0 +1,5 @@
+/*
+ * This file is automatically generated from arch/arm/tools/getconstants.c.
+ * Do not edit!  Only include this file in assembly (.S) files!
+ */
+
diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c
--- v2.4.2/linux/arch/arm/tools/getconstants.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/tools/getconstants.c	Tue Mar  6 19:44:35 2001
@@ -0,0 +1,72 @@
+/*
+ *  linux/arch/arm/tools/getconsdata.c
+ *
+ *  Copyright (C) 1995-2001 Russell King
+ *
+ * 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/sched.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+/*
+ * Make sure that the compiler and target are compatible
+ */
+#if (defined(__APCS_32__) && defined(CONFIG_CPU_26))
+#error Your compiler targets APCS-32 but this kernel requires APCS-26.
+#endif
+#if (defined(__APCS_26__) && defined(CONFIG_CPU_32))
+#error Your compiler targets APCS-26 but this kernel requires APCS-32.
+#endif
+
+#define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n)
+
+#define DEFN(name,off) asm("\n#define "name" %0" :: "I" (off))
+
+void func(void)
+{
+DEFN("TSK_SIGPENDING",		OFF_TSK(sigpending));
+DEFN("TSK_ADDR_LIMIT",		OFF_TSK(addr_limit));
+DEFN("TSK_NEED_RESCHED",	OFF_TSK(need_resched));
+DEFN("TSK_PTRACE",		OFF_TSK(ptrace));
+DEFN("TSK_USED_MATH",		OFF_TSK(used_math));
+
+DEFN("TSS_SAVE",		OFF_TSK(thread.save));
+DEFN("TSS_FPESAVE",		OFF_TSK(thread.fpstate.soft.save));
+
+#ifdef CONFIG_CPU_32
+DEFN("TSS_DOMAIN",		OFF_TSK(thread.domain));
+
+DEFN("HPTE_TYPE_SMALL",		PTE_TYPE_SMALL);
+DEFN("HPTE_AP_READ",		PTE_AP_READ);
+DEFN("HPTE_AP_WRITE",		PTE_AP_WRITE);
+
+DEFN("LPTE_PRESENT",		L_PTE_PRESENT);
+DEFN("LPTE_YOUNG",		L_PTE_YOUNG);
+DEFN("LPTE_BUFFERABLE",		L_PTE_BUFFERABLE);
+DEFN("LPTE_CACHEABLE",		L_PTE_CACHEABLE);
+DEFN("LPTE_USER",		L_PTE_USER);
+DEFN("LPTE_WRITE",		L_PTE_WRITE);
+DEFN("LPTE_EXEC",		L_PTE_EXEC);
+DEFN("LPTE_DIRTY",		L_PTE_DIRTY);
+#endif
+
+#ifdef CONFIG_CPU_26
+DEFN("PAGE_PRESENT",		_PAGE_PRESENT);
+DEFN("PAGE_READONLY",		_PAGE_READONLY);
+DEFN("PAGE_NOT_USER",		_PAGE_NOT_USER);
+DEFN("PAGE_OLD",		_PAGE_OLD);
+DEFN("PAGE_CLEAN",		_PAGE_CLEAN);
+#endif
+
+DEFN("PAGE_SZ",			PAGE_SIZE);
+
+DEFN("KSWI_BASE",		0x900000);
+DEFN("KSWI_SYS_BASE",		0x9f0000);
+DEFN("SYS_ERROR0",		0x9f0000);
+}
diff -u --recursive --new-file v2.4.2/linux/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types
--- v2.4.2/linux/arch/arm/tools/mach-types	Mon Nov 27 17:07:59 2000
+++ linux/arch/arm/tools/mach-types	Tue Mar  6 19:44:35 2001
@@ -4,7 +4,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Mon Nov 20 22:59:11 2000
+# Last update: Fri Feb  9 22:27:32 2001
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -48,13 +48,23 @@
 netport			SA1100_NETPORT		NETPORT			38
 pangolin		SA1100_PANGOLIN		PANGOLIN		39
 yopy			SA1100_YOPY		YOPY			40
-sa1100			SA1100_SA1100		SA1100			41
-huw_webpanel		ARCH_HUW_WEBPANEL	HUW_WEBPANEL		42
+coolidge		SA1100_COOLIDGE		coolidge		41
+huw_webpanel		SA1100_HUW_WEBPANEL	HUW_WEBPANEL		42
 spotme			ARCH_SPOTME		SPOTME			43
 freebird		ARCH_FREEBIRD		FREEBIRD		44
 ti925			ARCH_TI925		TI925			45
 riscstation		ARCH_RISCSTATION	RISCSTATION		46
 cavy			SA1100_CAVY		CAVY			47
+jornada720		SA1100_JORNADA720	JORNADA720		48
+omnimeter		SA1100_OMNIMETER	OMNIMETER		49
+edb7211			ARCH_EDB7211		EDB7211			50
+citygo			SA1100_CITYGO		CITYGO			51
+pfs168			SA1100_PFS168		PFS168			52
+spot			SA1100_SPOT		SPOT			53
+flexanet		ARCH_FLEXANET		FLEXANET		54
+webpal			ARCH_WEBPAL		WEBPAL			55
+linpda			SA1100_LINPDA		LINPDA			56
+anakin			ARCH_ANAKIN		ANAKIN			57
 
 # The following are unallocated
 empeg			SA1100_EMPEG		EMPEG
diff -u --recursive --new-file v2.4.2/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in
--- v2.4.2/linux/arch/arm/vmlinux-armv.lds.in	Wed Feb 21 18:20:10 2001
+++ linux/arch/arm/vmlinux-armv.lds.in	Tue Mar  6 19:44:35 2001
@@ -45,18 +45,22 @@
 			*(.glue_7)
 			*(.glue_7t)
 			*(.kstrtab)
-		. = ALIGN(16);
-		__start___ex_table = .;	/* Exception table		*/
+		*(.got)			/* Global offset table		*/
+
+		_etext = .;		/* End of text section		*/
+	}
+
+	. = ALIGN(16);
+	__ex_table : {			/* Exception table		*/
+		__start___ex_table = .;
 			*(__ex_table)
 		__stop___ex_table = .;
+	}
 
-		__start___ksymtab = .;	/* Kernel symbol table		*/
+	__ksymtab : {			/* Kernel symbol table		*/
+		__start___ksymtab = .;
 			*(__ksymtab)
 		__stop___ksymtab = .;
-
-		*(.got)			/* Global offset table		*/
-
-		_etext = .;		/* End of text section		*/
 	}
 
 	. = ALIGN(8192);
diff -u --recursive --new-file v2.4.2/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c
--- v2.4.2/linux/arch/cris/drivers/serial.c	Wed Feb 21 18:20:10 2001
+++ linux/arch/cris/drivers/serial.c	Fri Mar  2 18:38:40 2001
@@ -146,7 +146,7 @@
  *
  * Revision 1.24  2000/02/09 18:02:28  bjornw
  * * Clear serial errors (overrun, framing, parity) correctly. Before, the
- *   receiver would get stuck if an error occured and we did not restart
+ *   receiver would get stuck if an error occurred and we did not restart
  *   the input DMA.
  * * Cosmetics (indentation, some code made into inlines)
  * * Some more debug options
@@ -1371,7 +1371,7 @@
 			} 
 			else { /* it was a valid byte, now let the dma do the rest */
 #ifdef SERIAL_DEBUG_INTR
-				printk("** OK, disabling ser_interupts\n");
+				printk("** OK, disabling ser_interrupts\n");
 #endif
 				e100_disable_serial_data_irq(info);
 			}
diff -u --recursive --new-file v2.4.2/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
--- v2.4.2/linux/arch/cris/kernel/entry.S	Wed Feb 21 18:20:10 2001
+++ linux/arch/cris/kernel/entry.S	Fri Mar  2 18:38:40 2001
@@ -23,7 +23,7 @@
  *  Revision 1.8  2000/11/17 16:53:35  bjornw
  *  Added detection of frame-type in Rexit, so that mmu_bus_fault can
  *  use ret_from_intr in the return-path to check for signals (like SEGV)
- *  and other foul things that might have occured during the fault.
+ *  and other foul things that might have occurred during the fault.
  *
  *  Revision 1.7  2000/10/06 15:04:28  bjornw
  *  Include mof in register savings
diff -u --recursive --new-file v2.4.2/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c
--- v2.4.2/linux/arch/cris/kernel/sys_cris.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/cris/kernel/sys_cris.c	Mon Mar 19 12:35:11 2001
@@ -62,9 +62,9 @@
         }
         
         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-        down(&current->mm->mmap_sem);
+        down_write(&current->mm->mmap_sem);
         ret = do_mmap(file, addr, len, prot, flags, offset);
-        up(&current->mm->mmap_sem);
+        up_write(&current->mm->mmap_sem);
         if (file)
                 fput(file);
  out:
@@ -87,9 +87,9 @@
                         goto out;
         }
 
-        down(&current->mm->mmap_sem);
+        down_write(&current->mm->mmap_sem);
         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-        up(&current->mm->mmap_sem);
+        up_write(&current->mm->mmap_sem);
 
         if (file)
                 fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c
--- v2.4.2/linux/arch/cris/mm/fault.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/cris/mm/fault.c	Mon Mar 19 12:35:11 2001
@@ -146,7 +146,7 @@
  * routines.
  *
  * Notice that the address we're given is aligned to the page the fault
- * occured in, since we only get the PFN in R_MMU_CAUSE not the complete
+ * occurred in, since we only get the PFN in R_MMU_CAUSE not the complete
  * address.
  *
  * error_code:
@@ -212,7 +212,7 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -270,7 +270,7 @@
                 goto out_of_memory;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 	
 	/*
@@ -280,7 +280,7 @@
 
  bad_area:
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
  bad_area_nosemaphore:
 	DPG(show_registers(regs));
@@ -334,14 +334,14 @@
 	 */
 
  out_of_memory:
-        up(&mm->mmap_sem);
+        up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if(user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
 
  do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
          * Send a sigbus, regardless of whether we were in kernel
@@ -381,7 +381,7 @@
                 pmd = pmd_offset(pgd, address);
                 pmd_k = pmd_offset(pgd_k, address);
 
-                if (pmd_present(*pmd) || !pmd_present(*pmd_k))
+                if (!pmd_present(*pmd_k))
                         goto bad_area_nosemaphore;
                 set_pmd(pmd, *pmd_k);
                 return;
diff -u --recursive --new-file v2.4.2/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v2.4.2/linux/arch/i386/boot/Makefile	Mon Dec 20 14:43:39 1999
+++ linux/arch/i386/boot/Makefile	Thu Feb 22 00:25:29 2001
@@ -43,7 +43,7 @@
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
 
 bootsect: bootsect.o
-	$(LD) -Ttext 0x0 -s -oformat binary -o $@ $<
+	$(LD) -Ttext 0x0 -s --oformat binary -o $@ $<
 
 bootsect.o: bootsect.s
 	$(AS) -o $@ $<
@@ -52,7 +52,7 @@
 	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 bbootsect: bbootsect.o
-	$(LD) -Ttext 0x0 -s -oformat binary $< -o $@
+	$(LD) -Ttext 0x0 -s --oformat binary $< -o $@
 
 bbootsect.o: bbootsect.s
 	$(AS) -o $@ $<
@@ -61,7 +61,7 @@
 	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 setup: setup.o
-	$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
+	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
 
 setup.o: setup.s
 	$(AS) -o $@ $<
@@ -70,7 +70,7 @@
 	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 bsetup: bsetup.o
-	$(LD) -Ttext 0x0 -s -oformat binary -e begtext -o $@ $<
+	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
 
 bsetup.o: bsetup.s
 	$(AS) -o $@ $<
diff -u --recursive --new-file v2.4.2/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.2/linux/arch/i386/defconfig	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/defconfig	Fri Mar 23 16:05:44 2001
@@ -280,6 +280,7 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
@@ -382,7 +383,6 @@
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
 # CONFIG_8139TOO is not set
-# CONFIG_RTL8129 is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -434,6 +434,7 @@
 # CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
 CONFIG_PCMCIA_RAYCS=y
+# CONFIG_PCMCIA_HERMES is not set
 # CONFIG_PCMCIA_NETWAVE is not set
 # CONFIG_PCMCIA_WAVELAN is not set
 # CONFIG_AIRONET4500_CS is not set
@@ -529,13 +530,11 @@
 CONFIG_DRM_RADEON=y
 # CONFIG_DRM_I810 is not set
 # CONFIG_DRM_MGA is not set
-CONFIG_PCMCIA_SERIAL=y
 
 #
-# PCMCIA character device support
+# PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
-# CONFIG_PCMCIA_SERIAL_CB is not set
 
 #
 # Multimedia devices
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.4.2/linux/arch/i386/kernel/i386_ksyms.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/kernel/i386_ksyms.c	Fri Mar  2 12:03:49 2001
@@ -27,6 +27,7 @@
 #include <asm/mmx.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
+#include <asm/pgalloc.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
@@ -134,6 +135,9 @@
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(smp_call_function);
+
+/* TLB flushing */
+EXPORT_SYMBOL(flush_tlb_page);
 #endif
 
 #ifdef CONFIG_MCA
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/i387.c linux/arch/i386/kernel/i387.c
--- v2.4.2/linux/arch/i386/kernel/i387.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/kernel/i387.c	Fri Feb 23 10:09:08 2001
@@ -179,7 +179,7 @@
 
 unsigned short get_fpu_mxcsr( struct task_struct *tsk )
 {
-	if ( cpu_has_fxsr ) {
+	if ( cpu_has_xmm ) {
 		return tsk->thread.i387.fxsave.mxcsr;
 	} else {
 		return 0x1f80;
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.4.2/linux/arch/i386/kernel/ldt.c	Fri Dec 29 14:07:20 2000
+++ linux/arch/i386/kernel/ldt.c	Mon Mar 19 12:35:09 2001
@@ -86,7 +86,7 @@
 	 * the GDT index of the LDT is allocated dynamically, and is
 	 * limited by MAX_LDT_DESCRIPTORS.
 	 */
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 	if (!mm->context.segments) {
 		error = -ENOMEM;
 		mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
@@ -141,7 +141,7 @@
 	error = 0;
 
 out_unlock:
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 out:
 	return error;
 }
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c
--- v2.4.2/linux/arch/i386/kernel/pci-pc.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/kernel/pci-pc.c	Sun Mar 18 19:54:05 2001
@@ -861,6 +861,8 @@
 	}
 }
 
+#if 0
+/* Our bus code shouldnt need this fixup any more. Delete once verified */
 /*	
  * Compaq host bridges -- Find and scan all secondary buses.
  * This time registers 0xc8 and 0xc9.
@@ -878,6 +880,7 @@
 		printk("PCI: Compaq host bridge: last bus %02x\n", busno2);
 	}
 }
+#endif	
 
 static void __init pci_fixup_umc_ide(struct pci_dev *d)
 {
@@ -934,35 +937,116 @@
 	pcibios_max_latency = 32;
 }
 
+static void __init pci_fixup_via_acpi(struct pci_dev *d)
+{
+	/*
+	 * VIA ACPI device: IRQ line in PCI config byte 0x42
+	 */
+	u8 irq;
+	pci_read_config_byte(d, 0x42, &irq);
+	irq &= 0x0f;
+	if (irq && (irq != 2))
+		d->irq = irq;
+}
+
+static void __init pci_fixup_piix4_acpi(struct pci_dev *d)
+{
+	/*
+	 * PIIX4 ACPI device: hardwired IRQ9
+	 */
+	d->irq = 9;
+}
+
 static void __init pci_fixup_vt8363(struct pci_dev *d)
 {
 	/*
-	 *  VIA VT8363 host bridge has broken feature 'PCI Master Read
-	 *  Caching'. It caches more than is good for it, sometimes
-	 *  serving the bus master with stale data. Some BIOSes enable
-	 *  it by default, so we disable it.
+	 * The VIA bridge will corrupt disks without these settings.
 	 */
 	u8 tmp;
+	pci_read_config_byte(d, 0x54, &tmp);
+	if(tmp & (1<<2)) {
+		printk("PCI: Bus master Pipeline request disabled\n");
+		pci_write_config_byte(d, 0x54, tmp & ~(1<<2));
+	}
+	pci_read_config_byte(d, 0x54, &tmp);
+	if(tmp & (1)) {
+		printk("PCI: Fast Write to Read turnaround disabled\n");
+		pci_write_config_byte(d, 0x54, tmp & ~(1));
+	}
 	pci_read_config_byte(d, 0x70, &tmp);
-	if(tmp & 4) {
-		printk("PCI: Bus master read caching disabled\n");
-		pci_write_config_byte(d, 0x70, tmp & ~4);
+	if(tmp & (1<<3)) {
+		printk("PCI: Disabled enhanced CPU to PCI writes\n");
+		pci_write_config_byte(d, 0x70, tmp & ~(1<<3));
+	}
+	pci_read_config_byte(d, 0x70, &tmp);
+	if(tmp & (1<<2)) {
+		printk("PCI: Disabled Master Read Caching\n");
+		pci_write_config_byte(d, 0x70, tmp & ~(1<<2));
+	}
+	pci_read_config_byte(d, 0x71, &tmp);
+	if ((tmp & (1<<3))==0) {
+		printk("PCI: Bursting cornercase bug worked around\n");
+		pci_write_config_byte(d, 0x71, tmp | (1<<3));
+	}
+	pci_read_config_byte(d, 0x76, &tmp);
+	if(tmp & (1<<7)) {
+		printk("PCI: Post Write Fail set to Retry\n");
+		pci_write_config_byte(d, 0x76, tmp & ~(1<<7));
 	}
 }
 
+static void __init pci_fixup_via691(struct pci_dev *d)
+{
+	/*
+	 * The VIA bridge corrupts with Posting enabled
+	 */
+	u8 tmp;
+	
+	pci_read_config_byte(d, 0x70, &tmp);
+	if(tmp & (1<<7)) {
+		printk("PCI: Disabled enhanced CPU to PCI posting\n");
+		pci_write_config_byte(d, 0x70, tmp & ~(1<<7));
+	}
+}
+static void __init pci_fixup_via691_2(struct pci_dev *d)
+{
+	/*
+	 * The VIA bridge corrupts with Posting enabled
+	 */
+	u8 tmp;
+	
+	pci_read_config_byte(d, 0x40, &tmp);
+	if(tmp & (1<<7)) {
+		printk("PCI: Disabled enhanced CPU to PCI posting #2\n");
+		pci_write_config_byte(d, 0x40, tmp & ~(1<<7));
+	}
+}
+
+
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82451NX,	pci_fixup_i450nx },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82454GX,	pci_fixup_i450gx },
+#if 0
+/* Until we get proper handling pray the BIOS gets it right */
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SERVERWORKS,	PCI_DEVICE_ID_SERVERWORKS_HE,		pci_fixup_serverworks },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SERVERWORKS,	PCI_DEVICE_ID_SERVERWORKS_LE,		pci_fixup_serverworks },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SERVERWORKS,	PCI_DEVICE_ID_SERVERWORKS_CMIC_HE,	pci_fixup_serverworks },
+#endif	
+#if 0
+/* Our bus code shouldnt need this fixup any more. Delete once verified */
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_COMPAQ,	PCI_DEVICE_ID_COMPAQ_6010,	pci_fixup_compaq },
+#endif	
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_UMC,	PCI_DEVICE_ID_UMC_UM8886BF,	pci_fixup_umc_ide },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5513,		pci_fixup_ide_trash },
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_vt8363 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	pci_fixup_via_acpi },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C686_4,	pci_fixup_via_acpi },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_vt8363 },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C691,	pci_fixup_via691 },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C598_1,	pci_fixup_via691_2 },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
 	{ 0 }
 };
 
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.4.2/linux/arch/i386/kernel/ptrace.c	Mon Oct 30 14:46:53 2000
+++ linux/arch/i386/kernel/ptrace.c	Tue Mar  6 19:44:37 2001
@@ -167,14 +167,16 @@
 	if (request == PTRACE_ATTACH) {
 		if (child == current)
 			goto out_tsk;
-		if ((!child->dumpable ||
-		    (current->uid != child->euid) ||
+		if(((current->uid != child->euid) ||
 		    (current->uid != child->suid) ||
 		    (current->uid != child->uid) ||
 	 	    (current->gid != child->egid) ||
 	 	    (current->gid != child->sgid) ||
 	 	    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
 	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+			goto out_tsk;
+		rmb();
+		if (!child->dumpable && !capable(CAP_SYS_PTRACE))
 			goto out_tsk;
 		/* the same process cannot be attached many times */
 		if (child->ptrace & PT_PTRACED)
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.4.2/linux/arch/i386/kernel/setup.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/kernel/setup.c	Mon Mar 19 14:44:22 2001
@@ -418,8 +418,9 @@
 	int i;
 
 	for (i = 0; i < e820.nr_map; i++) {
-		printk(" %s: %016Lx @ %016Lx ", who,
-			e820.map[i].size, e820.map[i].addr);
+		printk(" %s: %016Lx - %016Lx ", who,
+			e820.map[i].addr,
+			e820.map[i].addr + e820.map[i].size);
 		switch (e820.map[i].type) {
 		case E820_RAM:	printk("(usable)\n");
 				break;
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/sys_i386.c linux/arch/i386/kernel/sys_i386.c
--- v2.4.2/linux/arch/i386/kernel/sys_i386.c	Wed Jul  5 11:31:00 2000
+++ linux/arch/i386/kernel/sys_i386.c	Mon Mar 19 12:35:09 2001
@@ -55,9 +55,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.4.2/linux/arch/i386/kernel/traps.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/kernel/traps.c	Mon Mar 19 18:23:40 2001
@@ -388,7 +388,7 @@
 
 #if CONFIG_X86_IO_APIC
 
-int nmi_watchdog = 1;
+int nmi_watchdog = 0;
 
 static int __init setup_nmi_watchdog(char *str)
 {
diff -u --recursive --new-file v2.4.2/linux/arch/i386/lib/mmx.c linux/arch/i386/lib/mmx.c
--- v2.4.2/linux/arch/i386/lib/mmx.c	Sat Feb  3 19:51:22 2001
+++ linux/arch/i386/lib/mmx.c	Thu Mar  1 18:04:34 2001
@@ -3,6 +3,7 @@
 #include <linux/sched.h>
 
 #include <asm/i387.h>
+#include <asm/hardirq.h> 
 
 /*
  *	MMX 3DNow! library helper functions
@@ -25,8 +26,14 @@
  
 void *_mmx_memcpy(void *to, const void *from, size_t len)
 {
-	void *p=to;
-	int i= len >> 6;	/* len/64 */
+	void *p;
+	int i;
+
+	if (in_interrupt())
+		return __memcpy(to, from, len);
+
+	p = to;
+	i = len >> 6; /* len/64 */
 
 	kernel_fpu_begin();
 
diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/extable.c linux/arch/i386/mm/extable.c
--- v2.4.2/linux/arch/i386/mm/extable.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/mm/extable.c	Fri Mar  2 11:12:07 2001
@@ -49,7 +49,7 @@
 
 	spin_lock_irqsave(&modlist_lock, flags);
 	for (mp = module_list; mp != NULL; mp = mp->next) {
-		if (mp->ex_table_start == NULL)
+		if (mp->ex_table_start == NULL || !(mp->flags&(MOD_RUNNING|MOD_INITIALIZING)))
 			continue;
 		ret = search_one_table(mp->ex_table_start,
 				       mp->ex_table_end - 1, addr);
diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.4.2/linux/arch/i386/mm/fault.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/i386/mm/fault.c	Mon Mar 19 12:35:09 2001
@@ -141,7 +141,7 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -214,7 +214,7 @@
 		if (bit < 32)
 			tsk->thread.screen_bitmap |= 1 << bit;
 	}
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
@@ -222,7 +222,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
@@ -290,14 +290,14 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (error_code & 4)
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.4.2/linux/arch/i386/mm/init.c	Sat Feb  3 19:51:22 2001
+++ linux/arch/i386/mm/init.c	Mon Mar 19 17:25:19 2001
@@ -111,61 +111,23 @@
 	set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
 }
 
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page(pte);
-			set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte)));
-			return pte + offset;
-		}
-		set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(get_bad_pte_table())));
-		return NULL;
-	}
-	free_page((unsigned long)pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	unsigned long pte;
-
-	pte = (unsigned long) __get_free_page(GFP_KERNEL);
-	if (pmd_none(*pmd)) {
-		if (pte) {
-			clear_page((void *)pte);
-			set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)));
-			return (pte_t *)pte + offset;
-		}
-		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(get_bad_pte_table())));
-		return NULL;
-	}
-	free_page(pte);
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + offset;
-}
-
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
 	if(pgtable_cache_size > high) {
 		do {
-			if(pgd_quicklist)
-				free_pgd_slow(get_pgd_fast()), freed++;
-			if(pmd_quicklist)
-				free_pmd_slow(get_pmd_fast()), freed++;
-			if(pte_quicklist)
-				free_pte_slow(get_pte_fast()), freed++;
+			if (pgd_quicklist) {
+				free_pgd_slow(get_pgd_fast());
+				freed++;
+			}
+			if (pmd_quicklist) {
+				pmd_free_slow(pmd_alloc_one_fast());
+				freed++;
+			}
+			if (pte_quicklist) {
+				pte_free_slow(pte_alloc_one_fast());
+				freed++;
+			}
 		} while(pgtable_cache_size > low);
 	}
 	return freed;
diff -u --recursive --new-file v2.4.2/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c
--- v2.4.2/linux/arch/i386/mm/ioremap.c	Thu Oct 12 12:44:04 2000
+++ linux/arch/i386/mm/ioremap.c	Tue Mar 20 08:13:33 2001
@@ -49,7 +49,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
@@ -62,6 +62,7 @@
 static int remap_area_pages(unsigned long address, unsigned long phys_addr,
 				 unsigned long size, unsigned long flags)
 {
+	int error;
 	pgd_t * dir;
 	unsigned long end = address + size;
 
@@ -70,19 +71,23 @@
 	flush_cache_all();
 	if (address >= end)
 		BUG();
+	spin_lock(&init_mm.page_table_lock);
 	do {
 		pmd_t *pmd;
-		pmd = pmd_alloc_kernel(dir, address);
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
 		if (!pmd)
-			return -ENOMEM;
+			break;
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
-			return -ENOMEM;
+			break;
+		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
-	return 0;
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c
--- v2.4.2/linux/arch/ia64/ia32/binfmt_elf32.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/ia32/binfmt_elf32.c	Thu Mar 22 09:24:58 2001
@@ -204,7 +204,6 @@
 
 	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
 		if (bprm->page[i]) {
-			current->mm->rss++;
 			put_dirty_page(current,bprm->page[i],stack_base);
 		}
 		stack_base += PAGE_SIZE;
@@ -260,11 +259,11 @@
 #	define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
 #	define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	retval = ia32_do_mmap(filep, IA32_PAGESTART(addr),
 			      eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type,
 			      eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr));
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 #endif
 	return retval;
 }
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- v2.4.2/linux/arch/ia64/ia32/sys_ia32.c	Wed Feb 21 18:20:11 2001
+++ linux/arch/ia64/ia32/sys_ia32.c	Mon Mar 19 12:35:10 2001
@@ -120,12 +120,12 @@
 	 *  `execve' frees all current memory we only have to do an
 	 *  `munmap' if the `execve' failes.
 	 */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 
 	av = (char **) do_mmap_pgoff(0, 0UL, len, PROT_READ | PROT_WRITE,
 				     MAP_PRIVATE | MAP_ANONYMOUS, 0);
 
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (IS_ERR(av))
 		return (long)av;
@@ -247,9 +247,9 @@
 		back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL);
 		__copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));
 	}
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	r = do_mmap(0, baddr, len + (addr - baddr), prot, flags | MAP_ANONYMOUS, 0);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if (r < 0)
 		return(r);
 	if (addr == 0)
@@ -293,9 +293,9 @@
  		poff = offset & PAGE_MASK;
  		len += offset - poff;
 
- 		down(&current->mm->mmap_sem);
+ 		down_write(&current->mm->mmap_sem);
  		error = do_mmap_pgoff(file, addr, len, prot, flags, poff >> PAGE_SHIFT);
-  		up(&current->mm->mmap_sem);
+  		up_write(&current->mm->mmap_sem);
 
  		if (!IS_ERR((void *) error))
  			error += offset - poff;
@@ -2573,7 +2573,7 @@
 		return(-EFAULT);
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	lock_kernel();
 
 	addr = do_mmap_pgoff(file, IA32_IOBASE,
@@ -2581,7 +2581,7 @@
 			(ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
 
 	unlock_kernel();
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (addr >= 0) {
 		__asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr));
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c
--- v2.4.2/linux/arch/ia64/kernel/sys_ia64.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/kernel/sys_ia64.c	Mon Mar 19 12:35:10 2001
@@ -102,7 +102,7 @@
 	 * check and the clearing of r8.  However, we can't call sys_brk() because we need
 	 * to acquire the mmap_sem before we can do the test...
 	 */
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 
 	if (brk < mm->end_code)
 		goto out;
@@ -142,7 +142,7 @@
 	mm->brk = brk;
 out:
 	retval = mm->brk;
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	regs->r8 = 0;		/* ensure large retval isn't mistaken as error code */
 	return retval;
 }
@@ -200,9 +200,9 @@
 	if (flags & MAP_SHARED)
 		current->thread.flags |= IA64_THREAD_MAP_SHARED;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	current->thread.flags &= ~IA64_THREAD_MAP_SHARED;
 
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S
--- v2.4.2/linux/arch/ia64/lib/copy_user.S	Wed Feb 21 18:20:11 2001
+++ linux/arch/ia64/lib/copy_user.S	Tue Mar  6 19:44:35 2001
@@ -16,7 +16,7 @@
  *	in2	number of bytes to copy
  *
  * Outputs: 
- * 	ret0	0 in case of sucess. The number of bytes NOT copied in
+ * 	ret0	0 in case of success. The number of bytes NOT copied in
  * 		case of error.
  *
  * Copyright (C) 2000 Hewlett-Packard Co
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/lib/strlen.S linux/arch/ia64/lib/strlen.S
--- v2.4.2/linux/arch/ia64/lib/strlen.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/strlen.S	Tue Mar  6 19:44:35 2001
@@ -198,5 +198,5 @@
 	;;
 	sub ret0=ret0,tmp	// length=now - back -1
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp	// end of sucessful recovery code
+	br.ret.sptk.few rp	// end of successful recovery code
 END(strlen)
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/lib/strlen_user.S linux/arch/ia64/lib/strlen_user.S
--- v2.4.2/linux/arch/ia64/lib/strlen_user.S	Thu Jun 22 07:09:44 2000
+++ linux/arch/ia64/lib/strlen_user.S	Tue Mar  6 19:44:35 2001
@@ -204,7 +204,7 @@
 	;;
 	sub ret0=ret0,tmp	// length=now - back -1
 	mov ar.pfs=saved_pfs	// because of ar.ec, restore no matter what
-	br.ret.sptk.few rp	// end of sucessful recovery code
+	br.ret.sptk.few rp	// end of successful recovery code
 
 	//
 	// We failed even on the normal load (called from exception handler)
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/mm/fault.c linux/arch/ia64/mm/fault.c
--- v2.4.2/linux/arch/ia64/mm/fault.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/mm/fault.c	Mon Mar 19 12:35:10 2001
@@ -60,7 +60,7 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	vma = find_vma_prev(mm, address, &prev_vma);
 	if (!vma)
@@ -112,7 +112,7 @@
 	      default:
 		goto out_of_memory;
 	}
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
   check_expansion:
@@ -135,7 +135,7 @@
 	goto good_area;
 
   bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	if (isr & IA64_ISR_SP) {
 		/*
 		 * This fault was due to a speculative load set the "ed" bit in the psr to
@@ -185,7 +185,7 @@
 	return;
 
   out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/sn/io/l1.c linux/arch/ia64/sn/io/l1.c
--- v2.4.2/linux/arch/ia64/sn/io/l1.c	Wed Feb 21 18:20:12 2001
+++ linux/arch/ia64/sn/io/l1.c	Tue Mar  6 19:44:35 2001
@@ -2788,7 +2788,7 @@
     while( (r = _elscuart_poll( sc )) == 0 );
 
     if( r < 0 ) {
-	/* some error occured */
+	/* some error occurred */
 	return r;
     }
 
diff -u --recursive --new-file v2.4.2/linux/arch/ia64/sn/io/pcibr.c linux/arch/ia64/sn/io/pcibr.c
--- v2.4.2/linux/arch/ia64/sn/io/pcibr.c	Wed Feb 21 18:20:12 2001
+++ linux/arch/ia64/sn/io/pcibr.c	Tue Mar  6 19:44:35 2001
@@ -3925,7 +3925,7 @@
      * above.
      *
      * Need to set the D_INTR_ISERR flag
-     * in the dev_desc used for alocating the
+     * in the dev_desc used for allocating the
      * error interrupt, so our interrupt will
      * be properly routed and prioritized.
      *
@@ -5540,7 +5540,7 @@
     } else
 	xio_port = pcibr_dmamap->bd_xio_port;
 
-    /* If this DMA is to an addres that
+    /* If this DMA is to an address that
      * refers back to this Bridge chip,
      * reduce it back to the correct
      * PCI MEM address.
@@ -8540,7 +8540,7 @@
 	 *
 	 * CAUTION: Resetting bit BRIDGE_IRR_PCI_GRP_CLR, acknowledges
 	 *      a group of interrupts. If while handling this error,
-	 *      some other error has occured, that would be
+	 *      some other error has occurred, that would be
 	 *      implicitly cleared by this write.
 	 *      Need a way to ensure we don't inadvertently clear some
 	 *      other errors.
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/apollo/dn_ints.c linux/arch/m68k/apollo/dn_ints.c
--- v2.4.2/linux/arch/m68k/apollo/dn_ints.c	Fri Jul 14 12:20:22 2000
+++ linux/arch/m68k/apollo/dn_ints.c	Tue Mar  6 19:44:35 2001
@@ -24,7 +24,7 @@
     dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp);
   }
   else {
-    printk("spurious irq %d occured\n",irq);
+    printk("spurious irq %d occurred\n",irq);
   }
 
   *(volatile unsigned char *)(pica)=0x20;
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/fpsp.S linux/arch/m68k/ifpsp060/src/fpsp.S
--- v2.4.2/linux/arch/m68k/ifpsp060/src/fpsp.S	Wed Feb 21 18:20:12 2001
+++ linux/arch/m68k/ifpsp060/src/fpsp.S	Tue Mar  6 19:44:35 2001
@@ -23523,7 +23523,7 @@
 #		in INEX2.						#
 #									#
 #	A10.	Or in INEX.						#
-#		If INEX is set, round error occured.  This is		#
+#		If INEX is set, round error occurred.  This is		#
 #		compensated for by 'or-ing' in the INEX2 flag to	#
 #		the lsb of Y.						#
 #									#
@@ -23989,7 +23989,7 @@
 	fmul.x		%fp1,%fp0	# calculate X * SCALE -> Y to fp0
 
 # A10. Or in INEX.
-#      If INEX is set, round error occured.  This is compensated
+#      If INEX is set, round error occurred.  This is compensated
 #      for by 'or-ing' in the INEX2 flag to the lsb of Y.
 #
 # Register usage:
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/ilsp.S linux/arch/m68k/ifpsp060/src/ilsp.S
--- v2.4.2/linux/arch/m68k/ifpsp060/src/ilsp.S	Fri Dec 29 14:07:20 2000
+++ linux/arch/m68k/ifpsp060/src/ilsp.S	Tue Mar  6 19:44:35 2001
@@ -514,7 +514,7 @@
 #	fmovm.l		&0x0,-(%sp)		# save no fpregs
 # PROLOGUE END ##########################################################
 
-	mov.w		%cc,MUL64_CC(%a6)	# save incomming ccodes
+	mov.w		%cc,MUL64_CC(%a6)	# save incoming ccodes
 
 	mov.l		0x8(%a6),%d0		# store multiplier in d0
 	beq.w		mulu64_zero		# handle zero separately
@@ -625,7 +625,7 @@
 #	fmovm.l		&0x0,-(%sp)		# save no fpregs
 # PROLOGUE END ##########################################################
 
-	mov.w		%cc,MUL64_CC(%a6)	# save incomming ccodes
+	mov.w		%cc,MUL64_CC(%a6)	# save incoming ccodes
 
 	mov.l		0x8(%a6),%d0		# store multiplier in d0
 	beq.b		mulu64_zero		# handle zero separately
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/isp.S linux/arch/m68k/ifpsp060/src/isp.S
--- v2.4.2/linux/arch/m68k/ifpsp060/src/isp.S	Wed Feb 21 18:20:12 2001
+++ linux/arch/m68k/ifpsp060/src/isp.S	Tue Mar  6 19:44:36 2001
@@ -3835,7 +3835,7 @@
 #	    assert LOCKE* for the final write operation.		#
 #	(13)Exit.							#
 # 									#
-# 	The algorithm is actually implemented slightly diferently	#
+# 	The algorithm is actually implemented slightly differently	#
 # depending on the size of the operation and the misalignment of the	#
 # operand. A misaligned operand must be written in aligned chunks or	#
 # else the BUSCR register control gets confused.			#
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/ifpsp060/src/pfpsp.S linux/arch/m68k/ifpsp060/src/pfpsp.S
--- v2.4.2/linux/arch/m68k/ifpsp060/src/pfpsp.S	Wed Feb 21 18:20:12 2001
+++ linux/arch/m68k/ifpsp060/src/pfpsp.S	Tue Mar  6 19:44:36 2001
@@ -13483,7 +13483,7 @@
 #		in INEX2.						#
 #									#
 #	A10.	Or in INEX.						#
-#		If INEX is set, round error occured.  This is		#
+#		If INEX is set, round error occurred.  This is		#
 #		compensated for by 'or-ing' in the INEX2 flag to	#
 #		the lsb of Y.						#
 #									#
@@ -13949,7 +13949,7 @@
 	fmul.x		%fp1,%fp0	# calculate X * SCALE -> Y to fp0
 
 # A10. Or in INEX.
-#      If INEX is set, round error occured.  This is compensated
+#      If INEX is set, round error occurred.  This is compensated
 #      for by 'or-ing' in the INEX2 flag to the lsb of Y.
 #
 # Register usage:
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c
--- v2.4.2/linux/arch/m68k/kernel/bios32.c	Wed Feb 21 18:20:12 2001
+++ linux/arch/m68k/kernel/bios32.c	Tue Mar  6 19:44:36 2001
@@ -444,7 +444,7 @@
  * dev	- device.
  * i	- resource.
  *
- * Result: 0 if successfull.
+ * Result: 0 if successful.
  */
 
 int __init pcibios_assign_resource(struct pci_dev *dev, int i)
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- v2.4.2/linux/arch/m68k/kernel/head.S	Wed Jan 26 12:44:20 2000
+++ linux/arch/m68k/kernel/head.S	Tue Mar  6 19:44:36 2001
@@ -840,7 +840,7 @@
 #ifdef CONFIG_MVME16x
 	is_not_mvme16x(L(gvtdone))
 
-	/* Need to get the BRD_ID info to diferentiate between 162, 167,
+	/* Need to get the BRD_ID info to differentiate between 162, 167,
 	 * etc.  This is available as a BI_VME_BRDINFO tag with later
 	 * versions of VMELILO and TFTPLILO, otherwise we call the Bug.
 	 */
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/ints.c linux/arch/m68k/kernel/ints.c
--- v2.4.2/linux/arch/m68k/kernel/ints.c	Mon Nov 27 17:11:26 2000
+++ linux/arch/m68k/kernel/ints.c	Tue Mar  6 19:44:36 2001
@@ -184,7 +184,7 @@
 /*
  * Do we need these probe functions on the m68k?
  *
- *  ... may be usefull with ISA devices
+ *  ... may be useful with ISA devices
  */
 unsigned long probe_irq_on (void)
 {
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- v2.4.2/linux/arch/m68k/kernel/sys_m68k.c	Mon Nov 27 17:11:26 2000
+++ linux/arch/m68k/kernel/sys_m68k.c	Mon Mar 19 12:35:09 2001
@@ -59,9 +59,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
@@ -146,9 +146,9 @@
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if (file)
 		fput(file);
 out:
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.4.2/linux/arch/m68k/mm/fault.c	Thu Jan  4 13:00:55 2001
+++ linux/arch/m68k/mm/fault.c	Mon Mar 19 12:35:10 2001
@@ -101,7 +101,7 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -168,7 +168,7 @@
 	#warning should be obsolete now...
 	if (CPU_IS_040_OR_060)
 		flush_tlb_page(vma, address);
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return 0;
 
 /*
@@ -203,6 +203,6 @@
 	current->thread.faddr = address;
 
 send_sig:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return send_fault_sig(regs);
 }
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/q40/README linux/arch/m68k/q40/README
--- v2.4.2/linux/arch/m68k/q40/README	Mon Nov 27 17:11:26 2000
+++ linux/arch/m68k/q40/README	Tue Mar  6 19:44:36 2001
@@ -127,7 +127,7 @@
 	- exact keypress/release sequence
 	- 'showkey -s' run on q40, non-X session
 	- 'showkey -s' run on a PC, non-X session
-	- AT codes as displayed by the q40 debuging ROM
+	- AT codes as displayed by the q40 debugging ROM
 btw if the showkey output from PC and Q40 doesn't differ then you have some
 classic configuration problem - don't send me anything in this case
 
diff -u --recursive --new-file v2.4.2/linux/arch/m68k/q40/config.c linux/arch/m68k/q40/config.c
--- v2.4.2/linux/arch/m68k/q40/config.c	Mon Nov 27 17:57:34 2000
+++ linux/arch/m68k/q40/config.c	Tue Mar  6 19:44:36 2001
@@ -238,7 +238,7 @@
     mach_max_dma_address = 32*1024*1024;   /* no DMA at all, but ide-scsi requires it.. */
 
 
-/* userfull for early debuging stages writes kernel messages into SRAM */
+/* userfull for early debugging stages writes kernel messages into SRAM */
 
     if (!strncmp( m68k_debug_device,"mem",3 ))
       {
diff -u --recursive --new-file v2.4.2/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c
--- v2.4.2/linux/arch/mips/baget/irq.c	Wed Feb 21 18:20:13 2001
+++ linux/arch/mips/baget/irq.c	Tue Mar  6 19:44:36 2001
@@ -199,7 +199,7 @@
 			add_interrupt_randomness(irq);
 		__cli();
 	} else {
-		printk("do_IRQ: Unregistered IRQ (0x%X) occured\n", irq);
+		printk("do_IRQ: Unregistered IRQ (0x%X) occurred\n", irq);
 	}
 	unmask_irq(irq);
 	irq_exit(cpu);
diff -u --recursive --new-file v2.4.2/linux/arch/mips/boot/elf2ecoff.c linux/arch/mips/boot/elf2ecoff.c
--- v2.4.2/linux/arch/mips/boot/elf2ecoff.c	Mon Jul  5 20:35:17 1999
+++ linux/arch/mips/boot/elf2ecoff.c	Tue Mar  6 19:44:36 2001
@@ -435,7 +435,7 @@
   char ibuf [4096];
   int remaining, cur, count;
 
-  /* Go the the start of the ELF symbol table... */
+  /* Go to the start of the ELF symbol table... */
   if (lseek (in, offset, SEEK_SET) < 0)
     {
       perror ("copy: lseek");
diff -u --recursive --new-file v2.4.2/linux/arch/mips/dec/prom/memory.c linux/arch/mips/dec/prom/memory.c
--- v2.4.2/linux/arch/mips/dec/prom/memory.c	Mon Aug  7 21:02:27 2000
+++ linux/arch/mips/dec/prom/memory.c	Tue Mar  6 19:44:36 2001
@@ -31,7 +31,7 @@
 extern int (*prom_printf)(char *, ...);
 #endif
 
-volatile unsigned long mem_err = 0;	/* So we know an error occured */
+volatile unsigned long mem_err = 0;	/* So we know an error occurred */
 
 extern char _end;
 
diff -u --recursive --new-file v2.4.2/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.4.2/linux/arch/mips/defconfig	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips/defconfig	Sun Mar  4 14:30:18 2001
@@ -175,6 +175,7 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
diff -u --recursive --new-file v2.4.2/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.4.2/linux/arch/mips/kernel/irixelf.c	Wed Feb 21 18:20:13 2001
+++ linux/arch/mips/kernel/irixelf.c	Mon Mar 19 12:35:09 2001
@@ -314,12 +314,12 @@
 		   (unsigned long) elf_prot, (unsigned long) elf_type,
 		   (unsigned long) (eppnt->p_offset & 0xfffff000));
 #endif
-	    down(&current->mm->mmap_sem);
+	    down_write(&current->mm->mmap_sem);
 	    error = do_mmap(interpreter, vaddr,
 			    eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
 			    elf_prot, elf_type,
 			    eppnt->p_offset & 0xfffff000);
-	    up(&current->mm->mmap_sem);
+	    up_write(&current->mm->mmap_sem);
 
 	    if(error < 0 && error > -1024) {
 		    printk("Aieee IRIX interp mmap error=%d\n", error);
@@ -498,12 +498,12 @@
 		prot  = (epp->p_flags & PF_R) ? PROT_READ : 0;
 		prot |= (epp->p_flags & PF_W) ? PROT_WRITE : 0;
 		prot |= (epp->p_flags & PF_X) ? PROT_EXEC : 0;
-	        down(&current->mm->mmap_sem);
+	        down_write(&current->mm->mmap_sem);
 		(void) do_mmap(fp, (epp->p_vaddr & 0xfffff000),
 			       (epp->p_filesz + (epp->p_vaddr & 0xfff)),
 			       prot, EXEC_MAP_FLAGS,
 			       (epp->p_offset & 0xfffff000));
-	        up(&current->mm->mmap_sem);
+	        up_write(&current->mm->mmap_sem);
 
 		/* Fixup location tracking vars. */
 		if((epp->p_vaddr & 0xfffff000) < *estack)
@@ -762,10 +762,10 @@
 	 * Since we do not have the power to recompile these, we
 	 * emulate the SVr4 behavior.  Sigh.
 	 */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	(void) do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
 		       MAP_FIXED | MAP_PRIVATE, 0);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 #endif
 
 	start_thread(regs, elf_entry, bprm->p);
@@ -837,14 +837,14 @@
 	while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
 	
 	/* Now use mmap to map the library into memory. */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap(file,
 			elf_phdata->p_vaddr & 0xfffff000,
 			elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
 			PROT_READ | PROT_WRITE | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
 			elf_phdata->p_offset & 0xfffff000);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
 	if (k > elf_bss) elf_bss = k;
@@ -916,12 +916,12 @@
 		prot  = (hp->p_flags & PF_R) ? PROT_READ : 0;
 		prot |= (hp->p_flags & PF_W) ? PROT_WRITE : 0;
 		prot |= (hp->p_flags & PF_X) ? PROT_EXEC : 0;
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 		retval = do_mmap(filp, (hp->p_vaddr & 0xfffff000),
 				 (hp->p_filesz + (hp->p_vaddr & 0xfff)),
 				 prot, (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
 				 (hp->p_offset & 0xfffff000));
-		up(&current->mm->mmap_sem);
+		up_write(&current->mm->mmap_sem);
 
 		if(retval != (hp->p_vaddr & 0xfffff000)) {
 			printk("irix_mapelf: do_mmap fails with %d!\n", retval);
diff -u --recursive --new-file v2.4.2/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c
--- v2.4.2/linux/arch/mips/kernel/mips_ksyms.c	Fri Aug  4 16:15:37 2000
+++ linux/arch/mips/kernel/mips_ksyms.c	Fri Mar  2 11:15:47 2001
@@ -140,3 +140,4 @@
 #endif
 
 EXPORT_SYMBOL(get_wchan);
+EXPORT_SYMBOL(flush_tlb_page);
diff -u --recursive --new-file v2.4.2/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
--- v2.4.2/linux/arch/mips/kernel/syscall.c	Tue Sep  5 13:50:02 2000
+++ linux/arch/mips/kernel/syscall.c	Mon Mar 19 12:35:09 2001
@@ -69,9 +69,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.4.2/linux/arch/mips/kernel/sysirix.c	Wed Feb 21 18:20:13 2001
+++ linux/arch/mips/kernel/sysirix.c	Mon Mar 19 12:35:09 2001
@@ -472,7 +472,7 @@
 		if (retval)
 			return retval;
 
-		down(&mm->mmap_sem);
+		down_read(&mm->mmap_sem);
 		pgdp = pgd_offset(mm, addr);
 		pmdp = pmd_offset(pgdp, addr);
 		ptep = pte_offset(pmdp, addr);
@@ -485,7 +485,7 @@
 				                   PAGE_SHIFT, pageno);
 			}
 		}
-		up(&mm->mmap_sem);
+		up_read(&mm->mmap_sem);
 		break;
 	}
 
@@ -535,7 +535,7 @@
 	struct mm_struct *mm = current->mm;
 	int ret;
 
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 	if (brk < mm->end_code) {
 		ret = -ENOMEM;
 		goto out;
@@ -593,7 +593,7 @@
 	ret = 0;
 
 out:
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	return ret;
 }
 
@@ -1083,9 +1083,9 @@
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	retval = do_mmap(file, addr, len, prot, flags, offset);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if (file)
 		fput(file);
 
@@ -1643,9 +1643,9 @@
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.4.2/linux/arch/mips/mm/fault.c	Sun Jul  9 22:18:15 2000
+++ linux/arch/mips/mm/fault.c	Mon Mar 19 12:35:09 2001
@@ -60,7 +60,7 @@
 	printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid,
 	       address, write, regs->cp0_epc);
 #endif
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -103,7 +103,7 @@
 		goto out_of_memory;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
@@ -111,7 +111,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
 		tsk->thread.cp0_badvaddr = address;
@@ -163,14 +163,14 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c
--- v2.4.2/linux/arch/mips/mm/umap.c	Mon Aug  7 21:02:27 2000
+++ linux/arch/mips/mm/umap.c	Mon Mar 19 12:35:09 2001
@@ -94,7 +94,7 @@
 	unsigned long beg = start;
 	pgd_t *dir;
 
-	down (&task->mm->mmap_sem);
+	down_write (&task->mm->mmap_sem);
 	dir = pgd_offset (task->mm, start);
 	flush_cache_range (task->mm, beg, end);
 	while (start < end){
@@ -103,7 +103,7 @@
 		dir++;
 	}
 	flush_tlb_range (task->mm, beg, end);
-	up (&task->mm->mmap_sem);
+	up_write (&task->mm->mmap_sem);
 }
 
 void *vmalloc_uncached (unsigned long size)
diff -u --recursive --new-file v2.4.2/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c
--- v2.4.2/linux/arch/mips/sgi/kernel/indy_sc.c	Sat May 13 08:29:14 2000
+++ linux/arch/mips/sgi/kernel/indy_sc.c	Tue Mar  6 19:44:36 2001
@@ -1,6 +1,6 @@
 /* $Id: indy_sc.c,v 1.14 2000/03/25 22:35:07 ralf Exp $
  *
- * indy_sc.c: Indy cache managment functions.
+ * indy_sc.c: Indy cache management functions.
  *
  * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org),
  * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
diff -u --recursive --new-file v2.4.2/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c
--- v2.4.2/linux/arch/mips/sgi/kernel/setup.c	Wed Aug  9 13:46:02 2000
+++ linux/arch/mips/sgi/kernel/setup.c	Tue Mar  6 19:44:36 2001
@@ -165,7 +165,7 @@
         *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST);
 
         /* Return the difference, this is how far the r4k counter increments
-         * for every 1/HZ seconds. We round off the the nearest 1 MHz of
+         * for every 1/HZ seconds. We round off the nearest 1 MHz of
 	 * master clock (= 1000000 / 100 / 2 = 5000 count).
          */
         return ((ct1 - ct0) / 5000) * 5000;
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/defconfig linux/arch/mips64/defconfig
--- v2.4.2/linux/arch/mips64/defconfig	Wed Feb 21 18:20:13 2001
+++ linux/arch/mips64/defconfig	Sun Mar  4 14:30:18 2001
@@ -165,6 +165,7 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/kernel/linux32.c linux/arch/mips64/kernel/linux32.c
--- v2.4.2/linux/arch/mips64/kernel/linux32.c	Sat Feb  3 19:51:22 2001
+++ linux/arch/mips64/kernel/linux32.c	Mon Mar 19 12:35:10 2001
@@ -443,10 +443,10 @@
 	 *  `execve' frees all current memory we only have to do an
 	 *  `munmap' if the `execve' failes.
 	 */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	av = (char **) do_mmap_pgoff(0, 0, len, PROT_READ | PROT_WRITE,
 				     MAP_PRIVATE | MAP_ANONYMOUS, 0);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (IS_ERR(av))
 		return (long) av;
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/kernel/mips64_ksyms.c linux/arch/mips64/kernel/mips64_ksyms.c
--- v2.4.2/linux/arch/mips64/kernel/mips64_ksyms.c	Thu Jul 27 18:36:54 2000
+++ linux/arch/mips64/kernel/mips64_ksyms.c	Fri Mar  2 11:15:47 2001
@@ -121,3 +121,4 @@
 #endif
 
 EXPORT_SYMBOL(get_wchan);
+EXPORT_SYMBOL(flush_tlb_page);
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/kernel/syscall.c linux/arch/mips64/kernel/syscall.c
--- v2.4.2/linux/arch/mips64/kernel/syscall.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/kernel/syscall.c	Mon Mar 19 12:35:10 2001
@@ -64,9 +64,9 @@
 	}
         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
         error = do_mmap(file, addr, len, prot, flags, offset);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
         if (file)
                 fput(file);
 out:
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c
--- v2.4.2/linux/arch/mips64/mm/fault.c	Tue Nov 28 21:42:04 2000
+++ linux/arch/mips64/mm/fault.c	Mon Mar 19 12:35:10 2001
@@ -61,7 +61,7 @@
 
 /*
  * Unlock any spinlocks which will prevent us from getting the
- * message out (timerlist_lock is aquired through the
+ * message out (timerlist_lock is acquired through the
  * console unblank code)
  */
 void bust_spinlocks(void)
@@ -95,7 +95,7 @@
 	printk("Cpu%d[%s:%d:%08lx:%ld:%08lx]\n", smp_processor_id(), current->comm,
 		current->pid, address, write, regs->cp0_epc);
 #endif
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -138,7 +138,7 @@
 		goto out_of_memory;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
@@ -146,7 +146,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Quickly check for vmalloc range faults.
@@ -209,14 +209,14 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c
--- v2.4.2/linux/arch/mips64/mm/umap.c	Mon Aug  7 21:02:27 2000
+++ linux/arch/mips64/mm/umap.c	Mon Mar 19 12:35:10 2001
@@ -89,7 +89,7 @@
 	unsigned long beg = start;
 	pgd_t *dir;
 
-	down (&task->mm->mmap_sem);
+	down_write (&task->mm->mmap_sem);
 	dir = pgd_offset (task->mm, start);
 	flush_cache_range (task->mm, beg, end);
 	while (start < end){
@@ -98,7 +98,7 @@
 		dir++;
 	}
 	flush_tlb_range (task->mm, beg, end);
-	up (&task->mm->mmap_sem);
+	up_write (&task->mm->mmap_sem);
 }
 
 void *vmalloc_uncached (unsigned long size)
diff -u --recursive --new-file v2.4.2/linux/arch/mips64/sgi-ip22/ip22-sc.c linux/arch/mips64/sgi-ip22/ip22-sc.c
--- v2.4.2/linux/arch/mips64/sgi-ip22/ip22-sc.c	Sat May 13 08:30:17 2000
+++ linux/arch/mips64/sgi-ip22/ip22-sc.c	Tue Mar  6 19:44:36 2001
@@ -1,6 +1,6 @@
 /* $Id: ip22-sc.c,v 1.2 1999/12/04 03:59:01 ralf Exp $
  *
- * indy_sc.c: Indy cache managment functions.
+ * indy_sc.c: Indy cache management functions.
  *
  * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org),
  * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
diff -u --recursive --new-file v2.4.2/linux/arch/parisc/kernel/sys_parisc.c linux/arch/parisc/kernel/sys_parisc.c
--- v2.4.2/linux/arch/parisc/kernel/sys_parisc.c	Tue Dec  5 12:29:39 2000
+++ linux/arch/parisc/kernel/sys_parisc.c	Mon Mar 19 12:35:11 2001
@@ -51,7 +51,7 @@
 	struct file * file = NULL;
 	int error;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		error = -EBADF;
@@ -65,7 +65,7 @@
 		fput(file);
 out:
 	unlock_kernel();
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return error;
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/parisc/mm/fault.c linux/arch/parisc/mm/fault.c
--- v2.4.2/linux/arch/parisc/mm/fault.c	Tue Dec  5 12:29:39 2000
+++ linux/arch/parisc/mm/fault.c	Mon Mar 19 12:37:16 2001
@@ -175,7 +175,7 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = pa_find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -218,14 +218,14 @@
 	      default:
 		goto out_of_memory;
 	}
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
  * Something tried to access memory that isn't in our memory map..
  */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
 		struct siginfo si;
@@ -275,7 +275,7 @@
 	parisc_terminate("Bad Address (null pointer deref?)",regs,code,address);
 
   out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/Config.in linux/arch/ppc/8xx_io/Config.in
--- v2.4.2/linux/arch/ppc/8xx_io/Config.in	Thu Jul 13 09:42:50 2000
+++ linux/arch/ppc/8xx_io/Config.in	Sat Mar  3 10:52:13 2001
@@ -7,24 +7,24 @@
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   bool 'CPM SCC Ethernet' CONFIG_SCC_ENET
   if [ "$CONFIG_SCC_ENET" = "y" ]; then
-  bool 'Ethernet on SCC1' CONFIG_SCC1_ENET
-    if [ "$CONFIG_SCC1_ENET" != "y" ]; then
-      bool 'Ethernet on SCC2' CONFIG_SCC2_ENET
-    fi
+    choice 'SCC used for Ethernet'	\
+  	"SCC1	CONFIG_SCC1_ENET	\
+	 SCC2	CONFIG_SCC2_ENET	\
+	 SCC3	CONFIG_SCC3_ENET"	SCC1
   fi
   bool '860T FEC Ethernet' CONFIG_FEC_ENET
+  if [ "$CONFIG_FEC_ENET" = "y" ]; then
+    bool 'Use MDIO for PHY configuration' CONFIG_USE_MDIO
+  fi
   bool 'Use Big CPM Ethernet Buffers' CONFIG_ENET_BIG_BUFFERS
 fi
 bool 'Use SMC2 for UART' CONFIG_8xxSMC2
 if [ "$CONFIG_8xxSMC2" = "y" ]; then
   bool 'Use Alternate SMC2 I/O (823/850)' CONFIG_8xx_ALTSMC2
+  bool 'Use SMC2 for Console' CONFIG_8xx_CONS_SMC2
 fi
 bool 'Enable SCC2 and SCC3 for UART' CONFIG_8xxSCC
 
-if [ "$CONFIG_TQM860" = "y" -o "$CONFIG_TQM860L" = "y" -o "$CONFIG_TQM8xxL" = "y" ]; then
-  bool 'Use SMC2 for Console' TQM_SMC2_CONSOLE
-fi
-
 # This doesn't really belong here, but it is convenient to ask
 # 8xx specific questions.
 
@@ -32,4 +32,7 @@
 bool 'Copy-Back Data Cache (else Writethrough)' CONFIG_8xx_COPYBACK
 bool 'CPU6 Silicon Errata (860 Pre Rev. C)' CONFIG_8xx_CPU6
 
+if [ "$CONFIG_IDE" = "y" ]; then
+	bool 'MPC8xx direct IDE support on PCMCIA port' CONFIG_BLK_DEV_MPC8xx_IDE
+fi
 endmenu
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/commproc.c linux/arch/ppc/8xx_io/commproc.c
--- v2.4.2/linux/arch/ppc/8xx_io/commproc.c	Sat Nov 11 18:14:38 2000
+++ linux/arch/ppc/8xx_io/commproc.c	Sat Mar  3 10:52:13 2001
@@ -61,22 +61,6 @@
 	imp = (immap_t *)IMAP_ADDR;
 	commproc = (cpm8xx_t *)&imp->im_cpm;
 
-#ifdef notdef
-	/* We can't do this.  It seems to blow away the microcode
-	 * patch that EPPC-Bug loaded for us.  EPPC-Bug uses SCC1 for
-	 * Ethernet, SMC1 for the console, and I2C for serial EEPROM.
-	 * Our own drivers quickly reset all of these.
-	 */
-
-	/* Perform a reset.
-	*/
-	commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
-
-	/* Wait for it.
-	*/
-	while (commproc->cp_cpcr & CPM_CR_FLG);
-#endif
-
 	/* Set SDMA Bus Request priority 5.
 	 * On 860T, this also enables FEC priority 6.  I am not sure
 	 * this is what we realy want for some applications, but the
@@ -168,6 +152,14 @@
 void
 cpm_install_handler(int vec, void (*handler)(void *), void *dev_id)
 {
+
+	/* If null handler, assume we are trying to free the IRQ.
+	*/
+	if (!handler) {
+		cpm_free_handler(vec);
+		return;
+	}
+
 	if (cpm_vecs[vec].handler != 0)
 		printk("CPM interrupt %x replacing %x\n",
 			(uint)handler, (uint)cpm_vecs[vec].handler);
@@ -226,8 +218,9 @@
  * The internal baud rate clock is the system clock divided by 16.
  * This assumes the baudrate is 16x oversampled by the uart.
  */
-#define BRG_INT_CLK	(((bd_t *)__res)->bi_intfreq * 1000000)
-#define BRG_UART_CLK	(BRG_INT_CLK/16)
+#define BRG_INT_CLK		(((bd_t *)__res)->bi_intfreq * 1000000)
+#define BRG_UART_CLK		(BRG_INT_CLK/16)
+#define BRG_UART_CLK_DIV16	(BRG_UART_CLK/16)
 
 void
 m8xx_cpm_setbrg(uint brg, uint rate)
@@ -238,6 +231,12 @@
 	*/
 	bp = (uint *)&cpmp->cp_brgc1;
 	bp += brg;
-	*bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
+	/* The BRG has a 12-bit counter.  For really slow baud rates (or
+	 * really fast processors), we may have to further divide by 16.
+	 */
+	if (((BRG_UART_CLK / rate) - 1) < 4096)
+		*bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
+	else
+		*bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
+						CPM_BRG_EN | CPM_BRG_DIV16;
 }
-
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h
--- v2.4.2/linux/arch/ppc/8xx_io/commproc.h	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/8xx_io/commproc.h	Sat Mar  3 10:52:13 2001
@@ -324,7 +324,7 @@
 */
 #define SCC_EB	((u_char)0x10)	/* Set big endian byte order */
 
-/* CPM Ethernet through SCC1.
+/* CPM Ethernet through SCCx.
  */
 typedef struct scc_enet {
 	sccp_t	sen_genscc;
@@ -379,6 +379,8 @@
 	ushort	sen_taddrl;	/* temp address (LSB) */
 } scc_enet_t;
 
+/***  MBX  ************************************************************/
+
 #ifdef CONFIG_MBX
 /* Bits in parallel I/O port registers that have to be set/cleared
  * to configure the pins for SCC1 use.  The TCLK and RCLK seem unique
@@ -399,7 +401,9 @@
  */
 #define SICR_ENET_MASK	((uint)0x000000ff)
 #define SICR_ENET_CLKRT	((uint)0x0000003d)
-#endif
+#endif	/* CONFIG_MBX */
+
+/***  RPXLITE  ********************************************************/
 
 #ifdef CONFIG_RPXLITE
 /* This ENET stuff is for the MPC850 with ethernet on SCC2.  Some of
@@ -416,7 +420,9 @@
 
 #define SICR_ENET_MASK	((uint)0x0000ff00)
 #define SICR_ENET_CLKRT	((uint)0x00003d00)
-#endif
+#endif	/* CONFIG_RPXLITE */
+
+/***  BSEIP  **********************************************************/
 
 #ifdef CONFIG_BSEIP
 /* This ENET stuff is for the MPC823 with ethernet on SCC2.
@@ -438,7 +444,9 @@
 
 #define SICR_ENET_MASK	((uint)0x0000ff00)
 #define SICR_ENET_CLKRT	((uint)0x00002c00)
-#endif
+#endif	/* CONFIG_BSEIP */
+
+/***  RPXCLASSIC  *****************************************************/
 
 #ifdef CONFIG_RPXCLASSIC
 /* Bits in parallel I/O port registers that have to be set/cleared
@@ -457,27 +465,63 @@
  */
 #define SICR_ENET_MASK	((uint)0x000000ff)
 #define SICR_ENET_CLKRT	((uint)0x0000003d)
-#endif
+#endif	/* CONFIG_RPXCLASSIC */
+
+/***  TQM823L, TQM850L  ***********************************************/
+
+#if defined(CONFIG_TQM823L) || defined(CONFIG_TQM850L)
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
+#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PB_ENET_TENA	((uint)0x00002000)	/* PB 18 */
+
+#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
+#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00002600)
+#endif	/* CONFIG_TQM823L, CONFIG_TQM850L */
+
+/***  FPS850L  *********************************************************/
+
+#ifdef CONFIG_FPS850L
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
+#define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
+#define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PC_ENET_TENA	((ushort)0x0002)	/* PC 14 */
+#define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
+#define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
 
-#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM860L))
-/*
- * TQM860 and TQM860L Configuration:
- *
- * Signal       PAR     DIR     ODR     DAT     Function
- * Port A,  5    1       0       -       -       TCLK (CLK3) for Ethernet
- * Port A,  7    1       0       -       -       RCLK (CLK1) for Ethernet
- * Port A, 14    1       0       -       -       TXD for Ethernet (SCC1)
- * Port A, 15    1       0       -       -       RXD for Ethernet (SCC1)
- * Port C,  7    0       0       0       -       -> ETH-LOOP
- * Port C, 10    0       0       1       -       CD  for Ethernet (SCC1)
- * Port C, 11    0       0       1       -       CTS for Ethernet (SCC1)
- * Port C, 15    *       *       0       -       TENA/RTS for Ethernet
+/* Control bits in the SICR to route TCLK (CLK2) and RCLK (CLK4) to
+ * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
  */
+#define SICR_ENET_MASK	((uint)0x0000ff00)
+#define SICR_ENET_CLKRT	((uint)0x00002600)
+#endif	/* CONFIG_FPS850L */
+
+/***  TQM860L  ********************************************************/
 
+#ifdef CONFIG_TQM860L
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ */
 #define PA_ENET_RXD	((ushort)0x0001)	/* PA 15 */
 #define PA_ENET_TXD	((ushort)0x0002)	/* PA 14 */
-#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
 #define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
 
 #define PC_ENET_TENA	((ushort)0x0001)	/* PC 15 */
 #define PC_ENET_CLSN	((ushort)0x0010)	/* PC 11 */
@@ -488,51 +532,59 @@
  */
 #define SICR_ENET_MASK	((uint)0x000000ff)
 #define SICR_ENET_CLKRT	((uint)0x00000026)
+#endif	/* CONFIG_TQM860L */
 
-#endif	/* CONFIG_TQM860, TQM860L */
+/***  SPD823TS  *******************************************************/
 
-#ifdef CONFIG_TQM8xxL
-/*
- * TQM8xxL Configuration (except TQM860L):
- *
- * Signal       PAR     DIR     ODR     DAT     Function
- * Port A,  5    1       0       -       -       TCLK (CLK3) for Ethernet
- * Port A,  7    1       0       -       -       RCLK (CLK1) for Ethernet
- * Port A, 12    1       0       -       -       TXD for Ethernet (SCC2)
- * Port A, 13    1       0       -       -       RXD for Ethernet (SCC2)
- * Port B, 18    1       1       -       -       TENA/RTS for Ethernet on STK8xx
- * Port C,  7    0       0       0       -       -> ETH-LOOP
- * Port C,  8    0       0       1       -       CD  for Ethernet (SCC2)
- * Port C,  9    0       0       1       -       CTS for Ethernet (SCC2)
- * Port C, 14    *       *       0       -       TENA/RTS for Ethernet on FPS850
- *
- * Note: Using PC14 as RTS2 (TENA) does not work on the TQM850L when
- * used with the starter-kit mainboard; we *must* use PB18 instead.
- * For the FPS850 system, we *must* use PC14 :-(
+#ifdef CONFIG_SPD823TS
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC2 use.
  */
-
+#define PA_ENET_MDC	((ushort)0x0001)	/* PA 15 !!! */
+#define PA_ENET_MDIO	((ushort)0x0002)	/* PA 14 !!! */
 #define PA_ENET_RXD	((ushort)0x0004)	/* PA 13 */
 #define PA_ENET_TXD	((ushort)0x0008)	/* PA 12 */
-#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_RCLK	((ushort)0x0200)	/* PA  6 */
 #define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
 
-#ifndef	CONFIG_FPS850	/* not valid on FPS board */
-#define	PB_ENET_TENA	((uint)0x00002000)
-#endif	/* !CONFIG_FPS850 */
+#define PB_ENET_TENA	((uint)0x00002000)	/* PB 18 */
 
-#ifdef	CONFIG_FPS850	/* FPS uses default configuration */
-#define PC_ENET_TENA	((ushort)0x0002)	/* PC 14 */
-#endif	/* CONFIG_FPS850 */
 #define PC_ENET_CLSN	((ushort)0x0040)	/* PC  9 */
 #define PC_ENET_RENA	((ushort)0x0080)	/* PC  8 */
+#define	PC_ENET_RESET	((ushort)0x0100)	/* PC  7 !!! */
 
-/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK2) to
  * SCC2.  Also, make sure GR2 (bit 16) and SC2 (bit 17) are zero.
  */
 #define SICR_ENET_MASK	((uint)0x0000ff00)
-#define SICR_ENET_CLKRT	((uint)0x00002600)
+#define SICR_ENET_CLKRT	((uint)0x00002E00)
+#endif	/* CONFIG_SPD823TS */
+
+
+/***  SM850  *********************************************************/
 
-#endif	/* CONFIG_TQM8xxL */
+/* The SM850 Service Module uses SCC2 for IrDA and SCC3 for Ethernet */
+
+#ifdef CONFIG_SM850
+#define PB_ENET_RXD	((uint)0x00000004)	/* PB 29 */
+#define PB_ENET_TXD	((uint)0x00000002)	/* PB 30 */
+#define PA_ENET_RCLK	((ushort)0x0100)	/* PA  7 */
+#define PA_ENET_TCLK	((ushort)0x0400)	/* PA  5 */
+
+#define PC_ENET_LBK	((ushort)0x0008)	/* PC 12 */
+#define PC_ENET_TENA	((ushort)0x0004)	/* PC 13 */
+
+#define PC_ENET_RENA	((ushort)0x0800)	/* PC  4 */
+#define PC_ENET_CLSN	((ushort)0x0400)	/* PC  5 */
+
+/* Control bits in the SICR to route TCLK (CLK3) and RCLK (CLK1) to
+ * SCC3.  Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero.
+ */
+#define SICR_ENET_MASK	((uint)0x00FF0000)
+#define SICR_ENET_CLKRT	((uint)0x00260000)
+#endif	/* CONFIG_SM850 */
+
+/*********************************************************************/
 
 /* SCC Event register as used by Ethernet.
 */
@@ -723,8 +775,6 @@
 #define	CPMVEC_PIO_PC4		((ushort)0x01)
 #define	CPMVEC_ERROR		((ushort)0x00)
 
-extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
-
 /* CPM interrupt configuration vector.
 */
 #define	CICR_SCD_SCC4		((uint)0x00c00000)	/* SCC4 @ SCCd */
@@ -735,4 +785,8 @@
 #define CICR_HP_MASK		((uint)0x00001f00)	/* Hi-pri int. */
 #define CICR_IEN		((uint)0x00000080)	/* Int. enable */
 #define CICR_SPS		((uint)0x00000001)	/* SCC Spread */
+
+extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
+extern void cpm_free_handler(int vec);
+
 #endif /* __CPM_8XX__ */
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
--- v2.4.2/linux/arch/ppc/8xx_io/enet.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/8xx_io/enet.c	Sat Mar  3 10:52:13 2001
@@ -154,20 +154,26 @@
 /*static	ushort	my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/
 
 /* Typically, 860(T) boards use SCC1 for Ethernet, and other 8xx boards
- * use SCC2.  This is easily extended if necessary.
+ * use SCC2. Some even may use SCC3.
+ * This is easily extended if necessary.
  */
-#ifdef CONFIG_SCC2_ENET
+#if defined(CONFIG_SCC3_ENET)
+#define CPM_CR_ENET	CPM_CR_CH_SCC3
+#define PROFF_ENET	PROFF_SCC3
+#define SCC_ENET	2		/* Index, not number! */
+#define CPMVEC_ENET	CPMVEC_SCC3
+#elif defined(CONFIG_SCC2_ENET)
 #define CPM_CR_ENET	CPM_CR_CH_SCC2
 #define PROFF_ENET	PROFF_SCC2
 #define SCC_ENET	1		/* Index, not number! */
 #define CPMVEC_ENET	CPMVEC_SCC2
-#endif
-
-#ifdef CONFIG_SCC1_ENET
-#define CPM_CR_ENET CPM_CR_CH_SCC1
+#elif defined(CONFIG_SCC1_ENET)
+#define CPM_CR_ENET	CPM_CR_CH_SCC1
 #define PROFF_ENET	PROFF_SCC1
-#define SCC_ENET	0
+#define SCC_ENET	0		/* Index, not number! */
 #define CPMVEC_ENET	CPMVEC_SCC1
+#else
+#error CONFIG_SCCx_ENET not defined
 #endif
 
 static int
@@ -642,10 +648,11 @@
 	volatile	scc_t		*sccp;
 	volatile	scc_enet_t	*ep;
 	volatile	immap_t		*immap;
+	extern unsigned long _get_IMMR(void);
 
 	cp = cpmp;	/* Get pointer to Communication Processor */
 
-	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
+	immap = (immap_t *)(_get_IMMR() & 0xFFFF0000);	/* and to internal registers */
 
 	bd = (bd_t *)__res;
 
@@ -683,28 +690,47 @@
 	 * It can't last though......
 	 */
 
+#if (defined(PA_ENET_RXD) && defined(PA_ENET_TXD))
 	/* Configure port A pins for Txd and Rxd.
 	*/
-	immap->im_ioport.iop_papar |= (PA_ENET_RXD | PA_ENET_TXD);
+	immap->im_ioport.iop_papar |=  (PA_ENET_RXD | PA_ENET_TXD);
 	immap->im_ioport.iop_padir &= ~(PA_ENET_RXD | PA_ENET_TXD);
-	immap->im_ioport.iop_paodr &= ~PA_ENET_TXD;
+	immap->im_ioport.iop_paodr &=                ~PA_ENET_TXD;
+#elif (defined(PB_ENET_RXD) && defined(PB_ENET_TXD))
+	/* Configure port B pins for Txd and Rxd.
+	*/
+	immap->im_cpm.cp_pbpar |=  (PB_ENET_RXD | PB_ENET_TXD);
+	immap->im_cpm.cp_pbdir &= ~(PB_ENET_RXD | PB_ENET_TXD);
+	immap->im_cpm.cp_pbodr &=		 ~PB_ENET_TXD;
+#else
+#error Exactly ONE pair of PA_ENET_[RT]XD, PB_ENET_[RT]XD must be defined
+#endif
+
+#if defined(PC_ENET_LBK)
+	/* Configure port C pins to disable External Loopback
+	 */
+	immap->im_ioport.iop_pcpar &= ~PC_ENET_LBK;
+	immap->im_ioport.iop_pcdir |=  PC_ENET_LBK;
+	immap->im_ioport.iop_pcso  &= ~PC_ENET_LBK;
+	immap->im_ioport.iop_pcdat &= ~PC_ENET_LBK;	/* Disable Loopback */
+#endif	/* PC_ENET_LBK */
 
 	/* Configure port C pins to enable CLSN and RENA.
 	*/
 	immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
 	immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
-	immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
+	immap->im_ioport.iop_pcso  |=  (PC_ENET_CLSN | PC_ENET_RENA);
 
 	/* Configure port A for TCLK and RCLK.
 	*/
-	immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
+	immap->im_ioport.iop_papar |=  (PA_ENET_TCLK | PA_ENET_RCLK);
 	immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
 
 	/* Configure Serial Interface clock routing.
 	 * First, clear all SCC bits to zero, then set the ones we want.
 	 */
 	cp->cp_sicr &= ~SICR_ENET_MASK;
-	cp->cp_sicr |= SICR_ENET_CLKRT;
+	cp->cp_sicr |=  SICR_ENET_CLKRT;
 
 	/* Manual says set SDDR, but I can't find anything with that
 	 * name.  I think it is a misprint, and should be SDCR.  This
@@ -884,20 +910,17 @@
 	/* It is now OK to enable the Ethernet transmitter.
 	 * Unfortunately, there are board implementation differences here.
 	 */
-#if (defined(CONFIG_MBX) || defined(CONFIG_TQM860) || defined(CONFIG_TQM860L) || defined(CONFIG_FPS850))
-	immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
+#if   (!defined (PB_ENET_TENA) &&  defined (PC_ENET_TENA))
+	immap->im_ioport.iop_pcpar |=  PC_ENET_TENA;
 	immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
-#endif
-
-#if (defined(CONFIG_TQM8xxL) && !defined(CONFIG_FPS850))
+#elif ( defined (PB_ENET_TENA) && !defined (PC_ENET_TENA))
 	cp->cp_pbpar |= PB_ENET_TENA;
 	cp->cp_pbdir |= PB_ENET_TENA;
+#else
+#error Configuration Error: define exactly ONE of PB_ENET_TENA, PC_ENET_TENA
 #endif
 
 #if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
-	cp->cp_pbpar |= PB_ENET_TENA;
-	cp->cp_pbdir |= PB_ENET_TENA;
-
 	/* And while we are here, set the configuration to enable ethernet.
 	*/
 	*((volatile uint *)RPX_CSR_ADDR) &= ~BCSR0_ETHLPBK;
@@ -906,9 +929,6 @@
 #endif
 
 #ifdef CONFIG_BSEIP
-	cp->cp_pbpar |= PB_ENET_TENA;
-	cp->cp_pbdir |= PB_ENET_TENA;
-
 	/* BSE uses port B and C for PHY control.
 	*/
 	cp->cp_pbpar &= ~(PB_BSE_POWERUP | PB_BSE_FDXDIS);
@@ -941,11 +961,12 @@
 	*/
 	sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 
-	printk("%s: CPM ENET Version 0.2, ", dev->name);
+	printk("%s: CPM ENET Version 0.2 on SCC%d, ", dev->name, SCC_ENET+1);
 	for (i=0; i<5; i++)
 		printk("%02x:", dev->dev_addr[i]);
 	printk("%02x\n", dev->dev_addr[5]);
 
 	return 0;
 }
+
 
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c
--- v2.4.2/linux/arch/ppc/8xx_io/fec.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/8xx_io/fec.c	Sat Mar  3 10:52:13 2001
@@ -8,7 +8,9 @@
  * describes connections using the internal parallel port I/O, which
  * is basically all of Port D.
  *
- * Right now, I am very watseful with the buffers.  I allocate memory
+ * Includes support for the following PHYs: QS6612, LXT970, LXT971/2.
+ *
+ * Right now, I am very wasteful with the buffers.  I allocate memory
  * pages and then divide them into 2K frame buffers.  This way I know I
  * have buffers large enough to hold one frame within one buffer descriptor.
  * Once I get this working, I will use 64 or 128 byte CPM buffers, which
@@ -18,13 +20,16 @@
  * Much better multiple PHY support by Magnus Damm.
  * Copyright (c) 2000 Ericsson Radio Systems AB.
  *
+ * Make use of MII for PHY control configurable.
+ * Some fixes.
+ * Copyright (c) 2000 Wolfgang Denk, DENX Software Engineering.
  */
 
 /* List of PHYs we wish to support.
 */
-#define CONFIG_FEC_LXT970
-#define CONFIG_FEC_LXT971
-#define CONFIG_FEC_QS6612
+#undef	CONFIG_FEC_LXT970
+#define	CONFIG_FEC_LXT971
+#undef	CONFIG_FEC_QS6612
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -54,6 +59,7 @@
 #include <asm/uaccess.h>
 #include "commproc.h"
 
+#ifdef	CONFIG_USE_MDIO
 /* Forward declarations of some structures to support different PHYs
 */
 
@@ -71,6 +77,7 @@
 	const phy_cmd_t *ack_int;
 	const phy_cmd_t *shutdown;
 } phy_info_t;
+#endif	/* CONFIG_USE_MDIO */
 
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it is best
@@ -78,20 +85,20 @@
  * We don't need to allocate pages for the transmitter.  We just use
  * the skbuffer directly.
  */
-#if 1
-#define FEC_ENET_RX_PAGES	4
+#ifdef CONFIG_ENET_BIG_BUFFERS
+#define FEC_ENET_RX_PAGES	16
 #define FEC_ENET_RX_FRSIZE	2048
 #define FEC_ENET_RX_FRPPG	(PAGE_SIZE / FEC_ENET_RX_FRSIZE)
 #define RX_RING_SIZE		(FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
-#define TX_RING_SIZE		8	/* Must be power of two */
-#define TX_RING_MOD_MASK	7	/*   for this to work */
+#define TX_RING_SIZE		16	/* Must be power of two */
+#define TX_RING_MOD_MASK	15	/*   for this to work */
 #else
-#define FEC_ENET_RX_PAGES	16
+#define FEC_ENET_RX_PAGES	4
 #define FEC_ENET_RX_FRSIZE	2048
 #define FEC_ENET_RX_FRPPG	(PAGE_SIZE / FEC_ENET_RX_FRSIZE)
 #define RX_RING_SIZE		(FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
-#define TX_RING_SIZE		16	/* Must be power of two */
-#define TX_RING_MOD_MASK	15	/*   for this to work */
+#define TX_RING_SIZE		8	/* Must be power of two */
+#define TX_RING_MOD_MASK	7	/*   for this to work */
 #endif
 
 /* Interrupt events/masks.
@@ -107,6 +114,26 @@
 #define FEC_ENET_MII	((uint)0x00800000)	/* MII interrupt */
 #define FEC_ENET_EBERR	((uint)0x00400000)	/* SDMA bus error */
 
+/*
+*/
+#define FEC_ECNTRL_PINMUX	0x00000004
+#define FEC_ECNTRL_ETHER_EN	0x00000002
+#define FEC_ECNTRL_RESET	0x00000001
+
+#define FEC_RCNTRL_BC_REJ	0x00000010
+#define FEC_RCNTRL_PROM		0x00000008
+#define FEC_RCNTRL_MII_MODE	0x00000004
+#define FEC_RCNTRL_DRT		0x00000002
+#define FEC_RCNTRL_LOOP		0x00000001
+
+#define FEC_TCNTRL_FDEN		0x00000004
+#define FEC_TCNTRL_HBC		0x00000002
+#define FEC_TCNTRL_GTS		0x00000001
+
+/* Delay to wait for FEC reset command to complete (in us)
+*/
+#define FEC_RESET_DELAY		50
+
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE		1518
@@ -138,6 +165,7 @@
 	uint	tx_full;
 	spinlock_t lock;
 
+#ifdef	CONFIG_USE_MDIO
 	uint	phy_id;
 	uint	phy_id_done;
 	uint	phy_status;
@@ -148,6 +176,7 @@
 	uint	sequence_done;
 
 	uint	phy_addr;
+#endif	/* CONFIG_USE_MDIO */
 
 	int	link;
 	int	old_link;
@@ -165,7 +194,9 @@
 
 static int fec_enet_open(struct net_device *dev);
 static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+#ifdef	CONFIG_USE_MDIO
 static void fec_enet_mii(struct net_device *dev);
+#endif	/* CONFIG_USE_MDIO */
 static void fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
 #ifdef CONFIG_FEC_PACKETHOOK
 static void  fec_enet_tx(struct net_device *dev, __u32 regval);
@@ -181,6 +212,7 @@
 static void fec_stop(struct net_device *dev);
 static	ushort	my_enet_addr[3];
 
+#ifdef	CONFIG_USE_MDIO
 /* MII processing.  We keep this as simple as possible.  Requests are
  * placed on the list (if there is room).  When the request is finished
  * by the MII, an optional function may be called.
@@ -197,7 +229,7 @@
 mii_list_t	*mii_head;
 mii_list_t	*mii_tail;
 
-static int	mii_queue(struct net_device *dev, int request, 
+static int	mii_queue(struct net_device *dev, int request,
 				void (*func)(uint, struct net_device *));
 
 /* Make MII read/write commands for the FEC.
@@ -206,11 +238,13 @@
 #define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
 						(VAL & 0xffff))
 #define mk_mii_end	0
+#endif	/* CONFIG_USE_MDIO */
 
 /* Transmitter timeout.
 */
 #define TX_TIMEOUT (2*HZ)
 
+#ifdef	CONFIG_USE_MDIO
 /* Register definitions for the PHY.
 */
 
@@ -218,7 +252,7 @@
 #define MII_REG_SR          1  /* Status Register                          */
 #define MII_REG_PHYIR1      2  /* PHY Identification Register 1            */
 #define MII_REG_PHYIR2      3  /* PHY Identification Register 2            */
-#define MII_REG_ANAR        4  /* A-N Advertisement Register               */ 
+#define MII_REG_ANAR        4  /* A-N Advertisement Register               */
 #define MII_REG_ANLPAR      5  /* A-N Link Partner Ability Register        */
 #define MII_REG_ANER        6  /* A-N Expansion Register                   */
 #define MII_REG_ANNPTR      7  /* A-N Next Page Transmit Register          */
@@ -230,18 +264,19 @@
 #define PHY_CONF_LOOP	0x0002  /* 1 loopback mode enabled */
 #define PHY_CONF_SPMASK	0x00f0  /* mask for speed */
 #define PHY_CONF_10HDX	0x0010  /* 10 Mbit half duplex supported */
-#define PHY_CONF_10FDX	0x0020  /* 10 Mbit full duplex supported */ 
+#define PHY_CONF_10FDX	0x0020  /* 10 Mbit full duplex supported */
 #define PHY_CONF_100HDX	0x0040  /* 100 Mbit half duplex supported */
-#define PHY_CONF_100FDX	0x0080  /* 100 Mbit full duplex supported */ 
+#define PHY_CONF_100FDX	0x0080  /* 100 Mbit full duplex supported */
 
 #define PHY_STAT_LINK	0x0100  /* 1 up - 0 down */
 #define PHY_STAT_FAULT	0x0200  /* 1 remote fault */
 #define PHY_STAT_ANC	0x0400  /* 1 auto-negotiation complete	*/
 #define PHY_STAT_SPMASK	0xf000  /* mask for speed */
 #define PHY_STAT_10HDX	0x1000  /* 10 Mbit half duplex selected	*/
-#define PHY_STAT_10FDX	0x2000  /* 10 Mbit full duplex selected	*/ 
+#define PHY_STAT_10FDX	0x2000  /* 10 Mbit full duplex selected	*/
 #define PHY_STAT_100HDX	0x4000  /* 100 Mbit half duplex selected */
-#define PHY_STAT_100FDX	0x8000  /* 100 Mbit full duplex selected */ 
+#define PHY_STAT_100FDX	0x8000  /* 100 Mbit full duplex selected */
+#endif	/* CONFIG_USE_MDIO */
 
 #ifdef CONFIG_FEC_PACKETHOOK
 int
@@ -291,7 +326,7 @@
 	fep->ph_proto = 0;
 	fep->ph_regaddr = NULL;
 	fep->ph_priv = NULL;
-	
+
 	fep->ph_lock = 0;
 
 	return retval;
@@ -345,7 +380,7 @@
 
 	fep->stats.tx_bytes += skb->len;
 	fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
-	
+
 	/* Push the data cache so the CPM does not get stale memory
 	 * data.
 	 */
@@ -404,7 +439,7 @@
 	bdp = fep->tx_bd_base;
 	printk(" tx: %u buffers\n",  TX_RING_SIZE);
 	for (i = 0 ; i < TX_RING_SIZE; i++) {
-		printk("  %08x: %04x %04x %08x\n", 
+		printk("  %08x: %04x %04x %08x\n",
 		       (uint) bdp,
 		       bdp->cbd_sc,
 		       bdp->cbd_datlen,
@@ -443,7 +478,6 @@
 
 	if (fep->ph_regaddr) regval = *fep->ph_regaddr;
 #endif
-
 	fecp = (volatile fec_t*)dev->base_addr;
 
 	/* Get the interrupt events that caused us to be here.
@@ -478,9 +512,13 @@
 		}
 
 		if (int_events & FEC_ENET_MII) {
+#ifdef	CONFIG_USE_MDIO
 			fec_enet_mii(dev);
+#else
+printk("%s[%d] %s: unexpected FEC_ENET_MII event\n", __FILE__,__LINE__,__FUNCTION__);
+#endif	/* CONFIG_USE_MDIO */
 		}
-	
+
 	}
 }
 
@@ -541,23 +579,23 @@
 		 */
 		if (bdp->cbd_sc & BD_ENET_TX_DEF)
 			fep->stats.collisions++;
-	    
+
 		/* Free the sk buffer associated with this last transmit.
 		 */
 #if 0
 printk("TXI: %x %x %x\n", bdp, skb, fep->skb_dirty);
 #endif
-		dev_kfree_skb(skb/*, FREE_WRITE*/);
+		dev_kfree_skb_irq (skb/*, FREE_WRITE*/);
 		fep->tx_skbuff[fep->skb_dirty] = NULL;
 		fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
-	    
+
 		/* Update pointer to next buffer descriptor to be transmitted.
 		 */
 		if (bdp->cbd_sc & BD_ENET_TX_WRAP)
 			bdp = fep->tx_bd_base;
 		else
 			bdp++;
-	    
+
 		/* Since we have freed up a buffer, the ring is no longer
 		 * full.
 		 */
@@ -617,7 +655,7 @@
 	/* Check for errors. */
 	if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
 			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
-		fep->stats.rx_errors++;       
+		fep->stats.rx_errors++;
 		if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
 		/* Frame too long or too short. */
 			fep->stats.rx_length_errors++;
@@ -703,7 +741,7 @@
 		bdp = fep->rx_bd_base;
 	else
 		bdp++;
-	
+
 #if 1
 	/* Doing this here will keep the FEC running while we process
 	 * incoming frames.  On a heavily loaded network, we should be
@@ -732,6 +770,7 @@
 }
 
 
+#ifdef	CONFIG_USE_MDIO
 static void
 fec_enet_mii(struct net_device *dev)
 {
@@ -743,7 +782,7 @@
 	fep = (struct fec_enet_private *)dev->priv;
 	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);
 	mii_reg = ep->fec_mii_data;
-	
+
 	if ((mip = mii_head) == NULL) {
 		printk("MII and no head!\n");
 		return;
@@ -756,8 +795,9 @@
 	mip->mii_next = mii_free;
 	mii_free = mip;
 
-	if ((mip = mii_head) != NULL)
+	if ((mip = mii_head) != NULL) {
 		ep->fec_mii_data = mip->mii_regval;
+	}
 }
 
 static int
@@ -786,13 +826,11 @@
 		if (mii_head) {
 			mii_tail->mii_next = mip;
 			mii_tail = mip;
-		}
-		else {
+		} else {
 			mii_head = mii_tail = mip;
 			(&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval;
 		}
-	}
-	else {
+	} else {
 		retval = 1;
 	}
 
@@ -808,7 +846,7 @@
 	if(!c)
 		return;
 
-	for(k = 0; (c+k)->mii_data != mk_mii_end; k++) 
+	for(k = 0; (c+k)->mii_data != mk_mii_end; k++)
 		mii_queue(dev, (c+k)->mii_data, (c+k)->funct);
 }
 
@@ -896,7 +934,7 @@
 }
 
 static phy_info_t phy_info_lxt970 = {
-	0x07810000, 
+	0x07810000,
 	"LXT970",
 
 	(const phy_cmd_t []) {  /* config */
@@ -919,12 +957,12 @@
 	},
 	(const phy_cmd_t []) { /* ack_int */
 		/* read SR and ISR to acknowledge */
-		
+
 		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
 		{ mk_mii_read(MII_LXT970_ISR), NULL },
 
 		/* find out the current status */
-		
+
 		{ mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr },
 		{ mk_mii_end, }
 	},
@@ -933,7 +971,7 @@
 		{ mk_mii_end, }
 	},
 };
-	
+
 #endif /* CONFIG_FEC_LXT970 */
 
 /* ------------------------------------------------------------------------- */
@@ -950,7 +988,7 @@
 #define MII_LXT971_LCR       20  /* LED Control Register      */
 #define MII_LXT971_TCR       30  /* Transmit Control Register */
 
-/* 
+/*
  * I had some nice ideas of running the MDIO faster...
  * The 971 should support 8MHz and I tried it, but things acted really
  * weird, so 2.5 MHz ought to be enough for anyone...
@@ -980,14 +1018,11 @@
 }
 
 static phy_info_t phy_info_lxt971 = {
-	0x0001378e, 
+	0x0001378e,
 	"LXT971",
-	
-	(const phy_cmd_t []) {  /* config */  
-		/* limit to 10MBit because my protorype board 
-		 * doesn't work with 100. */
 
-		{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */
+	(const phy_cmd_t []) {  /* config */
+//		{ mk_mii_write(MII_REG_ANAR, 0x021), NULL }, /* 10  Mbps, HD */
 		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
 		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
 		{ mk_mii_end, }
@@ -995,12 +1030,12 @@
 	(const phy_cmd_t []) {  /* startup - enable interrupts */
 		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
 		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-	
+
 		/* Somehow does the 971 tell me that the link is down
 		 * the first read after power-up.
 		 * read here to get a valid value in ack_int */
 
-		{ mk_mii_read(MII_REG_SR), mii_parse_sr }, 
+		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
@@ -1008,9 +1043,9 @@
 
 		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
 		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
-		
+
 		/* we only need to read ISR to acknowledge */
-		
+
 		{ mk_mii_read(MII_LXT971_ISR), NULL },
 		{ mk_mii_end, }
 	},
@@ -1053,13 +1088,13 @@
 }
 
 static phy_info_t phy_info_qs6612 = {
-	0x00181440, 
+	0x00181440,
 	"QS6612",
-	
-	(const phy_cmd_t []) {  /* config */  
-//	{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10 MBit */
 
-		/* The PHY powers up isolated on the RPX, 
+	(const phy_cmd_t []) {  /* config */
+//	{ mk_mii_write(MII_REG_ANAR, 0x061), NULL }, /* 10  Mbps */
+
+		/* The PHY powers up isolated on the RPX,
 		 * so send a command to allow operation.
 		 */
 
@@ -1077,9 +1112,9 @@
 		{ mk_mii_end, }
 	},
 	(const phy_cmd_t []) { /* ack_int */
-		
+
 		/* we need to read ISR, SR and ANER to acknowledge */
-		
+
 		{ mk_mii_read(MII_QS6612_ISR), NULL },
 		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
 		{ mk_mii_read(MII_REG_ANER), NULL },
@@ -1134,10 +1169,10 @@
 		printk("link up");
 
 		switch(*s & PHY_STAT_SPMASK) {
-		case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;
-		case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;
-		case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;
-		case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break;
+		case PHY_STAT_100FDX: printk(", 100 Mbps Full Duplex"); break;
+		case PHY_STAT_100HDX: printk(", 100 Mbps Half Duplex"); break;
+		case PHY_STAT_10FDX: printk(", 10 Mbps Full Duplex"); break;
+		case PHY_STAT_10HDX: printk(", 10 Mbps Half Duplex"); break;
 		default:
 			printk(", Unknown speed/duplex");
 		}
@@ -1177,7 +1212,7 @@
 
 	if (*s & PHY_CONF_LOOP)
 		printk(", loopback enabled");
-	
+
 	printk(".\n");
 
 	fep->sequence_done = 1;
@@ -1194,7 +1229,7 @@
 
 	if (fep->link) {
 		duplex = 0;
-		if (fep->phy_status 
+		if (fep->phy_status
 		    & (PHY_STAT_100FDX | PHY_STAT_10FDX))
 			duplex = 1;
 		fec_restart(dev, duplex);
@@ -1245,18 +1280,20 @@
 
 	fep = dev->priv;
 	fep->phy_id |= (mii_reg & 0xffff);
-	printk("fec: Phy @ 0x%x, type 0x%08x\n", fep->phy_addr, fep->phy_id);
 
 	for(i = 0; phy_info[i]; i++)
 		if(phy_info[i]->id == (fep->phy_id >> 4))
 			break;
 
 	if(!phy_info[i])
-		panic("%s: PHY id 0x%08x is not supported!\n", 
+		panic("%s: PHY id 0x%08x is not supported!\n",
 		      dev->name, fep->phy_id);
-      
+
 	fep->phy = phy_info[i];
 	fep->phy_id_done = 1;
+
+	printk("%s: Phy @ 0x%x, type %s (0x%08x)\n",
+		dev->name, fep->phy_addr, fep->phy->name, fep->phy_id);
 }
 
 /* Scan all of the MII PHY addresses looking for someone to respond
@@ -1270,25 +1307,23 @@
 
 	fep = dev->priv;
 
-	if (fep->phy_addr < 32) {
-		if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
-			
-			/* Got first part of ID, now get remainder.
-			*/
-			fep->phy_id = phytype << 16;
-			mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
-							mii_discover_phy3);
-		}
-		else {
-			fep->phy_addr++;
+	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
+
+		/* Got first part of ID, now get remainder.
+		*/
+		fep->phy_id = phytype << 16;
+		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3);
+	} else {
+		fep->phy_addr++;
+		if (fep->phy_addr < 32) {
 			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
 							mii_discover_phy);
+		} else {
+			printk("fec: No PHY device found.\n");
 		}
 	}
-	else {
-		printk("FEC: No PHY device found.\n");
-	}
 }
+#endif	/* CONFIG_USE_MDIO */
 
 /* This interrupt occurs when the PHY detects a link change.
 */
@@ -1299,16 +1334,36 @@
 mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 #endif
 {
+#ifdef	CONFIG_USE_MDIO
 	struct	net_device *dev = dev_id;
 	struct fec_enet_private *fep = dev->priv;
+	volatile immap_t *immap = (immap_t *)IMAP_ADDR;
+	volatile fec_t *fecp = &(immap->im_cpm.cp_fec);
+	unsigned int ecntrl = fecp->fec_ecntrl;
+
+	/* We need the FEC enabled to access the MII
+	*/
+	if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) {
+		fecp->fec_ecntrl |= FEC_ECNTRL_ETHER_EN;
+	}
+#endif	/* CONFIG_USE_MDIO */
 
 #if 0
 	disable_irq(fep->mii_irq);  /* disable now, enable later */
 #endif
 
+
+#ifdef	CONFIG_USE_MDIO
 	mii_do_cmd(dev, fep->phy->ack_int);
 	mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
 
+	if ((ecntrl & FEC_ECNTRL_ETHER_EN) == 0) {
+		fecp->fec_ecntrl = ecntrl;	/* restore old settings */
+	}
+#else
+printk("%s[%d] %s: unexpected Link interrupt\n", __FILE__,__LINE__,__FUNCTION__);
+#endif	/* CONFIG_USE_MDIO */
+
 }
 
 static int
@@ -1320,6 +1375,7 @@
 	 * a simple way to do that.
 	 */
 
+#ifdef	CONFIG_USE_MDIO
 	fep->sequence_done = 0;
 	fep->link = 0;
 
@@ -1327,7 +1383,6 @@
 		mii_do_cmd(dev, fep->phy->ack_int);
 		mii_do_cmd(dev, fep->phy->config);
 		mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
-
 		while(!fep->sequence_done)
 			schedule();
 
@@ -1335,8 +1390,12 @@
 		netif_start_queue(dev);
 		return 0;		/* Success */
 	}
-
 	return -ENODEV;		/* No PHY we understand */
+#else
+	fep->link = 1;
+	netif_start_queue(dev);
+	return 0;	/* Success */
+#endif	/* CONFIG_USE_MDIO */
 
 }
 
@@ -1377,13 +1436,13 @@
 	ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec);
 
 	if (dev->flags&IFF_PROMISC) {
-	  
+
 		/* Log any net taps. */
 		printk("%s: Promiscuous mode enabled.\n", dev->name);
-		ep->fec_r_cntrl |= 0x0008;
+		ep->fec_r_cntrl |= FEC_RCNTRL_PROM;
 	} else {
 
-		ep->fec_r_cntrl &= ~0x0008;
+		ep->fec_r_cntrl &= ~FEC_RCNTRL_PROM;
 
 		if (dev->flags & IFF_ALLMULTI) {
 			/* Catch all multicast addresses, so set the
@@ -1404,7 +1463,7 @@
 			dmi = dev->mc_list;
 
 			for (i=0; i<dev->mc_count; i++) {
-				
+
 				/* Only support group multicast for now.
 				*/
 				if (!(dmi->dmi_addr[0] & 1))
@@ -1448,7 +1507,7 @@
 	volatile	fec_t	*fecp;
 	bd_t		*bd;
 	extern		uint	_get_IMMR(void);
-#ifdef CONFIG_RPXCLASSIC
+#ifdef CONFIG_SCC_ENET
 	unsigned char	tmpaddr[6];
 #endif
 
@@ -1472,8 +1531,15 @@
 
 	/* Whack a reset.  We should wait for this.
 	*/
-	fecp->fec_ecntrl = 1;
-	udelay(10);
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printk ("FEC Reset timeout!\n");
+	}
 
 	/* Set the Ethernet address.  If using multiple Enets on the 8xx,
 	 * this needs some work to get unique addresses.
@@ -1481,12 +1547,13 @@
 	eap = (unsigned char *)my_enet_addr;
 	iap = bd->bi_enetaddr;
 
-#ifdef CONFIG_RPXCLASSIC
-	/* The Embedded Planet boards have only one MAC address in
-	 * the EEPROM, but can have two Ethernet ports.  For the
-	 * FEC port, we create another address by setting one of
-	 * the address bits above something that would have (up to
-	 * now) been allocated.
+#ifdef CONFIG_SCC_ENET
+	/*
+         * If a board has Ethernet configured both on a SCC and the
+         * FEC, it needs (at least) 2 MAC addresses (we know that Sun
+         * disagrees, but anyway). For the FEC port, we create
+         * another address by setting one of the address bits above
+         * something that would have (up to now) been allocated.
 	 */
 	for (i=0; i<6; i++)
 		tmpaddr[i] = *iap++;
@@ -1494,8 +1561,9 @@
 	iap = tmpaddr;
 #endif
 
-	for (i=0; i<6; i++)
+	for (i=0; i<6; i++) {
 		dev->dev_addr[i] = *eap++ = *iap++;
+	}
 
 	/* Allocate memory for buffer descriptors.
 	*/
@@ -1518,9 +1586,6 @@
 	fep->rx_bd_base = cbd_base;
 	fep->tx_bd_base = cbd_base + RX_RING_SIZE;
 
-	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
-	fep->cur_rx = fep->rx_bd_base;
-
 	fep->skb_cur = fep->skb_dirty = 0;
 
 	/* Initialize the receive buffer descriptors.
@@ -1565,22 +1630,27 @@
 	*/
 	if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
 		panic("Could not allocate FEC IRQ!");
+
 #ifdef CONFIG_RPXCLASSIC
 	/* Make Port C, bit 15 an input that causes interrupts.
 	*/
 	immap->im_ioport.iop_pcpar &= ~0x0001;
 	immap->im_ioport.iop_pcdir &= ~0x0001;
-	immap->im_ioport.iop_pcso &= ~0x0001;
-	immap->im_ioport.iop_pcint |= 0x0001;
+	immap->im_ioport.iop_pcso  &= ~0x0001;
+	immap->im_ioport.iop_pcint |=  0x0001;
 	cpm_install_handler(CPMVEC_PIO_PC15, mii_link_interrupt, dev);
 
 	/* Make LEDS reflect Link status.
 	*/
 	*((uint *) RPX_CSR_ADDR) &= ~BCSR2_FETHLEDMODE;
 #endif
-#ifdef CONFIG_FADS
-	if (request_8xxirq(SIU_IRQ2, mii_link_interrupt, 0, "mii", dev) != 0)
+
+#ifdef PHY_INTERRUPT
+	if (request_8xxirq(PHY_INTERRUPT, mii_link_interrupt, 0, "mii", dev) != 0)
 		panic("Could not allocate MII IRQ!");
+
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+		(0x80000000 >> PHY_INTERRUPT);
 #endif
 
 	dev->base_addr = (unsigned long)fecp;
@@ -1595,9 +1665,11 @@
 	dev->get_stats = fec_enet_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
+#ifdef	CONFIG_USE_MDIO
 	for (i=0; i<NMII-1; i++)
 		mii_cmds[i].mii_next = &mii_cmds[i+1];
 	mii_free = mii_cmds;
+#endif	/* CONFIG_USE_MDIO */
 
 	/* Configure all of port D for MII.
 	*/
@@ -1609,23 +1681,46 @@
 		immap->im_ioport.iop_pddir = 0x1c58;	/* Pre rev. D */
 	else
 		immap->im_ioport.iop_pddir = 0x1fff;	/* Rev. D and later */
-	
+
+#ifdef	CONFIG_USE_MDIO
 	/* Set MII speed to 2.5 MHz
 	*/
-	fecp->fec_mii_speed = fep->phy_speed = 
-		((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;
+	fecp->fec_mii_speed = fep->phy_speed =
+		(
+		  ( ((bd->bi_intfreq * 1000000) + 500000) / 2500000 / 2 )
+		  & 0x3F
+		) << 1;
+#else
+	fecp->fec_mii_speed = 0;	/* turn off MDIO */
+#endif	/* CONFIG_USE_MDIO */
 
-	printk("%s: FEC ENET Version 0.2, ", dev->name);
-	for (i=0; i<5; i++)
-		printk("%02x:", dev->dev_addr[i]);
-	printk("%02x\n", dev->dev_addr[5]);
+	printk ("%s: FEC ENET Version 0.2, FEC irq %d"
+#ifdef PHY_INTERRUPT
+		", MII irq %d"
+#endif
+		", addr ",
+		dev->name, FEC_INTERRUPT
+#ifdef PHY_INTERRUPT
+		, PHY_INTERRUPT
+#endif
+	);
+	for (i=0; i<6; i++)
+		printk("%02x%c", dev->dev_addr[i], (i==5) ? '\n' : ':');
 
+#ifdef	CONFIG_USE_MDIO	/* start in full duplex mode, and negotiate speed */
+	fec_restart (dev, 1);
+#else			/* always use half duplex mode only */
+	fec_restart (dev, 0);
+#endif
+
+#ifdef	CONFIG_USE_MDIO
 	/* Queue up command to detect the PHY and initialize the
 	 * remainder of the interface.
 	 */
 	fep->phy_id_done = 0;
 	fep->phy_addr = 0;
 	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
+#endif	/* CONFIG_USE_MDIO */
 
 	return 0;
 }
@@ -1639,7 +1734,6 @@
 {
 	struct fec_enet_private *fep;
 	int i;
-	unsigned char	*eap;
 	volatile	cbd_t	*bdp;
 	volatile	immap_t	*immap;
 	volatile	fec_t	*fecp;
@@ -1652,33 +1746,25 @@
 
 	/* Whack a reset.  We should wait for this.
 	*/
-	fecp->fec_ecntrl = 1;
-	udelay(10);
-
-	/* Enable interrupts we wish to service.
-	*/
-	fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
-				FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
-
-	/* Clear any outstanding interrupt.
-	*/
-	fecp->fec_ievent = 0xffc0;
-
-	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
+	for (i = 0;
+	     (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printk ("FEC Reset timeout!\n");
+	}
 
 	/* Set station address.
 	*/
-	fecp->fec_addr_low = (my_enet_addr[0] << 16) | my_enet_addr[1];
-	fecp->fec_addr_high = my_enet_addr[2];
-
-	eap = (unsigned char *)&my_enet_addr[0];
-	for (i=0; i<6; i++)
-		dev->dev_addr[i] = *eap++;
+	fecp->fec_addr_low  = (my_enet_addr[0] << 16) | my_enet_addr[1];
+	fecp->fec_addr_high =  my_enet_addr[2];
 
 	/* Reset all multicast.
 	*/
 	fecp->fec_hash_table_high = 0;
-	fecp->fec_hash_table_low = 0;
+	fecp->fec_hash_table_low  = 0;
 
 	/* Set maximum receive buffer size.
 	*/
@@ -1739,12 +1825,12 @@
 	/* Enable MII mode.
 	*/
 	if (duplex) {
-		fecp->fec_r_cntrl = 0x04;	/* MII enable */
-		fecp->fec_x_cntrl = 0x04;	/* FD enable */
+		fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;	/* MII enable */
+		fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;		/* FD enable */
 	}
 	else {
-		fecp->fec_r_cntrl = 0x06;	/* MII enable|No Rcv on Xmit */
-		fecp->fec_x_cntrl = 0x00;
+		fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
+		fecp->fec_x_cntrl = 0;
 	}
 	fep->full_duplex = duplex;
 
@@ -1752,13 +1838,26 @@
 	*/
 	fecp->fec_fun_code = 0x78000000;
 
+#ifdef	CONFIG_USE_MDIO
 	/* Set MII speed.
 	*/
 	fecp->fec_mii_speed = fep->phy_speed;
+#endif	/* CONFIG_USE_MDIO */
+
+	/* Clear any outstanding interrupt.
+	*/
+	fecp->fec_ievent = 0xffc0;
+
+	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+
+	/* Enable interrupts we wish to service.
+	*/
+	fecp->fec_imask = ( FEC_ENET_TXF | FEC_ENET_TXB |
+			    FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII );
 
 	/* And last, enable the transmit and receive processing.
 	*/
-	fecp->fec_ecntrl = 6;
+	fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
 	fecp->fec_r_des_active = 0x01000000;
 }
 
@@ -1768,33 +1867,45 @@
 	volatile	immap_t	*immap;
 	volatile	fec_t	*fecp;
 	struct fec_enet_private *fep;
+	int i;
 
 	immap = (immap_t *)IMAP_ADDR;	/* pointer to internal registers */
-	
+
 	fecp = &(immap->im_cpm.cp_fec);
-	
+
+	if ((fecp->fec_ecntrl & FEC_ECNTRL_ETHER_EN) == 0)
+		return;	/* already down */
+
 	fep = dev->priv;
 
 
 	fecp->fec_x_cntrl = 0x01;	/* Graceful transmit stop */
 
-	while(!(fecp->fec_ievent & 0x10000000));
-
-	/* Whack a reset.  We should wait for this.
-	*/
-	fecp->fec_ecntrl = 1;
-	udelay(10);
+	for (i = 0;
+	     ((fecp->fec_ievent & 0x10000000) == 0) && (i < FEC_RESET_DELAY);
+	     ++i) {
+		udelay(1);
+	}
+	if (i == FEC_RESET_DELAY) {
+		printk ("FEC timeout on graceful transmit stop\n");
+	}
 
 	/* Clear outstanding MII command interrupts.
 	*/
 	fecp->fec_ievent = FEC_ENET_MII;
 
-	/* Enable MII command finihed interrupt 
+	/* Enable MII command finished interrupt
 	*/
 	fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
 	fecp->fec_imask = FEC_ENET_MII;
 
+#ifdef	CONFIG_USE_MDIO
 	/* Set MII speed.
 	*/
 	fecp->fec_mii_speed = fep->phy_speed;
+#endif	/* CONFIG_USE_MDIO */
+
+	/* Disable FEC
+	*/
+	fecp->fec_ecntrl &= ~(FEC_ECNTRL_ETHER_EN);
 }
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.4.2/linux/arch/ppc/8xx_io/uart.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/8xx_io/uart.c	Sat Mar  3 10:52:13 2001
@@ -53,10 +53,22 @@
 
 /* this defines the index into rs_table for the port to use
 */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT	0
-#endif
-#endif
+# ifndef CONFIG_SERIAL_CONSOLE_PORT
+#  ifdef CONFIG_SCC3_ENET
+#   ifdef CONFIG_8xx_CONS_SMC2
+#    define CONFIG_SERIAL_CONSOLE_PORT	0	/* Console on SMC2 is 1st port */
+#   else
+#    error "Can't use SMC1 for console with Ethernet on SCC3"
+#   endif
+#  else	/* ! CONFIG_SCC3_ENET */
+#   ifdef CONFIG_8xx_CONS_SMC2			/* Console on SMC2 */
+#    define CONFIG_SERIAL_CONSOLE_PORT	1
+#   else					/* Console on SMC1 */
+#    define CONFIG_SERIAL_CONSOLE_PORT	0
+#   endif /* CONFIG_8xx_CONS_SMC2 */
+#  endif  /* CONFIG_SCC3_ENET */
+# endif	  /* CONFIG_SERIAL_CONSOLE_PORT */
+#endif	  /* CONFIG_SERIAL_CONSOLE */
 
 #if 0
 /* SCC2 for console
@@ -118,14 +130,22 @@
  */
 static struct serial_state rs_table[] = {
 	/* UART CLK   PORT          IRQ      FLAGS  NUM   */
-	{ 0,     0, PROFF_SMC1, CPMVEC_SMC1,   0,    0 },    /* SMC1 ttyS0 */
-#ifdef CONFIG_8xxSMC2
-	{ 0,     0, PROFF_SMC2, CPMVEC_SMC2,   0,    1 },    /* SMC2 ttyS1 */
-#endif
-#ifdef CONFIG_8xxSCC
-	{ 0,     0, PROFF_SCC2, CPMVEC_SCC2,   0,    (NUM_IS_SCC | 1) },    /* SCC2 ttyS2 */
-	{ 0,     0, PROFF_SCC3, CPMVEC_SCC3,   0,    (NUM_IS_SCC | 2) },    /* SCC3 ttyS3 */
+#ifndef CONFIG_SCC3_ENET	/* SMC1 not usable with Ethernet on SCC3 */
+  	{ 0,     0, PROFF_SMC1, CPMVEC_SMC1,   0,    0 },    /* SMC1 ttyS0 */
 #endif
+#if !defined(CONFIG_USB_MPC8xx) && !defined(CONFIG_USB_CLIENT_MPC8xx)
+# ifdef CONFIG_8xxSMC2
+  	{ 0,     0, PROFF_SMC2, CPMVEC_SMC2,   0,    1 },    /* SMC2 ttyS1 */
+# endif
+# ifdef CONFIG_8xxSCC
+  	{ 0,     0, PROFF_SCC2, CPMVEC_SCC2,   0,    (NUM_IS_SCC | 1) },    /* SCC2 ttyS2 */
+  	{ 0,     0, PROFF_SCC3, CPMVEC_SCC3,   0,    (NUM_IS_SCC | 2) },    /* SCC3 ttyS3 */
+# endif
+  #else /* CONFIG_USB_xxx */
+# ifdef CONFIG_8xxSCC
+  	{ 0,     0, PROFF_SCC3, CPMVEC_SCC3,   0,    (NUM_IS_SCC | 2) },    /* SCC3 ttyS3 */
+# endif
+#endif	/* CONFIG_USB_xxx */
 };
 
 #define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
@@ -2733,10 +2753,10 @@
 				cp->cp_pbdir &= ~iobits;
 				cp->cp_pbodr &= ~iobits;
 #else
+				iobits = 0xc0;
 				if (idx == 0) {
 					/* SMC1 on Port B, like all 8xx.
 					*/
-					iobits = 0xc0;
 					cp->cp_pbpar |= iobits;
 					cp->cp_pbdir &= ~iobits;
 					cp->cp_pbodr &= ~iobits;
@@ -2744,7 +2764,6 @@
 				else {
 					/* SMC2 is on Port A.
 					*/
-					iobits = 0x300;
 					immap->im_ioport.iop_papar |= iobits;
 					immap->im_ioport.iop_padir &= ~iobits;
 					immap->im_ioport.iop_paodr &= ~iobits;
@@ -2836,6 +2855,9 @@
 	for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
 		if (bd->bi_baudrate == baud_table[bidx])
 			break;
+	/* make sure we have a useful value */
+	if (bidx == (sizeof(baud_table) / sizeof(int)))
+		bidx = 13;	/* B9600 */
 
 	co->cflag = CREAD|CLOCAL|bidx|CS8;
 	baud_idx = bidx;
@@ -2958,7 +2980,7 @@
 		*/
 		chan = smc_chan_map[idx];
 		cp->cp_cpcr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
-		printk("");
+		printk("%s", "");
 		while (cp->cp_cpcr & CPM_CR_FLG);
 
 		/* Set UART mode, 8 bit, no parity, one stop.
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.4.2/linux/arch/ppc/config.in	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/config.in	Sat Mar  3 10:52:13 2001
@@ -57,14 +57,25 @@
 	"RPX-Lite	CONFIG_RPXLITE		\
 	 RPX-Classic	CONFIG_RPXCLASSIC	\
 	 BSE-IP		CONFIG_BSEIP		\
-	 TQM8xxL	CONFIG_TQM8xxL		\
-	 TQM860L	CONFIG_TQM860L		\
-	 TQM860		CONFIG_TQM860		\
+ 	 TQM823L	CONFIG_TQM823L		\
+ 	 TQM850L	CONFIG_TQM850L		\
+ 	 TQM855L	CONFIG_TQM855L		\
+  	 TQM860L	CONFIG_TQM860L		\
+ 	 FPS850L	CONFIG_FPS850L		\
+  	 TQM860		CONFIG_TQM860		\
+ 	 SPD823TS	CONFIG_SPD823TS		\
+ 	 IVMS8		CONFIG_IVMS8		\
+ 	 SM850		CONFIG_SM850		\
 	 MBX		CONFIG_MBX		\
 	 WinCept	CONFIG_WINCEPT"		RPX-Lite
-	 
-  if [ "$CONFIG_TQM8xxL" = "y" ]; then
-    bool 'FPS850 Mainboard' CONFIG_FPS850
+
+  if [ "$CONFIG_TQM823L" = "y" -o \
+       "$CONFIG_TQM850L" = "y" -o \
+       "$CONFIG_FPS850L" = "y" -o \
+       "$CONFIG_TQM855L" = "y" -o \
+       "$CONFIG_TQM860L" = "y" -o \
+       "$CONFIG_SM850"   = "y" ]; then
+ 	define_bool	CONFIG_TQM8xxL	y
   fi
 fi
 
@@ -298,6 +309,11 @@
     else
       bool '   Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD
     fi
+  fi
+  # This is for drivers/macintosh/mac_hid.o, which is needed if the input
+  # layer is used.
+  if [ "$CONFIG_INPUT" != "n" ]; then
+    define_bool CONFIG_MAC_HID y
   fi
 fi
 endmenu
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/IVMS8_defconfig linux/arch/ppc/configs/IVMS8_defconfig
--- v2.4.2/linux/arch/ppc/configs/IVMS8_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/configs/IVMS8_defconfig	Sat Mar  3 10:52:13 2001
@@ -0,0 +1,452 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
+CONFIG_8xx=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_TQM823L is not set
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_TQM860 is not set
+# CONFIG_SPD823TS is not set
+CONFIG_IVMS8=y
+# CONFIG_SM850 is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_SASH=y
+CONFIG_SASH_PATH="/bin/sash"
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+# 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 is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# 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_MPC8xx_IDE=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_FLASH is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_AGP is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+# CONFIG_SCC_ENET is not set
+CONFIG_FEC_ENET=y
+CONFIG_USE_MDIO=y
+CONFIG_ENET_BIG_BUFFERS=y
+# CONFIG_8xxSMC2 is not set
+# CONFIG_8xxSCC is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_CPU6 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/SM850_defconfig linux/arch/ppc/configs/SM850_defconfig
--- v2.4.2/linux/arch/ppc/configs/SM850_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/configs/SM850_defconfig	Sat Mar  3 10:52:13 2001
@@ -0,0 +1,420 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
+CONFIG_8xx=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_TQM823L is not set
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_TQM860 is not set
+# CONFIG_SPD823TS is not set
+CONFIG_SM850=y
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+CONFIG_TQM8xxL=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_SASH=y
+CONFIG_SASH_PATH="/bin/sash"
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_FLASH=y
+CONFIG_AMD_FLASH=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_AGP is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+# CONFIG_SCC1_ENET is not set
+# CONFIG_SCC2_ENET is not set
+CONFIG_SCC3_ENET=y
+# CONFIG_FEC_ENET is not set
+CONFIG_ENET_BIG_BUFFERS=y
+CONFIG_8xxSMC2=y
+CONFIG_8xx_ALTSMC2=y
+CONFIG_8xx_CONS_SMC2=y
+# CONFIG_8xxSCC is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/SPD823TS_defconfig linux/arch/ppc/configs/SPD823TS_defconfig
--- v2.4.2/linux/arch/ppc/configs/SPD823TS_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/configs/SPD823TS_defconfig	Sat Mar  3 10:52:13 2001
@@ -0,0 +1,416 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
+CONFIG_8xx=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_TQM823L is not set
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_TQM860 is not set
+CONFIG_SPD823TS=y
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_SASH=y
+CONFIG_SASH_PATH="/bin/sash"
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_FLASH is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_AGP is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+# CONFIG_SCC1_ENET is not set
+CONFIG_SCC2_ENET=y
+# CONFIG_FEC_ENET is not set
+CONFIG_ENET_BIG_BUFFERS=y
+CONFIG_8xxSMC2=y
+CONFIG_8xx_ALTSMC2=y
+# CONFIG_8xx_CONS_SMC2 is not set
+# CONFIG_8xxSCC is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_CPU6 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/TQM823L_defconfig linux/arch/ppc/configs/TQM823L_defconfig
--- v2.4.2/linux/arch/ppc/configs/TQM823L_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/configs/TQM823L_defconfig	Sat Mar  3 10:52:13 2001
@@ -0,0 +1,419 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
+CONFIG_8xx=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+CONFIG_TQM823L=y
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_TQM860 is not set
+# CONFIG_SPD823TS is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+CONFIG_TQM8xxL=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_SASH=y
+CONFIG_SASH_PATH="/bin/sash"
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_FLASH=y
+CONFIG_AMD_FLASH=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_AGP is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+# CONFIG_SCC1_ENET is not set
+CONFIG_SCC2_ENET=y
+# CONFIG_SCC3_ENET is not set
+# CONFIG_FEC_ENET is not set
+CONFIG_ENET_BIG_BUFFERS=y
+CONFIG_8xxSMC2=y
+CONFIG_8xx_ALTSMC2=y
+# CONFIG_8xx_CONS_SMC2 is not set
+# CONFIG_8xxSCC is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_CPU6 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/TQM850L_defconfig linux/arch/ppc/configs/TQM850L_defconfig
--- v2.4.2/linux/arch/ppc/configs/TQM850L_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/configs/TQM850L_defconfig	Sat Mar  3 10:52:13 2001
@@ -0,0 +1,419 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
+CONFIG_8xx=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_TQM823L is not set
+CONFIG_TQM850L=y
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_TQM860 is not set
+# CONFIG_SPD823TS is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+CONFIG_TQM8xxL=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_SASH=y
+CONFIG_SASH_PATH="/bin/sash"
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_FLASH=y
+CONFIG_AMD_FLASH=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_AGP is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+# CONFIG_SCC1_ENET is not set
+CONFIG_SCC2_ENET=y
+# CONFIG_SCC3_ENET is not set
+# CONFIG_FEC_ENET is not set
+CONFIG_ENET_BIG_BUFFERS=y
+CONFIG_8xxSMC2=y
+CONFIG_8xx_ALTSMC2=y
+# CONFIG_8xx_CONS_SMC2 is not set
+# CONFIG_8xxSCC is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/TQM860L_defconfig linux/arch/ppc/configs/TQM860L_defconfig
--- v2.4.2/linux/arch/ppc/configs/TQM860L_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/configs/TQM860L_defconfig	Sat Mar  3 10:52:13 2001
@@ -0,0 +1,419 @@
+#
+# Automatically generated make config: don't edit
+#
+# CONFIG_UID16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+# CONFIG_6xx is not set
+# CONFIG_4xx is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+# CONFIG_8260 is not set
+CONFIG_8xx=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_TQM823L is not set
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+CONFIG_TQM860L=y
+# CONFIG_FPS850L is not set
+# CONFIG_TQM860 is not set
+# CONFIG_SPD823TS is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+CONFIG_TQM8xxL=y
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_MATH_EMULATION=y
+CONFIG_SASH=y
+CONFIG_SASH_PATH="/bin/sash"
+
+#
+# General setup
+#
+# CONFIG_ISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_LVM is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_FLASH=y
+CONFIG_AMD_FLASH=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
+# CONFIG_AGP is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+CONFIG_SCC1_ENET=y
+# CONFIG_SCC2_ENET is not set
+# CONFIG_SCC3_ENET is not set
+# CONFIG_FEC_ENET is not set
+CONFIG_ENET_BIG_BUFFERS=y
+CONFIG_8xxSMC2=y
+# CONFIG_8xx_ALTSMC2 is not set
+# CONFIG_8xx_CONS_SMC2 is not set
+# CONFIG_8xxSCC is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+# CONFIG_8xx_CPU6 is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig
--- v2.4.2/linux/arch/ppc/configs/common_defconfig	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/configs/common_defconfig	Sun Mar  4 14:30:18 2001
@@ -295,11 +295,11 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_PROC_STATS=y
-CONFIG_AIC7XXX_RESET_DELAY=15
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_SCSI_AIC7XXX_OLD=m
+# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
+CONFIG_AIC7XXX_OLD_PROC_STATS=y
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.4.2/linux/arch/ppc/defconfig	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/defconfig	Sun Mar  4 14:30:18 2001
@@ -296,10 +296,9 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_PROC_STATS=y
-CONFIG_AIC7XXX_RESET_DELAY=15
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY=15000
+# CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.4.2/linux/arch/ppc/kernel/Makefile	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/Makefile	Sat Mar  3 10:52:13 2001
@@ -70,6 +70,7 @@
 
 include $(TOPDIR)/Rules.make
 
+entry.o: entry.S ppc_defs.h
 head.o: head.S ppc_defs.h
 head_4xx.o: head_4xx.S ppc_defs.h
 head_8xx.o: head_8xx.S ppc_defs.h
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.4.2/linux/arch/ppc/kernel/chrp_pci.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/chrp_pci.c	Sat Mar  3 10:52:13 2001
@@ -298,8 +298,9 @@
     	bus->resource[1] = &gg2_resources.pci_mem;
 }
 
-static void process_bridge_ranges(struct pci_controller *hose,
-				  struct device_node *dev, int index)
+/* this is used by the pmac_pci code too... - paulus */
+void process_bridge_ranges(struct pci_controller *hose,
+			   struct device_node *dev, int primary)
 {
 	unsigned int *ranges;
 	int rlen = 0;
@@ -316,31 +317,34 @@
 				break;
 			hose->io_base_phys = ranges[3];
 			hose->io_base_virt = ioremap(ranges[3], ranges[5]);
-			if (index == 0) {
+			if (primary)
 				isa_io_base = (unsigned long) hose->io_base_virt;
-				printk("isa_io_base=%lx\n", isa_io_base);
-			}
 			res = &hose->io_resource;
 			res->flags = IORESOURCE_IO;
+			res->start = ranges[2];
 			break;
 		case 2:		/* memory space */
-			if (index == 0 && ranges[1] == 0 && ranges[2] == 0){
-				isa_mem_base = ranges[3];
-				printk("isa_mem_base=%lx\n", isa_mem_base);
+			memno = 0;
+			if (ranges[1] == 0 && ranges[2] == 0
+			    && ranges[5] <= (16 << 20)) {
+				/* 1st 16MB, i.e. ISA memory area */
+				if (primary)
+					isa_mem_base = ranges[3];
+				memno = 1;
 			}
-			if (memno == 0) {
+			while (memno < 3 && hose->mem_resources[memno].flags)
+				++memno;
+			if (memno == 0)
 				hose->pci_mem_offset = ranges[3] - ranges[2];
-				printk("pci_mem_offset=%lx for this bridge\n",
-				       hose->pci_mem_offset);
+			if (memno < 3) {
+				res = &hose->mem_resources[memno];
+				res->flags = IORESOURCE_MEM;
+				res->start = ranges[3];
 			}
-			res = &hose->mem_resources[memno];
-			res->flags = IORESOURCE_MEM;
-			++memno;
 			break;
 		}
 		if (res != NULL) {
 			res->name = dev->full_name;
-			res->start = ranges[3];
 			res->end = res->start + ranges[5] - 1;
 			res->parent = NULL;
 			res->sibling = NULL;
@@ -401,7 +405,7 @@
        		hose->cfg_addr = (volatile unsigned int *) cfg;
        		hose->cfg_data = cfg + 0x10;
 
-		process_bridge_ranges(hose, dev, index);
+		process_bridge_ranges(hose, dev, index == 0);
 
 #ifdef CONFIG_POWER3
                 openpic_setup_ISU(index, opprop[index+1]);
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.4.2/linux/arch/ppc/kernel/chrp_setup.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/chrp_setup.c	Tue Mar  6 19:28:35 2001
@@ -84,7 +84,7 @@
 extern void mackbd_init_hw(void);
 extern unsigned char mackbd_sysrq_xlate[128];
 
-kdev_t boot_dev;
+extern kdev_t boot_dev;
 
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
@@ -237,7 +237,6 @@
 void __init
 chrp_setup_arch(void)
 {
-	extern char cmd_line[];
 	struct device_node *device;
 
 	/* init to some ~sane value until calibrate_delay() runs */
@@ -252,7 +251,6 @@
 	else
 #endif
 		ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */
-	printk("Boot arguments: %s\n", cmd_line);
 
 	/* Lookup PCI host bridges */
 	chrp_find_bridges();
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.4.2/linux/arch/ppc/kernel/head.S	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/head.S	Sat Mar  3 10:52:13 2001
@@ -1135,7 +1135,7 @@
 #ifdef CONFIG_APUS
 /*
  * On APUS the physical base address of the kernel is not known at compile
- * time, which means the __pa/__va constants used are incorect. In the
+ * time, which means the __pa/__va constants used are incorrect. In the
  * __init section is recorded the virtual addresses of instructions using
  * these constants, so all that has to be done is fix these before
  * continuing the kernel boot.
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S
--- v2.4.2/linux/arch/ppc/kernel/head_8xx.S	Sun Sep 17 09:48:06 2000
+++ linux/arch/ppc/kernel/head_8xx.S	Sat Mar  3 10:52:14 2001
@@ -968,26 +968,6 @@
 	SYNC
 	blr
 
-/* Jump into the system reset for the rom.
- * We first disable the MMU, and then jump to the ROM reset address.
- *
- * r3 is the board info structure, r4 is the location for starting.
- * I use this for building a small kernel that can load other kernels,
- * rather than trying to write or rely on a rom monitor that can tftp load.
- */
-       .globl  m8xx_gorom
-m8xx_gorom:
-       li      r5,MSR_KERNEL & ~(MSR_IR|MSR_DR)
-       lis     r6,2f@h
-       addis   r6,r6,-KERNELBASE@h
-       ori     r6,r6,2f@l
-       mtspr   SRR0,r6
-       mtspr   SRR1,r5
-       rfi
-2:
-       mtlr    r4
-       blr
-
 #ifdef CONFIG_8xx_CPU6
 /* It's here because it is unique to the 8xx.
  * It is important we get called with interrupts disabled.  I used to
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.4.2/linux/arch/ppc/kernel/irq.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/irq.c	Sat Mar  3 10:52:14 2001
@@ -7,8 +7,8 @@
  *    Copyright (C) 1992 Linus Torvalds
  *  Adapted from arch/i386 by Gary Thomas
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *  Updated and modified by Cort Dougan (cort@cs.nmt.edu)
- *    Copyright (C) 1996 Cort Dougan
+ *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
+ *    Copyright (C) 1996-2001 Cort Dougan
  *  Adapted for Power Macintosh by Paul Mackerras
  *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
  *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
@@ -258,7 +258,10 @@
 	
 	retval = setup_irq(irq, action);
 	if (retval)
+	{
 		kfree(action);
+		return retval;
+	}
 		
 	return 0;
 }
@@ -464,13 +467,11 @@
 			ppc_spurious_interrupts++;
 			printk(KERN_DEBUG "Unhandled interrupt %x, disabled\n", irq);
 			/* We can't call disable_irq here, it would deadlock */
-			if (!desc->depth)
-				desc->depth = 1;
+			++desc->depth;
 			desc->status |= IRQ_DISABLED;
-			/* This is not a real spurrious interrupt, we
-			 * have to eoi it, so we jump to out
-			 */
 			mask_irq(irq);
+			/* This is a real interrupt, we have to eoi it,
+			   so we jump to out */
 			goto out;
 		}
 		status &= ~IRQ_PENDING; /* we commit to handling */
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c
--- v2.4.2/linux/arch/ppc/kernel/m8260_setup.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/m8260_setup.c	Sat Mar  3 10:52:14 2001
@@ -85,10 +85,6 @@
 void __init
 m8260_setup_arch(void)
 {
-	extern char cmd_line[];
-	
-	printk("Boot arguments: %s\n", cmd_line);
-
 	/* Reset the Communication Processor Module.
 	*/
 	m8260_cpm_reset();
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.4.2/linux/arch/ppc/kernel/m8xx_setup.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/m8xx_setup.c	Sat Mar  3 10:52:14 2001
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <linux/blk.h>
 #include <linux/ioport.h>
+#include <asm/mpc8xx.h>  /* Before ide.h to avoid warning: `MAX_HWIFS' redefined */
 #include <linux/ide.h>
 #include <linux/bootmem.h>
 
@@ -41,7 +42,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/ide.h>
-#include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
 #include <asm/machdep.h>
 
@@ -52,19 +52,65 @@
 unsigned long m8xx_get_rtc_time(void);
 void m8xx_calibrate_decr(void);
 
-#if 0
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-#endif
-
 unsigned char __res[sizeof(bd_t)];
 unsigned long empty_zero_page[1024];
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+
+#ifdef	CONFIG_BLK_DEV_MPC8xx_IDE
+#include "../../../drivers/ide/ide_modes.h"
+
+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 reg. 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];
+
+/* Make clock cycles and always round up */
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
+
+#endif	/* CONFIG_BLK_DEV_MPC8xx_IDE */
+#endif	/* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
@@ -77,6 +123,8 @@
 extern unsigned long find_available_memory(void);
 extern void m8xx_cpm_reset(uint);
 
+static void ide_interrupt_handler(void* dev_id);
+
 void __init adbdev_init(void)
 {
 }
@@ -85,12 +133,9 @@
 m8xx_setup_arch(void)
 {
 	int	cpm_page;
-	extern char cmd_line[];
 	
 	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
 	
-	printk("Boot arguments: %s\n", cmd_line);
-
 	/* Reset the Communication Processor Module.
 	*/
 	m8xx_cpm_reset(cpm_page);
@@ -137,7 +182,7 @@
 */
 void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
 {
-	printk("timebase_interrupt()\n");
+	printk ("timebase_interrupt()\n");
 }
 
 /* The decrementer counts at the system (internal) clock frequency divided by
@@ -164,7 +209,7 @@
 	fp = (binfo->bi_intfreq * 1000000) / 16;
 	freq = fp*60;	/* try to make freq/1e6 an integer */
         divisor = 60;
-        printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+        printk("Decrementer Frequency = %d/%d\n", freq, divisor);
         tb_ticks_per_jiffy = freq / HZ / divisor;
 	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
 
@@ -232,9 +277,21 @@
 void
 m8xx_restart(char *cmd)
 {
-	extern void m8xx_gorom(void);
+	__volatile__ unsigned char dummy;
+	uint	msr;
 
-	m8xx_gorom();
+	cli();
+	((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;
+
+	/* Clear the ME bit in MSR to cause checkstop on machine check
+	*/
+	__asm__("mfmsr %0" : "=r" (msr) );
+	msr &= ~0x1000;
+	__asm__("mtmsr %0" : : "r" (msr) );
+
+	dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
+	printk("Restart failed\n"); 
+	while(1);
 }
 
 void
@@ -257,8 +314,8 @@
 
 	bp = (bd_t *)__res;
 			
-	len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
-		       "bus clock\t: %dMHz\n",
+	len += sprintf(len+buffer,"clock\t\t: %ldMHz\n"
+		       "bus clock\t: %ldMHz\n",
 		       bp->bi_intfreq /*/ 1000000*/,
 		       bp->bi_busfreq /*/ 1000000*/);
 
@@ -298,17 +355,13 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
-/* Define this to make a PCMCIA ATA Flash card work.
-*/
-#define ATA_FLASH 1
-
 /*
  * IDE stuff.
  */
 void
 m8xx_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
-#ifdef ATA_FLASH
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
 	ide_insw(port, buf, ns);
 #else
 	ide_insw(port+_IO_BASE, buf, ns);
@@ -318,7 +371,7 @@
 void
 m8xx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
-#ifdef ATA_FLASH
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
 	ide_outsw(port, buf, ns);
 #else
 	ide_outsw(port+_IO_BASE, buf, ns);
@@ -328,8 +381,11 @@
 int
 m8xx_ide_default_irq(ide_ioreg_t base)
 {
-#ifdef ATA_FLASH
-	return PCMCIA_INTERRUPT;
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+	if (base >= MAX_HWIFS)
+		return 0;
+	
+	return (ioport_dsc[base].irq);
 #else
         return 14;
 #endif
@@ -348,60 +404,105 @@
 		       const char *device,
 		       void *dev_id)
 {
-#ifdef ATA_FLASH
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
 	return request_8xxirq(irq, handler, flags, device, dev_id);
 #else
 	return request_irq(irq, handler, flags, device, dev_id);
 #endif
 }
 
-/* We can use an external IDE controller or wire the IDE interface to
- * the internal PCMCIA controller.
+/* We can use an external IDE controller
+ * or wire the IDE interface to the internal PCMCIA controller.
+ *
+ * See include/linux/ide.h for definition of hw_regs_t (p, base)
  */
-void __init m8xx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+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 port = base;
+	ide_ioreg_t *p = hw->io_ports;
 	int i;
-#ifdef ATA_FLASH
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
 	volatile pcmconf8xx_t	*pcmp;
+
+	static unsigned long pcmcia_base = 0;
+#else
+	ide_ioreg_t port = data_port;	/* ??? XXX ??? XXX */
 #endif
+	unsigned long base;
 
-#ifdef ATA_FLASH
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
 	*p = 0;
-	*irq = 0;
+	if (irq)
+		*irq = 0;
+
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
 
-	if (base != 0)		/* Only map the first ATA flash drive */
+	if (!pcmcia_base) {
+		/* relies PCMCIA registers being set up by firmware */
+		pcmcia_base = (unsigned long) ioremap(PCMCIA_MEM_ADDR,
+						      PCMCIA_MEM_SIZE);
+
+		/* Compute clock cycles for PIO timings */
+		for (i=0; i<6; ++i) {
+			bd_t	*binfo = (bd_t *)__res;
+
+			ide_pio_clocks[i].hold_time   =
+				PCMCIA_MK_CLKS (ide_pio_timings[i].hold_time,
+						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;
 
-	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+	base = pcmcia_base + ioport_dsc[data_port].base_off;
+
+# if (!defined(CONFIG_SPD823TS) && !defined(CONFIG_IVMS8))
+	/* SPD823TS and IVMS8 have a direct connection */
 	if (pcmp->pcmc_pipr & 0x18000000)
 		return;		/* No card in slot */
+# endif	/* CONFIG_SPD823TS, CONFIG_IVMS8 */
 
-	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+	for (i = 0; i < IDE_NR_PORTS; ++i) {
+	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+	}
 
-	/* For the M-Systems ATA card, the first 8 registers map 1:1.
-	 * The following register, control/Altstatus, is located at 0x0e.
-	 * Following that, the irq offset, is not used, so we place it in
-	 * an unused location, 0x0a.
-	 */
-	*p++ = base + 8;
-	for (i = 1; i < 8; ++i)
-		*p++ = base + i;
-	*p++ = base + 0x0e;		/* control/altstatus */
-	*p = base + 0x0a;		/* IRQ, not used */
-	if (irq)
-		*irq = PCMCIA_INTERRUPT;
+	if (irq) {
+	    *irq = ioport_dsc[data_port].irq;
+	}
 
-	/* Configure the interface for this interrupt.
-	*/
-	pcmp->pcmc_pgcra = (mk_int_int_mask(PCMCIA_INTERRUPT) << 24) |
-		(mk_int_int_mask(PCMCIA_INTERRUPT) << 16);
+	/* register routine to tune PIO mode */
+	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
 
-	/* Enable status change interrupt from slot A.
-	*/
-	pcmp->pcmc_per = 0xff100000;
-	pcmp->pcmc_pscr = ~0;
-#else
+	/* Enable Harddisk Interrupt,
+	 * and make it edge sensitive
+	 */
+	hw->ack_intr = (ide_ack_intr_t *)ide_interrupt_handler;
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel |=
+					(0x80000000 >> ioport_dsc[data_port].irq);
+
+#else	/* ! CONFIG_BLK_DEV_MPC8xx_IDE */
 	
 	/* Just a regular IDE drive on some I/O port.
 	*/
@@ -411,10 +512,84 @@
 	*p++ = base + 0x206;
 	if (irq != NULL)
 		*irq = 0;
-#endif
+#endif	/* CONFIG_BLK_DEV_MPC8xx_IDE */
 }
+#endif	/* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
+
+
+/* -------------------------------------------------------------------- */
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
+
+/* 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)
+{
+	volatile pcmconf8xx_t	*pcmp;
+	ide_pio_data_t d;
+	ulong timing, mask, reg;
+
+	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
+	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
+
+	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
+
+	timing  = PCMCIA_SHT(ide_pio_clocks[pio].hold_time  )
+		| 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;
+}
+
+void ide_interrupt_handler (void *dev)
+{
+}
+
+#endif	/* CONFIG_BLK_DEV_MPC8xx_IDE */
+#endif	/* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
+
+/* -------------------------------------------------------------------- */
+
 void __init
 m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	 unsigned long r6, unsigned long r7)
@@ -490,7 +665,6 @@
         ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
         ppc_ide_md.fix_driveid = ppc_generic_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
-        ppc_ide_md.ide_request_irq = m8xx_ide_request_irq;
 
         ppc_ide_md.io_base = _IO_BASE;
 #endif		
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.4.2/linux/arch/ppc/kernel/open_pic.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/open_pic.c	Sat Mar  3 10:52:14 2001
@@ -42,6 +42,45 @@
 
 OpenPIC_SourcePtr ISU[OPENPIC_MAX_ISU];
 
+/* Global Operations */
+static void openpic_disable_8259_pass_through(void);
+static u_int openpic_irq(void);
+static void openpic_eoi(void);
+static void openpic_set_priority(u_int pri);
+static void openpic_set_spurious(u_int vector);
+
+#ifdef CONFIG_SMP
+/* Interprocessor Interrupts */
+static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+#endif
+
+/* Timer Interrupts */
+static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
+static void openpic_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+static void openpic_enable_irq(u_int irq);
+static void openpic_disable_irq(u_int irq);
+static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+			    int is_level);
+static void openpic_mapirq(u_int irq, u_int cpumask);
+
+/*
+ * These functions are not used but the code is kept here
+ * for completeness and future reference.
+ */
+#ifdef notused
+static void openpic_reset(void);
+static void openpic_enable_8259_pass_through(void);
+static u_int openpic_get_priority(void);
+static u_int openpic_get_spurious(void);
+static void openpic_set_sense(u_int irq, int sense);
+#endif /* notused */
+
+/*
+ * Description of the openpic for the higher-level irq code
+ */
 static void openpic_end_irq(unsigned int irq_nr);
 static void openpic_ack_irq(unsigned int irq_nr);
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
@@ -370,17 +409,19 @@
 #endif
 }
 
-static inline void openpic_reset(void)
+#ifdef notused
+static void openpic_reset(void)
 {
 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
 			 OPENPIC_CONFIG_RESET);
 }
 
-static inline void openpic_enable_8259_pass_through(void)
+static void openpic_enable_8259_pass_through(void)
 {
 	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
 			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
 }
+#endif /* notused */
 
 static void openpic_disable_8259_pass_through(void)
 {
@@ -412,8 +453,8 @@
 	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
 }
 
-
-static inline u_int openpic_get_priority(void)
+#ifdef notused
+static u_int openpic_get_priority(void)
 {
 	DECL_THIS_CPU;
 
@@ -421,6 +462,7 @@
 	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
 				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
 }
+#endif /* notused */
 
 static void openpic_set_priority(u_int pri)
 {
@@ -435,11 +477,13 @@
 /*
  *  Get/set the spurious vector
  */
-static inline u_int openpic_get_spurious(void)
+#ifdef notused
+static u_int openpic_get_spurious(void)
 {
 	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
 				 OPENPIC_VECTOR_MASK);
 }
+#endif /* notused */
 
 static void openpic_set_spurious(u_int vec)
 {
@@ -604,21 +648,6 @@
 static void openpic_enable_irq(u_int irq)
 {
 	check_arg_irq(irq);
-
-        /*
-         * Never want to disable a timer or ipi irq
-         * (only want to disable irqs within an ISU).
-         */
-        if (((irq >= OPENPIC_VEC_IPI+open_pic_irq_offset)   &&
-           (irq <  OPENPIC_VEC_IPI+open_pic_irq_offset+OPENPIC_NUM_IPI)) ||
-           ((irq >= OPENPIC_VEC_TIMER+open_pic_irq_offset) &&
-            (irq <  OPENPIC_VEC_TIMER+open_pic_irq_offset+OPENPIC_NUM_TIMERS)))
-        {
-        /* silently ignore the enable of the timer or ipi irq. */
-        return;
-        }
-
-
 	openpic_clearfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
@@ -632,19 +661,6 @@
 	u32 vp;
 	
 	check_arg_irq(irq);
-        /*
-         * Never want to disable a timer or ipi irq
-         * (only want to disable irqs within an ISU).
-         */
-        if (((irq >= OPENPIC_VEC_IPI+open_pic_irq_offset)   &&
-             (irq <  OPENPIC_VEC_IPI+open_pic_irq_offset+OPENPIC_NUM_IPI)) ||
-             ((irq >= OPENPIC_VEC_TIMER+open_pic_irq_offset) &&
-             (irq <  OPENPIC_VEC_TIMER+open_pic_irq_offset+OPENPIC_NUM_TIMERS)))
-        {
-                panic("openpic_disable_irq - disabling non-ISU irq");
-        }
-
-
 	openpic_setfield(&GET_ISU(irq - open_pic_irq_offset).Vector_Priority, OPENPIC_MASK);
 	/* make sure mask gets to controller before we return to user */
 	do {
@@ -667,11 +683,13 @@
 	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
 
 }
+
 void openpic_disable_ipi(u_int irq)
 {
-   /* NEVER disable an IPI... that's just plain wrong! */
+	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
+	check_arg_ipi(irq);
+	openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
 }
-
 #endif
 
 /*
@@ -702,39 +720,33 @@
 	openpic_write(&GET_ISU(irq).Destination, physmask);
 }
 
+#ifdef notused
 /*
  *  Set the sense for an interrupt source (and disable it!)
  *
  *  sense: 1 for level, 0 for edge
  */
-static inline void openpic_set_sense(u_int irq, int sense)
+static void openpic_set_sense(u_int irq, int sense)
 {
 	openpic_safe_writefield(&GET_ISU(irq).Vector_Priority,
 				OPENPIC_SENSE_LEVEL,
 				(sense ? OPENPIC_SENSE_LEVEL : 0));
 }
+#endif /* notused */
 
 /* No spinlocks, should not be necessary with the OpenPIC
  * (1 register = 1 interrupt and we have the desc lock).
  */
 static void openpic_ack_irq(unsigned int irq_nr)
 {
-#if 1 /* masking should be unnecessary, but I still get spurrious */
 	openpic_disable_irq(irq_nr);
-#endif		
-	if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
-		openpic_eoi();
+	openpic_eoi();
 }
 
 static void openpic_end_irq(unsigned int irq_nr)
 {
-	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
-		openpic_eoi();
-	
-#if 1 /* masking should be unnecessary, but I still get spurrious */
 	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
 		openpic_enable_irq(irq_nr);
-#endif
 }
 
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
@@ -745,23 +757,11 @@
 #ifdef CONFIG_SMP
 static void openpic_ack_ipi(unsigned int irq_nr)
 {
+	openpic_eoi();
 }
 
 static void openpic_end_ipi(unsigned int irq_nr)
 {
-	/* IPIs are marked IRQ_PER_CPU. This has the side effect of
-	 * preventing the IRQ_PENDING/IRQ_INPROGRESS logic from
-	 * applying to them. We EOI them late to avoid re-entering.
-	 * however, I'm wondering if we could simply let them have the
-	 * SA_INTERRUPT flag and let them execute with all interrupts OFF.
-	 * This would have the side effect of either running cross-CPU
-	 * functions with interrupts off, or we can re-enable them explicitely
-	 * with a __sti() in smp_call_function_interrupt(), since
-	 * smp_call_function() is protected by a spinlock.
-	 * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU
-	 * function calls IPI at all but that would make a special case.
-	 */
-	openpic_eoi();
 }
 
 static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
@@ -791,8 +791,11 @@
 			irq = i8259_irq( smp_processor_id() );
 		openpic_eoi();
         }
-	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
+	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) {
 		irq = -1;
+		/* That's not SMP safe ... but who cares ? */
+		ppc_spurious_interrupts++;
+	}
 	return irq;
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/open_pic_defs.h linux/arch/ppc/kernel/open_pic_defs.h
--- v2.4.2/linux/arch/ppc/kernel/open_pic_defs.h	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/open_pic_defs.h	Sat Mar  3 10:52:14 2001
@@ -28,8 +28,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
-
     /*
      *  OpenPIC supports up to 2048 interrupt sources and up to 32 processors
      */
@@ -288,40 +286,6 @@
 /* Interrupt Source Registers */
 #define Vector_Priority			_Vector_Priority.Reg
 #define Destination			_Destination.Reg
-
-    /*
-     *  Local (static) OpenPIC Operations
-     */
-
-
-/* Global Operations */
-static void openpic_reset(void);
-static void openpic_enable_8259_pass_through(void);
-static void openpic_disable_8259_pass_through(void);
-static u_int openpic_irq(void);
-static void openpic_eoi(void);
-static u_int openpic_get_priority(void);
-static void openpic_set_priority(u_int pri);
-static u_int openpic_get_spurious(void);
-static void openpic_set_spurious(u_int vector);
-
-#ifdef CONFIG_SMP
-/* Interprocessor Interrupts */
-static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
-#endif
-
-/* Timer Interrupts */
-static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
-static void openpic_maptimer(u_int timer, u_int cpumask);
-
-/* Interrupt Sources */
-static void openpic_enable_irq(u_int irq);
-static void openpic_disable_irq(u_int irq);
-static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
-			    int is_level);
-static void openpic_mapirq(u_int irq, u_int cpumask);
-static void openpic_set_sense(u_int irq, int sense);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.4.2/linux/arch/ppc/kernel/pci.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/pci.c	Sat Mar  3 10:52:14 2001
@@ -109,7 +109,7 @@
 		struct resource *res = dev->resource + i;
 		if (!res->start)
 			continue;
-		if (res->flags & IORESOURCE_MEM) {
+		if ((res->flags & IORESOURCE_MEM) && hose->pci_mem_offset) {
 			res->start += hose->pci_mem_offset;
 			res->end += hose->pci_mem_offset;
 #ifdef DEBUG
@@ -121,7 +121,9 @@
 
 		if ((res->flags & IORESOURCE_IO)
 		    && (unsigned long) hose->io_base_virt != isa_io_base) {
-			unsigned long offs = (unsigned long) hose->io_base_virt - isa_io_base;
+			unsigned long offs;
+
+			offs = (unsigned long)hose->io_base_virt - isa_io_base;
 			res->start += offs;
 			res->end += offs;
 			printk("Fixup IO res, dev: %x.%x, res_start: %lx->%lx\n",
@@ -245,13 +247,30 @@
 	}
 }
 
+static inline void alloc_resource(struct pci_dev *dev, int idx)
+{
+	struct resource *pr, *r = &dev->resource[idx];
+
+	DBG("PCI:%x:%x:%x: Resource %08lx-%08lx (f=%lx)\n",
+	    dev->bus->number, dev->devfn >> 3, dev->devfn & 7,
+	    r->start, r->end, r->flags);
+	pr = pci_find_parent_resource(dev, r);
+	if (!pr || request_resource(pr, r) < 0) {
+		printk(KERN_ERR "PCI: Cannot allocate resource region %d"
+		       " of device %s\n", idx, dev->slot_name);
+		/* We'll assign a new address later */
+		r->end -= r->start;
+		r->start = 0;
+	}
+}
+
 static void __init
 pcibios_allocate_resources(int pass)
 {
 	struct pci_dev *dev;
 	int idx, disabled;
 	u16 command;
-	struct resource *r, *pr;
+	struct resource *r;
 
 	pci_for_each_dev(dev) {
 		pci_read_config_word(dev, PCI_COMMAND, &command);
@@ -259,7 +278,7 @@
 			r = &dev->resource[idx];
 			if (r->parent)		/* Already allocated */
 				continue;
-			if (!r->start)		/* Address not assigned at all */
+			if (!r->start)		/* Not assigned at all */
 				continue;
 			if (r->end == 0xffffffff) {
 				/* LongTrail OF quirk: unassigned */
@@ -273,28 +292,19 @@
 				disabled = !(command & PCI_COMMAND_IO);
 			else
 				disabled = !(command & PCI_COMMAND_MEMORY);
-			if (pass == disabled) {
-				DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
-				    r->start, r->end, r->flags, disabled, pass);
-				pr = pci_find_parent_resource(dev, r);
-				if (!pr || request_resource(pr, r) < 0) {
-					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
-					/* We'll assign a new address later */
-					r->end -= r->start;
-					r->start = 0;
-				}
-			}
+			if (pass == disabled)
+				alloc_resource(dev, idx);
 		}
-		if (!pass) {
-			r = &dev->resource[PCI_ROM_RESOURCE];
-			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
-				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
-				u32 reg;
-				DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
-				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
-				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
-			}
+		if (pass)
+			continue;
+		r = &dev->resource[PCI_ROM_RESOURCE];
+		if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+			/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+			u32 reg;
+			DBG("PCI: Switching off ROM of %s\n", dev->slot_name);
+			r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+			pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+			pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
 		}
 	}
 }
@@ -315,17 +325,18 @@
 
 		for(idx=0; idx<6; idx++) {
 			r = &dev->resource[idx];
-
+#if 0	/* we don't need this PC-ism */
 			/*
 			 *  Don't touch IDE controllers and I/O ports of video cards!
 			 */
 			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
 			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
 				continue;
+#endif
 
 			/*
 			 *  We shall assign a new address to this resource, either because
-			 *  the BIOS forgot to do so or because we have decided the old
+			 *  the BIOS (sic) forgot to do so or because we have decided the old
 			 *  address was unusable for some reason.
 			 */
 			if (!r->start && r->end &&
@@ -572,7 +583,7 @@
 {
 	struct pci_controller *hose;
 	struct pci_bus *bus;
-	int next_busno;
+	int next_busno, i;
 
 	printk("PCI: Probing PCI hardware\n");
 
@@ -582,6 +593,17 @@
 			hose->first_busno = next_busno;
 		hose->last_busno = 0xff;
 		bus = pci_scan_bus(hose->first_busno, hose->ops, hose);
+		if (hose->io_resource.flags) {
+			unsigned long offs;
+
+			offs = (unsigned long)hose->io_base_virt - isa_io_base;
+			hose->io_resource.start += offs;
+			hose->io_resource.end += offs;
+			bus->resource[0] = &hose->io_resource;
+		}
+		for (i = 0; i < 3; ++i)
+			if (hose->mem_resources[i].flags)
+				bus->resource[i+1] = &hose->mem_resources[i];
 		hose->bus = bus;
 		hose->last_busno = bus->subordinate;
 		if (pci_assign_all_busses || next_busno <= hose->last_busno)
@@ -654,8 +676,20 @@
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
+	struct pci_controller *hose;
+
 	pci_read_bridge_bases(bus);
-	
+
+	hose = pci_bus_to_hose(bus->number);
+
+	/* Apply pci_mem_offset to bridge mem resource */
+	if (hose->first_busno != bus->number)
+		if (bus->resource[1]->start && (bus->resource[1]->end != -1))
+		{
+			bus->resource[1]->start += hose->pci_mem_offset;
+			bus->resource[1]->end += hose->pci_mem_offset;
+		}
+
 	if ( ppc_md.pcibios_fixup_bus )
 		ppc_md.pcibios_fixup_bus(bus);
 }
@@ -773,6 +807,32 @@
 /* Obsolete functions. Should be removed once the symbios driver
  * is fixed
  */
+unsigned long
+phys_to_bus(unsigned long pa)
+{
+	struct pci_controller *hose;
+	int i;
+
+	for (hose = hose_head; hose; hose = hose->next) {
+		for (i = 0; i < 3; ++i) {
+			if (pa >= hose->mem_resources[i].start
+			    && pa <= hose->mem_resources[i].end) {
+				/*
+				 * XXX the hose->pci_mem_offset really
+				 * only applies to mem_resources[0].
+				 * We need a way to store an offset for
+				 * the others.  -- paulus
+				 */
+				if (i == 0)
+					pa -= hose->pci_mem_offset;
+				return pa;
+			}
+		}
+	}
+	/* hmmm, didn't find it */
+	return 0;
+}
+
 unsigned long
 pci_phys_to_bus(unsigned long pa, int busnr)
 {
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.4.2/linux/arch/ppc/kernel/pmac_pci.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/pmac_pci.c	Sat Mar  3 10:52:14 2001
@@ -29,6 +29,8 @@
 
 #undef DEBUG
 
+extern void process_bridge_ranges(struct pci_controller *hose,
+				  struct device_node *dev, int primary);
 static void add_bridges(struct device_node *dev);
 
 /* XXX Could be per-controller, but I don't think we risk anything by
@@ -372,7 +374,7 @@
 	(void)in_le32((volatile unsigned int *)bp->cfg_data);
 }
 
-static void __init
+static int __init
 setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
 {
 	pci_assign_all_busses = 1;
@@ -380,6 +382,7 @@
 	hose->ops = &macrisc_pci_ops;
 	hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
 	hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
+#if 0 /* done in process_bridge_ranges now - paulus */
 	hose->io_base_phys = addr->address;
 	/* is 0x10000 enough for io space ? */
 	hose->io_base_virt = (void *)ioremap(addr->address, 0x10000);
@@ -389,6 +392,9 @@
 	 */
 	if (addr->address == 0xf2000000)
 		isa_io_base = (unsigned long)hose->io_base_virt;
+#endif
+	/* We "know" that the bridge at f2000000 has the PCI slots. */
+	return addr->address == 0xf2000000;
 }
 
 static void __init
@@ -399,8 +405,10 @@
 		ioremap(addr->address + 0x800000, 0x1000);
 	hose->cfg_data = (volatile unsigned char *)
 		ioremap(addr->address + 0xc00000, 0x1000);
+#if 0 /* done in process_bridge_ranges now - paulus */
 	hose->io_base_phys = addr->address;
 	hose->io_base_virt = (void *) ioremap(addr->address, 0x10000);
+#endif
 	init_bandit(hose);
 }
 
@@ -413,19 +421,23 @@
 		ioremap(addr->address + 0x800000, 0x1000);
 	hose->cfg_data = (volatile unsigned char *)
 		ioremap(addr->address + 0xc00000, 0x1000);
+#if 0 /* done in process_bridge_ranges now - paulus */
 	hose->io_base_phys = addr->address;
 	hose->io_base_virt = (void *) ioremap(addr->address, 0x10000);
+#endif
 }
 
 void __init
 setup_grackle(struct pci_controller *hose, unsigned io_space_size)
 {
 	setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
+#if 0 /* done in process_bridge_ranges now - paulus */
 	hose->io_base_phys = 0xfe000000;
 	hose->io_base_virt = (void *) ioremap(0xfe000000, io_space_size);
 	pci_dram_offset = 0;
 	isa_mem_base = 0xfd000000;
 	isa_io_base = (unsigned long) hose->io_base_virt;
+#endif
 	if (machine_is_compatible("AAPL,PowerBook1998"))
 		grackle_set_loop_snoop(hose, 1);
 #if 0	/* Disabled for now, HW problems ??? */
@@ -445,6 +457,7 @@
 	struct reg_property *addr;
 	char* disp_name;
 	int *bus_range;
+	int first = 1, primary;
 	
 	for (; dev != NULL; dev = dev->next) {
 		addr = (struct reg_property *) get_property(dev, "reg", &len);
@@ -467,8 +480,9 @@
 		hose->last_busno = bus_range ? bus_range[1] : 0xff;
 
 		disp_name = NULL;
+		primary = first;
 		if (device_is_compatible(dev, "uni-north")) {
-			setup_uninorth(hose, addr);
+			primary = setup_uninorth(hose, addr);
 			disp_name = "UniNorth";
 		} else if (strcmp(dev->name, "pci") == 0) {
 			/* XXX assume this is a mpc106 (grackle) */
@@ -480,6 +494,7 @@
 		} else if (strcmp(dev->name, "chaos") == 0) {
 			setup_chaos(hose, addr);
 			disp_name = "Chaos";
+			primary = 0;
 		}
 		printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
 			disp_name, addr->address, hose->first_busno, hose->last_busno);
@@ -488,12 +503,14 @@
 			hose, hose->cfg_addr, hose->cfg_data);
 #endif		
 		
-		/* Setup a default isa_io_base */
-		if (isa_io_base == 0)
-			isa_io_base = (unsigned long)hose->io_base_virt;
+		/* Interpret the "ranges" property */
+		/* This also maps the I/O region and sets isa_io/mem_base */
+		process_bridge_ranges(hose, dev, primary);
 
 		/* Fixup "bus-range" OF property */
 		fixup_bus_range(dev);
+
+		first &= !primary;
 	}
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.4.2/linux/arch/ppc/kernel/pmac_setup.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/pmac_setup.c	Tue Mar  6 19:28:35 2001
@@ -81,7 +81,7 @@
 extern int mackbd_getkeycode(unsigned int scancode);
 extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
 		     char raw_mode);
-extern int mackbd_unexpected_up(unsigned char keycode);
+extern char mackbd_unexpected_up(unsigned char keycode);
 extern void mackbd_leds(unsigned char leds);
 extern void __init mackbd_init_hw(void);
 extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -253,6 +253,7 @@
 
 #endif
 
+#ifdef CONFIG_VT
 /*
  * Dummy mksound function that does nothing.
  * The real one is in the dmasound driver.
@@ -262,6 +263,7 @@
 pmac_mksound(unsigned int hz, unsigned int ticks)
 {
 }
+#endif /* CONFIG_VT */
 
 static volatile u32 *sysctrl_regs;
 
@@ -345,9 +347,9 @@
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
-
+#ifdef CONFIG_VT
 	kd_mksound = pmac_mksound;
-
+#endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start)
 		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
@@ -380,7 +382,7 @@
 void *boot_host;
 int boot_target;
 int boot_part;
-kdev_t boot_dev;
+extern kdev_t boot_dev;
 
 void __init
 pmac_init2(void)
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
--- v2.4.2/linux/arch/ppc/kernel/ppc8xx_pic.c	Tue May  2 13:05:40 2000
+++ linux/arch/ppc/kernel/ppc8xx_pic.c	Sat Mar  3 10:52:14 2001
@@ -153,6 +153,20 @@
 	irq += i8259_pic.irq_offset;
 	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
 #else
-	panic("request_irq");
+	/*
+	 * Handle other "well-known" interrupts, but panic on unknown ones.
+	 */
+	switch (irq) {
+#ifdef	IDE0_INTERRUPT
+	case IDE0_INTERRUPT:		/* fall through */
+#endif
+#ifdef	IDE1_INTERRUPT
+	case IDE1_INTERRUPT:		/* fall through */
+#endif
+		return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
+	
+	default:			/* unknown IRQ -> panic */
+		panic("request_irq");
+	}
 #endif
 }
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.4.2/linux/arch/ppc/kernel/ppc_ksyms.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Sat Mar  3 10:52:14 2001
@@ -46,6 +46,10 @@
 #endif /* CONFIG_SMP */
 #include <asm/time.h>
 
+#ifdef  CONFIG_8xx
+#include "../8xx_io/commproc.h"
+#endif
+
 /* Tell string.h we don't want memcpy etc. as cpp defines */
 #define EXPORT_SYMTAB_STROPS
 
@@ -94,7 +98,7 @@
 EXPORT_SYMBOL_NOVERS(pci_dram_offset);
 #endif
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
-EXPORT_SYMBOL(DMA_MODE_READ);
+EXPORT_SYMBOL_NOVERS(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
 #ifndef CONFIG_8xx
 #if defined(CONFIG_ALL_PPC)
@@ -192,6 +196,9 @@
 EXPORT_SYMBOL(giveup_altivec);
 #endif /* CONFIG_ALTIVEC */
 #ifdef CONFIG_SMP
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
@@ -242,11 +249,11 @@
 EXPORT_SYMBOL(set_backlight_enable);
 EXPORT_SYMBOL(register_backlight_controller);
 #endif /* CONFIG_PMAC_BACKLIGHT */
-EXPORT_SYMBOL_NOVERS(sys_ctrler);
 #ifndef CONFIG_MACH_SPECIFIC
 EXPORT_SYMBOL_NOVERS(have_of);
 #endif /* CONFIG_MACH_SPECIFIC */
 #if defined(CONFIG_ALL_PPC)
+EXPORT_SYMBOL_NOVERS(sys_ctrler);
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
 EXPORT_SYMBOL(find_compatible_devices);
@@ -280,7 +287,9 @@
 #if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC)
 EXPORT_SYMBOL(note_scsi_host);
 #endif
+#ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
+#endif
 #ifdef CONFIG_NVRAM
 EXPORT_SYMBOL(nvram_read_byte);
 EXPORT_SYMBOL(nvram_write_byte);
@@ -342,11 +351,18 @@
 EXPORT_SYMBOL(debugger_fault_handler);
 #endif
 
+#ifdef  CONFIG_8xx
+EXPORT_SYMBOL(request_8xxirq);
+EXPORT_SYMBOL(cpm_install_handler);
+EXPORT_SYMBOL(cpm_free_handler);
+#endif /* CONFIG_8xx */
+
 EXPORT_SYMBOL(ret_to_user_hook);
 EXPORT_SYMBOL(do_softirq);
 EXPORT_SYMBOL(next_mmu_context);
 EXPORT_SYMBOL(set_context);
 EXPORT_SYMBOL(mmu_context_overflow);
+EXPORT_SYMBOL_NOVERS(disarm_decr);
 #if !defined(CONFIG_8xx) && !defined(CONFIG_4xx)
 extern long *intercept_table;
 EXPORT_SYMBOL(intercept_table);
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.4.2/linux/arch/ppc/kernel/prep_pci.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/prep_pci.c	Sat Mar  3 10:52:14 2001
@@ -37,6 +37,10 @@
 /* How is the 82378 PIRQ mapping setup? */
 unsigned char *Motherboard_routes;
 
+void (*Motherboard_non0)(struct pci_dev *);
+
+void Powerplus_Map_Non0(struct pci_dev *);
+
 /* Used for Motorola to store system config register */
 static unsigned long	*ProcInfo;
 
@@ -505,6 +509,52 @@
         13      /* Line 4 */
 };
 
+/* Motorola PowerPlus architecture PCI IRQ tables */
+/* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
+
+struct powerplus_irq_list
+{
+	unsigned char primary[4];       /* INT A-D */
+	unsigned char secondary[4];     /* INT A-D */
+};
+
+/*
+ * For standard PowerPlus boards, bus 0 PCI INTs A-D are routed to
+ * OpenPIC inputs 9-12.  PCI INTs A-D from the on board P2P bridge
+ * are routed to OpenPIC inputs 5-8.  These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Powerplus_pci_IRQ_list =
+{
+	{25, 26, 27, 28},
+	{21, 22, 23, 24}
+};
+
+/*
+ * For the MCP750 (system slot board), cPCI INTs A-D are routed to
+ * OpenPIC inputs 8-11 and the PMC INTs A-D are routed to OpenPIC
+ * input 3.  On a hot swap MCP750, the companion card PCI INTs A-D
+ * are routed to OpenPIC inputs 12-15. These values are offset by
+ * 16 in the table to reflect the Linux kernel interrupt value.
+ */
+struct powerplus_irq_list Mesquite_pci_IRQ_list =
+{
+	{24, 25, 26, 27},
+	{28, 29, 30, 31}
+};
+
+/*
+ * This table represents the standard PCI swizzle defined in the
+ * PCI bus specification.
+ */
+static unsigned char prep_pci_intpins[4][4] =
+{
+	{ 1, 2, 3, 4},  /* Buses 0, 4, 8, ... */
+	{ 2, 3, 4, 1},  /* Buses 1, 5, 9, ... */
+	{ 3, 4, 1, 2},  /* Buses 2, 6, 10 ... */
+	{ 4, 1, 2, 3},  /* Buses 3, 7, 11 ... */
+};
+
 /* We have to turn on LEVEL mode for changed IRQ's */
 /* All PCI IRQ's need to be level mode, so this should be something
  * other than hard-coded as well... IRQ's are individually mappable
@@ -599,6 +649,7 @@
 #define MOT_RAVEN_PRESENT	0x1
 #define MOT_HAWK_PRESENT	0x2
 
+int mot_entry = -1;
 int prep_keybd_present = 1;
 int MotMPIC;
 int mot_multi;
@@ -682,33 +733,36 @@
 	const char	*name;
 	unsigned char	*map;
 	unsigned char	*routes;
+	void            (*map_non0_bus)(struct pci_dev *);      /* For boards with more than bus 0 devices. */
+	struct powerplus_irq_list *pci_irq_list; /* List of PCI MPIC inputs */
+	unsigned char   secondary_bridge_devfn; /* devfn of secondary bus transparent bridge */
 } mot_info[] = {
-	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes},
-	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes},
-	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes},
-	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes},
-	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes},
-	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes},
-	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes},
-	{0x000, 0x00, 0x00, "",					NULL,			NULL}
+	{0x300, 0x00, 0x00, "MVME 2400",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x010, 0x00, 0x00, "Genesis",				Genesis_pci_IRQ_map,	Genesis_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x020, 0x00, 0x00, "Powerstack (Series E)",		Comet_pci_IRQ_map,	Comet_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x040, 0x00, 0x00, "Blackhawk (Powerstack)",		Blackhawk_pci_IRQ_map,	Blackhawk_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x050, 0x00, 0x00, "Omaha (PowerStack II Pro3000)",	Omaha_pci_IRQ_map,	Omaha_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x060, 0x00, 0x00, "Utah (Powerstack II Pro4000)",	Utah_pci_IRQ_map,	Utah_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x0A0, 0x00, 0x00, "Powerstack (Series EX)",		Comet2_pci_IRQ_map,	Comet2_pci_IRQ_routes, NULL, NULL, 0x00},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)",		Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)",		Sitka_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC",	Mesquite_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Mesquite_pci_IRQ_list, 0xC0},
+	{0x1E0, 0xF6, 0x80, "MTX Plus",				MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus",			MTXplus_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xA0},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port",		MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port",	MTX_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xF9, 0x00, "MVME 2300",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",			Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0x00},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761",		Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x1E0, 0xFF, 0x00, "MVME 1600-001 or 1600-011",	Genesis2_pci_IRQ_map,	Raven_pci_IRQ_routes, Powerplus_Map_Non0, &Powerplus_pci_IRQ_list, 0xFF},
+	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
 };
 
 unsigned long __init prep_route_pci_interrupts(void)
@@ -723,7 +777,6 @@
 		unsigned char  cpu_type;
 		unsigned char  base_mod;
 		int	       entry;
-		int	       mot_entry = -1;
 
 		cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
 		base_mod = inb(MOTOROLA_BASETYPE_REG);
@@ -769,6 +822,7 @@
 		Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
 		Motherboard_map = mot_info[mot_entry].map;
 		Motherboard_routes = mot_info[mot_entry].routes;
+		Motherboard_non0 = mot_info[mot_entry].map_non0_bus;
 
 		if (!(mot_info[entry].cpu_type & 0x100)) {
 			/* AJF adjust level/edge control according to routes */
@@ -836,6 +890,157 @@
 }
 
 void __init
+prep_pib_init(void)
+{
+unsigned char   reg;
+unsigned short  short_reg;
+
+struct pci_dev *dev = NULL;
+
+	if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
+		/*
+		 * Perform specific configuration for the Via Tech or
+		 * or Winbond PCI-ISA-Bridge part.
+		 */
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, 
+					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+			/*
+			 * PPCBUG does not set the enable bits
+			 * for the IDE device. Force them on here.
+			 */
+			pcibios_read_config_byte(dev->bus->number, 
+					dev->devfn, 0x40, &reg);
+
+			reg |= 0x03; /* IDE: Chip Enable Bits */
+			pcibios_write_config_byte(dev->bus->number, 
+					dev->devfn, 0x40, reg);
+
+			/* Force correct IDE function interrupt */
+			dev->irq = 14;
+			pcibios_write_config_byte(dev->bus->number,
+					dev->devfn,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
+
+		} else if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, 
+					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+			/*
+			 * Clear the PCI Interrupt Routing Control Register.
+			 */
+			short_reg = 0x0000;
+			pci_write_config_word(dev, 0x44, short_reg);
+			if (OpenPIC_Addr){
+				/*
+				 * Route both IDE interrupts to IRQ 14
+				 */
+				reg = 0xEE;
+				pci_write_config_byte(dev, 0x44, reg);
+			}
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+						PCI_DEVICE_ID_VIA_82C586_2,
+						dev)))
+		{
+			/* Force correct USB function interrupt */
+			dev->irq = 11;
+			pcibios_write_config_byte(dev->bus->number,
+					dev->devfn,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
+		}
+	}
+	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
+		if (OpenPIC_Addr){
+			/* Disable LEGIRQ mode so PCI INTs are routed to
+			   the 8259 */
+			printk("Set winbond IDE to native mode\n");
+			pci_write_config_dword(dev, 0x40, 0x10ff00a1);
+		}else{
+			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
+			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
+		}
+	}
+}
+
+void
+Powerplus_Map_Non0(struct pci_dev *dev)
+{
+	struct pci_bus  *pbus;          /* Parent bus structure pointer */
+	struct pci_dev  *tdev = dev;    /* Temporary device structure */
+	unsigned int    devnum;         /* Accumulated device number */
+	unsigned char   intline;        /* Linux interrupt value */
+	unsigned char   intpin;         /* PCI interrupt pin */
+
+	/* Check for valid PCI dev pointer */
+	if (dev == NULL) return;
+
+	/* Initialize bridge IDSEL variable */
+	devnum = PCI_SLOT(tdev->devfn);
+
+	/* Read the interrupt pin of the device and adjust for indexing */
+	pcibios_read_config_byte(dev->bus->number, dev->devfn,
+			PCI_INTERRUPT_PIN, &intpin);
+
+	/* If device doesn't request an interrupt, return */
+	if ( (intpin < 1) || (intpin > 4) )
+		return;
+
+	intpin--;
+
+	/*
+	 * Walk up to bus 0, adjusting the interrupt pin for the standard
+	 * PCI bus swizzle.
+	 */
+	do {
+		intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+		pbus = tdev->bus;        /* up one level */
+		tdev = pbus->self;
+		devnum = PCI_SLOT(tdev->devfn);
+	} while(tdev->bus->number);
+
+	/* Use the primary interrupt inputs by default */
+	intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+
+	/*
+	 * If the board has secondary interrupt inputs, walk the bus and
+	 * note the devfn of the bridge from bus 0.  If it is the same as
+	 * the devfn of the bus bridge with secondary inputs, use those.
+	 * Otherwise, assume it's a PMC site and get the interrupt line
+	 * value from the interrupt routing table.
+	 */ 
+	if (mot_info[mot_entry].secondary_bridge_devfn)
+	{
+		pbus = dev->bus;
+
+		while (pbus->primary != 0)
+			pbus = pbus->parent;
+
+		if ((pbus->self)->devfn != 0xA0)
+		{
+			if ((pbus->self)->devfn == mot_info[mot_entry].secondary_bridge_devfn)
+				intline = mot_info[mot_entry].pci_irq_list->secondary[intpin];
+			else
+			{
+				if ((char *)(mot_info[mot_entry].map) == (char *)Mesquite_pci_IRQ_map)
+					intline = mot_info[mot_entry].map[((pbus->self)->devfn)/8] + 16;
+				else
+				{
+					int i;
+					for (i=0;i<3;i++)
+						intpin = (prep_pci_intpins[devnum % 4][intpin]) - 1;
+					intline = mot_info[mot_entry].pci_irq_list->primary[intpin];
+				}
+			}
+		}
+	}
+
+	/* Write calculated interrupt value to header and device list */
+	dev->irq = intline;
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, (u8)dev->irq);
+}
+
+void __init
 prep_pcibios_fixup(void)
 {
         struct pci_dev *dev;
@@ -849,11 +1054,21 @@
 	if (OpenPIC_Addr) {
 		/* PCI interrupts are controlled by the OpenPIC */
 		pci_for_each_dev(dev) {
-			if (dev->bus->number == 0) {
+			if (dev->bus->number == 0)
+			{
                        		dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]);
-				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_PIN, dev->irq);
+				pcibios_write_config_byte(dev->bus->number, dev->devfn, PCI_INTERRUPT_LINE, dev->irq);
+			}
+			else
+			{
+				if (Motherboard_non0 != NULL)
+					Motherboard_non0(dev);
 			}
 		}
+
+		/* Setup the Winbond or Via PIB */
+		prep_pib_init();
+
 		return;
 	}
 
@@ -912,6 +1127,7 @@
 	hose->first_busno = 0;
 	hose->last_busno = 0xff;
 	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
+	hose->io_base_virt = (void *)PREP_ISA_IO_BASE;
 	
 	printk("PReP architecture\n");
 	{
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.4.2/linux/arch/ppc/kernel/prep_setup.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Sat Mar  3 10:52:14 2001
@@ -215,7 +215,6 @@
 void __init
 prep_setup_arch(void)
 {
-	extern char cmd_line[];
 	unsigned char reg;
 #if 0 /* unused?? */
 	unsigned char ucMothMemType;
@@ -272,8 +271,6 @@
               }
       }
 
-	printk("Boot arguments: %s\n", cmd_line);
-	
 #ifdef CONFIG_SOUND_CS4232
 	/*
 	 * setup proper values for the cs4232 driver so we don't have
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.4.2/linux/arch/ppc/kernel/prom.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/prom.c	Sat Mar  3 10:52:14 2001
@@ -757,8 +757,11 @@
 		setup_disp_fake_bi(RELOC(prom_disp_node));
 #endif
 
-	/* If OpenFirmware version >= 3, then use quiesce call */
-	if (prom_version >= 3) {
+	/* If pmac, then use quiesce call. We can't rely on prom_version
+	 * since some old iMacs appear to have an incorrect /openprom/model
+	 * entry in the device tree
+	 */
+	if (!chrp) {
 		prom_print(RELOC("Calling quiesce ...\n"));
 		call_prom(RELOC("quiesce"), 0, 0);
 	}
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.4.2/linux/arch/ppc/kernel/setup.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/setup.c	Sat Mar  3 10:52:14 2001
@@ -386,8 +386,8 @@
 	if ( i )
 		len += sprintf(buffer+len, "\n");
 	len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
-		       (bogosum+2500)/500000,
-		       (bogosum+2500)/5000 % 100);
+		       (bogosum+2500)/(500000/HZ),
+		       (bogosum+2500)/(5000/HZ) % 100);
 #endif /* CONFIG_SMP */
 
 	/*
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.4.2/linux/arch/ppc/kernel/smp.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/smp.c	Sat Mar  3 10:52:14 2001
@@ -100,14 +100,14 @@
 #define PSURGE_QUAD_CKSTOP_RDBK	8
 #define PSURGE_QUAD_RESET_CTL	11
 
-#define PSURGE_QUAD_OUT(r, v)	(out_8((u8 *)(quad_base+((r)<<2)+1), (v)))
-#define PSURGE_QUAD_IN(r)	(in_8((u8 *)(quad_base+((r)<<2)+1)) & 0x0f)
+#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
+#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
 #define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
 #define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
 
 /* virtual addresses for the above */
 static volatile u8 *hhead_base;
-static volatile u32 *quad_base;
+static volatile u8 *quad_base;
 static volatile u32 *psurge_pri_intr;
 static volatile u8 *psurge_sec_intr;
 static volatile u32 *psurge_start;
@@ -216,7 +216,7 @@
 
 /*
  * Determine a quad card presence. We read the board ID register, we
- * for the data bus to change to something else, and we read it again.
+ * force the data bus to change to something else, and we read it again.
  * It it's stable, then the register probably exist (ugh !)
  */
 static int __init psurge_quad_probe(void)
@@ -303,11 +303,7 @@
 	psurge_type = psurge_quad_probe();
 	if (psurge_type != PSURGE_DUAL) {
 		psurge_quad_init();
-		/* I believe we could "count" CPUs by counting 1 bits
-		 * in procbits on a quad board. For now, we assume 4,
-		 * non-present CPUs will just be seen as "stuck".
-		 * (hope they are the higher-numbered ones -- paulus)
-		 */
+		/* All released cards using this HW design have 4 CPUs */
 		ncpus = 4;
 	} else {
 		iounmap((void *) quad_base);
@@ -424,11 +420,10 @@
 		break;
 	case MSG_ALL_BUT_SELF:
 		openpic_cause_IPI(msg,
-       			0xffffffff & ~(1 << smp_hw_index[smp_processor_id()])); 
-
+				  0xffffffff & ~(1 << smp_processor_id()));
 		break;
 	default:
-		openpic_cause_IPI(msg, smp_hw_index[1<<target]);
+		openpic_cause_IPI(msg, 1<<target);
 		break;
 	}
 }
@@ -437,27 +432,14 @@
 smp_core99_probe(void)
 {
 	struct device_node *cpus;
-	int *pp;
 	int i, ncpus = 1;
 
 	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-#if 0	/* Paulus method.. doesn't seem to work on earlier dual G4's??*/
-	cpus = find_devices("cpus");
-	if (cpus != 0) {
-		pp = (int *) get_property(cpus, "#cpus", NULL);
-		if (pp != NULL)
-			ncpus = *pp;
-	}
-#else	/* My original method -- Troy <hozer@drgw.net> */
-	
 	cpus = find_type_devices("cpu");
-	if (cpus){
-		for ( ncpus = 1; cpus->next; cpus = cpus->next ){
-					ncpus++;
-		}
-	}
-#endif
-	printk("smp_core99_probe: OF reports %d cpus\n", ncpus);
+	if (cpus)
+		while ((cpus = cpus->next) != NULL)
+			++ncpus;
+	printk("smp_core99_probe: found %d cpus\n", ncpus);
 	if (ncpus > 1) {
 		openpic_request_IPIs();
 		for (i = 1; i < ncpus; ++i)
@@ -1010,6 +992,9 @@
 
 	/* Setup CPU 0 last (important) */
 	smp_ops->setup_cpu(0);
+	
+	if (smp_num_cpus < 2)
+		smp_tb_synchronized = 1;
 }
 
 void __init smp_software_tb_sync(int cpu)
@@ -1027,17 +1012,6 @@
 	register unsigned long start = 0;
 	register unsigned long stop = 0;
 	register unsigned long temp = 0;
-	
-	if (smp_num_cpus < 2) {
-		smp_tb_synchronized = 1;
-		return;
-	}
-
-	/* This code need fixing on >2 CPUs --BenH/paulus */
-	if (smp_num_cpus > 2) {
-		smp_tb_synchronized = 0;
-		return;
-	}
 
 	set_tb(0, 0);
 
@@ -1107,6 +1081,7 @@
 	if (ppc_md.progress) ppc_md.progress("smp_commence", 0x370);
 	wmb();
 	smp_commenced = 1;
+
 	/* if the smp_ops->setup_cpu function has not already synched the
 	 * timebases with a nicer hardware-based method, do so now
 	 *
@@ -1117,9 +1092,9 @@
 	 * since if this code runs pretty early and needs all cpus that
 	 * reported in in smp_callin_map to be working
 	 *
-	 * NOTE2: this code doesn't seem to work on > 2 cpus. -- paulus
+	 * NOTE2: this code doesn't seem to work on > 2 cpus. -- paulus/BenH
 	 */
-	if (!smp_tb_synchronized) {
+	if (!smp_tb_synchronized && smp_num_cpus == 2) {
 		unsigned long flags;
 		__save_and_cli(flags);	
 		smp_software_tb_sync(0);
@@ -1142,7 +1117,7 @@
 	while(!smp_commenced)
 		barrier();
 	/* see smp_commence for more info */
-	if (!smp_tb_synchronized){
+	if (!smp_tb_synchronized && smp_num_cpus == 2) {
 		smp_software_tb_sync(cpu);
 	}
 	__sti();
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/softemu8xx.c linux/arch/ppc/kernel/softemu8xx.c
--- v2.4.2/linux/arch/ppc/kernel/softemu8xx.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/softemu8xx.c	Sat Mar  3 10:52:14 2001
@@ -75,12 +75,12 @@
 		sdisp = (instword & 0xffff);
 		ea = (uint *)(regs->gpr[idxreg] + sdisp);
 		if (copy_from_user(ip, ea, sizeof(double)))
-			retval = EFAULT;
+			retval = -EFAULT;
 		break;
 		
 	case LFDU:
 		if (copy_from_user(ip, ea, sizeof(double)))
-			retval = EFAULT;
+			retval = -EFAULT;
 		else
 			regs->gpr[idxreg] = (uint)ea;
 		break;
@@ -88,7 +88,7 @@
 		sdisp = (instword & 0xffff);
 		ea = (uint *)(regs->gpr[idxreg] + sdisp);
 		if (copy_from_user(ip, ea, sizeof(float)))
-			retval = EFAULT;
+			retval = -EFAULT;
 		break;
 	case STFD:
 		/* this is a 16 bit quantity that is sign extended
@@ -97,12 +97,12 @@
 		sdisp = (instword & 0xffff);
 		ea = (uint *)(regs->gpr[idxreg] + sdisp);
 		if (copy_to_user(ea, ip, sizeof(double)))
-			retval = EFAULT;
+			retval = -EFAULT;
 		break;
 
 	case STFDU:
 		if (copy_to_user(ea, ip, sizeof(double)))
-			retval = EFAULT;
+			retval = -EFAULT;
 		else
 			regs->gpr[idxreg] = (uint)ea;
 		break;
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.4.2/linux/arch/ppc/kernel/syscalls.c	Sun Sep 17 09:48:07 2000
+++ linux/arch/ppc/kernel/syscalls.c	Mon Mar 19 12:35:09 2001
@@ -198,9 +198,9 @@
 			goto out;
 	}
 	
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	ret = do_mmap(file, addr, len, prot, flags, offset);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if (file)
 		fput(file);
 out:
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.4.2/linux/arch/ppc/kernel/time.c	Sat Feb  3 19:51:23 2001
+++ linux/arch/ppc/kernel/time.c	Sat Mar  3 10:52:14 2001
@@ -67,6 +67,8 @@
 
 #include <asm/time.h>
 
+unsigned long disarm_decr[NR_CPUS];
+
 #ifdef CONFIG_SMP
 extern void smp_local_timer_interrupt(struct pt_regs *);
 extern int smp_tb_synchronized;
@@ -147,7 +149,6 @@
 	
 	if (!user_mode(regs))
 		ppc_do_profile(instruction_pointer(regs));
-
 	do { 
 		jiffy_stamp += tb_ticks_per_jiffy;
 	  	if (smp_processor_id()) continue;
@@ -184,7 +185,8 @@
 		}
 		write_unlock(&xtime_lock);
 	} while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0);
-	set_dec(next_dec);
+	if ( !disarm_decr[smp_processor_id()] )
+		set_dec(next_dec);
 	last_jiffy_stamp(cpu) = jiffy_stamp;
 
 #ifdef CONFIG_SMP
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.4.2/linux/arch/ppc/kernel/traps.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/ppc/kernel/traps.c	Sat Mar  3 10:52:14 2001
@@ -237,7 +237,7 @@
 		return retval;
 
 	if (get_user(instword, (uint *)(regs->nip)))
-		return EFAULT;
+		return -EFAULT;
 
 	/* Emulate the mfspr rD, PVR.
 	 */
@@ -281,7 +281,7 @@
 		/* Try to emulate it if we should. */
 		int errcode;
 		if ((errcode = emulate_instruction(regs))) {
-			if (errcode == EFAULT)
+			if (errcode == -EFAULT)
 				_exception(SIGBUS, regs);
 			else
 				_exception(SIGILL, regs);
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.4.2/linux/arch/ppc/mm/fault.c	Sat Feb  3 19:51:24 2001
+++ linux/arch/ppc/mm/fault.c	Mon Mar 19 12:35:09 2001
@@ -99,7 +99,7 @@
 		bad_page_fault(regs, address, SIGSEGV);
 		return;
 	}
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -159,7 +159,7 @@
                 goto out_of_memory;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	/*
 	 * keep track of tlb+htab misses that are good addrs but
 	 * just need pte's created via handle_mm_fault()
@@ -169,7 +169,7 @@
 	return;
 
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	pte_errors++;	
 
 	/* User mode accesses cause a SIGSEGV */
@@ -190,7 +190,7 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
@@ -198,7 +198,7 @@
 	return;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRERR;
@@ -276,7 +276,7 @@
 	
 	pte = va_to_pte(address);
 	if (pte)
-		return(((unsigned long)(pte_val(*pte)) & PAGE_MASK) | (address & ~(PAGE_MASK-1)));
+		return(((unsigned long)(pte_val(*pte)) & PAGE_MASK) | (address & ~(PAGE_MASK)));
 	return (0);
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.4.2/linux/arch/ppc/mm/init.c	Sat Feb  3 19:51:24 2001
+++ linux/arch/ppc/mm/init.c	Sat Mar  3 10:52:14 2001
@@ -889,13 +889,14 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
+	printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+
 	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 ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 }
 #endif
 
diff -u --recursive --new-file v2.4.2/linux/arch/ppc/treeboot/mkevimg linux/arch/ppc/treeboot/mkevimg
--- v2.4.2/linux/arch/ppc/treeboot/mkevimg	Mon May 15 14:53:30 2000
+++ linux/arch/ppc/treeboot/mkevimg	Sat Mar  3 10:52:14 2001
@@ -431,7 +431,7 @@
 
   close(BOOT);
 
-  print("\nBoot image file \"$ofile\" built successfuly.\n\n");
+  print("\nBoot image file \"$ofile\" built successfully.\n\n");
 
   exit(0);
 }
diff -u --recursive --new-file v2.4.2/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- v2.4.2/linux/arch/s390/kernel/entry.S	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390/kernel/entry.S	Fri Mar  2 11:12:06 2001
@@ -687,7 +687,7 @@
         lr      %r3,%r8
         la      %r0,0x7f
         nr      %r3,%r0           # clear per-event-bit
-        be      BASED(pgm_dn)     # none of Martins exceptions occured bypass
+        be      BASED(pgm_dn)     # none of Martins exceptions occurred bypass
         l       %r9,BASED(.Ljump_table)
         sll     %r3,2
         l       %r9,0(%r3,%r9)    # load address of handler routine
diff -u --recursive --new-file v2.4.2/linux/arch/s390/kernel/sys_s390.c linux/arch/s390/kernel/sys_s390.c
--- v2.4.2/linux/arch/s390/kernel/sys_s390.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390/kernel/sys_s390.c	Mon Mar 19 12:35:11 2001
@@ -61,9 +61,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c
--- v2.4.2/linux/arch/s390/mm/fault.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390/mm/fault.c	Mon Mar 19 12:35:11 2001
@@ -122,7 +122,7 @@
 	 * task's user address space, so we search the VMAs
 	 */
 
-        down(&mm->mmap_sem);
+        down_read(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
         if (!vma)
@@ -173,7 +173,7 @@
 		goto out_of_memory;
 	}
 
-        up(&mm->mmap_sem);
+        up_read(&mm->mmap_sem);
         return;
 
 /*
@@ -181,7 +181,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-        up(&mm->mmap_sem);
+        up_read(&mm->mmap_sem);
 
         /* User mode accesses just cause a SIGSEGV */
         if (psw_mask & PSW_PROBLEM_STATE) {
@@ -240,14 +240,14 @@
  * us unable to handle the page fault gracefully.
 */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (psw_mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c
--- v2.4.2/linux/arch/s390/tools/dasdfmt/dasdfmt.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.c	Fri Mar  2 11:12:06 2001
@@ -477,7 +477,7 @@
 
 	rc=stat(dev_name,&stat_buf);
 	if (rc) {
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occured during stat: " \
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
 			"%s\n",prog_name,strerror(errno));
 	} else {
 		if (!S_ISBLK(stat_buf.st_mode))
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/binfmt_elf32.c linux/arch/s390x/kernel/binfmt_elf32.c
--- v2.4.2/linux/arch/s390x/kernel/binfmt_elf32.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390x/kernel/binfmt_elf32.c	Mon Mar 19 12:35:11 2001
@@ -193,11 +193,11 @@
 	if(!addr)
 		addr = 0x40000000;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	map_addr = do_mmap(filep, ELF_PAGESTART(addr),
 			   eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
 			   eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return(map_addr);
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S
--- v2.4.2/linux/arch/s390x/kernel/entry.S	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390x/kernel/entry.S	Fri Mar  2 11:12:06 2001
@@ -724,7 +724,7 @@
         stosm   48(%r15),0x03     # reenable interrupts
 	lghi    %r3,0x7f
         nr      %r3,%r8           # clear per-event-bit & move to r3
-        je      pgm_dn            # none of Martins exceptions occured bypass
+        je      pgm_dn            # none of Martins exceptions occurred bypass
         sll     %r3,3
         larl    %r9,pgm_check_table
         lg      %r9,0(%r3,%r9)    # load address of handler routine
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/exec32.c linux/arch/s390x/kernel/exec32.c
--- v2.4.2/linux/arch/s390x/kernel/exec32.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390x/kernel/exec32.c	Thu Mar 22 09:25:21 2001
@@ -54,7 +54,7 @@
 	if (!mpnt) 
 		return -ENOMEM; 
 	
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	{
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -73,12 +73,11 @@
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			current->mm->rss++;
 			put_dirty_page(current,page,stack_base);
 		}
 		stack_base += PAGE_SIZE;
 	}
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	
 	return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c
--- v2.4.2/linux/arch/s390x/kernel/linux32.c	Wed Feb 21 18:20:14 2001
+++ linux/arch/s390x/kernel/linux32.c	Mon Mar 19 12:35:11 2001
@@ -4184,9 +4184,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/kernel/sys_s390.c linux/arch/s390x/kernel/sys_s390.c
--- v2.4.2/linux/arch/s390x/kernel/sys_s390.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/s390x/kernel/sys_s390.c	Mon Mar 19 12:35:11 2001
@@ -61,9 +61,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c
--- v2.4.2/linux/arch/s390x/mm/fault.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/s390x/mm/fault.c	Mon Mar 19 12:35:11 2001
@@ -122,7 +122,7 @@
 	 * task's user address space, so we search the VMAs
 	 */
 
-        down(&mm->mmap_sem);
+        down_read(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
         if (!vma) {
@@ -176,7 +176,7 @@
 		goto out_of_memory;
 	}
 
-        up(&mm->mmap_sem);
+        up_read(&mm->mmap_sem);
         return;
 
 /*
@@ -184,7 +184,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-        up(&mm->mmap_sem);
+        up_read(&mm->mmap_sem);
 
         /* User mode accesses just cause a SIGSEGV */
         if (psw_mask & PSW_PROBLEM_STATE) {
@@ -243,14 +243,14 @@
  * us unable to handle the page fault gracefully.
 */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (psw_mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/s390x/tools/dasdfmt/dasdfmt.c linux/arch/s390x/tools/dasdfmt/dasdfmt.c
--- v2.4.2/linux/arch/s390x/tools/dasdfmt/dasdfmt.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/s390x/tools/dasdfmt/dasdfmt.c	Fri Mar  2 11:12:06 2001
@@ -477,7 +477,7 @@
 
 	rc=stat(dev_name,&stat_buf);
 	if (rc) {
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occured during stat: " \
+		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
 			"%s\n",prog_name,strerror(errno));
 	} else {
 		if (!S_ISBLK(stat_buf.st_mode))
diff -u --recursive --new-file v2.4.2/linux/arch/sh/kernel/sh_ksyms.c linux/arch/sh/kernel/sh_ksyms.c
--- v2.4.2/linux/arch/sh/kernel/sh_ksyms.c	Sat Feb  3 19:51:24 2001
+++ linux/arch/sh/kernel/sh_ksyms.c	Fri Mar  2 11:15:47 2001
@@ -77,3 +77,4 @@
 /* needed by some modules */
 EXPORT_SYMBOL(flush_dcache_page);
 #endif
+EXPORT_SYMBOL(flush_tlb_page);
diff -u --recursive --new-file v2.4.2/linux/arch/sh/kernel/sys_sh.c linux/arch/sh/kernel/sys_sh.c
--- v2.4.2/linux/arch/sh/kernel/sys_sh.c	Wed Jul  5 11:31:01 2000
+++ linux/arch/sh/kernel/sys_sh.c	Mon Mar 19 12:35:10 2001
@@ -57,9 +57,9 @@
 			goto out;
 	}
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	if (file)
 		fput(file);
diff -u --recursive --new-file v2.4.2/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.4.2/linux/arch/sh/mm/fault.c	Thu Jan  4 13:19:13 2001
+++ linux/arch/sh/mm/fault.c	Mon Mar 19 12:35:10 2001
@@ -109,7 +109,7 @@
 	if (in_interrupt() || !mm)
 		goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -151,7 +151,7 @@
 		goto out_of_memory;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
 /*
@@ -159,7 +159,7 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
 		tsk->thread.address = address;
@@ -208,14 +208,14 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (user_mode(regs))
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.4.2/linux/arch/sparc/kernel/sys_sparc.c	Mon Dec 11 12:37:02 2000
+++ linux/arch/sparc/kernel/sys_sparc.c	Mon Mar 19 12:35:09 2001
@@ -236,9 +236,9 @@
 	if (flags & MAP_SHARED)
 		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
 
@@ -284,7 +284,7 @@
 	if (old_len > TASK_SIZE - PAGE_SIZE ||
 	    new_len > TASK_SIZE - PAGE_SIZE)
 		goto out;
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	vma = find_vma(current->mm, addr);
 	if (vma && (vma->vm_flags & VM_SHARED))
 		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
@@ -309,7 +309,7 @@
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
 	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 out:
 	return ret;       
 }
diff -u --recursive --new-file v2.4.2/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.4.2/linux/arch/sparc/kernel/sys_sunos.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Mar 19 12:35:09 2001
@@ -116,9 +116,9 @@
 	}
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	retval = do_mmap(file, addr, len, prot, flags, off);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if(!ret_type)
 		retval = ((retval < PAGE_OFFSET) ? 0 : retval);
 
@@ -145,7 +145,7 @@
 	unsigned long rlim;
 	unsigned long newbrk, oldbrk;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	if(ARCH_SUN4C_SUN4) {
 		if(brk >= 0x20000000 && brk < 0xe0000000) {
 			goto out;
@@ -208,7 +208,7 @@
 	do_brk(oldbrk, newbrk-oldbrk);
 	retval = 0;
 out:
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return retval;
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.4.2/linux/arch/sparc/mm/fault.c	Mon Jan  1 10:37:41 2001
+++ linux/arch/sparc/mm/fault.c	Mon Mar 19 12:35:09 2001
@@ -224,7 +224,7 @@
         if (in_interrupt() || !mm)
                 goto no_context;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	/*
 	 * The kernel referencing a bad kernel pointer can lock up
@@ -274,7 +274,7 @@
 	default:
 		goto out_of_memory;
 	}
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 
 	/*
@@ -282,7 +282,7 @@
 	 * Fix it, but check if it's kernel or user first..
 	 */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
@@ -338,14 +338,14 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
 	if (from_user)
 		do_exit(SIGKILL);
 	goto no_context;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRERR;
@@ -479,7 +479,7 @@
 	printk("wf<pid=%d,wr=%d,addr=%08lx>\n",
 	       tsk->pid, write, address);
 #endif
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if(!vma)
 		goto bad_area;
@@ -500,10 +500,10 @@
 	}
 	if (!handle_mm_fault(mm, vma, address, write))
 		goto do_sigbus;
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return;
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 #if 0
 	printk("Window whee %s [%d]: segfaults at %08lx\n",
 	       tsk->comm, tsk->pid, address);
@@ -518,7 +518,7 @@
 	return;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	info.si_signo = SIGBUS;
 	info.si_errno = 0;
 	info.si_code = BUS_ADRERR;
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.4.2/linux/arch/sparc64/config.in	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/config.in	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.130 2001/01/18 04:47:44 davem Exp $
+# $Id: config.in,v 1.133 2001/03/07 00:44:36 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -165,12 +165,14 @@
    dep_tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
 
    if [ "$CONFIG_PCI" != "n" ]; then
-      dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
-      if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-	 bool '  Enable tagged command queueing (TCQ) by default' CONFIG_AIC7XXX_TAGGED_QUEUEING
-	 int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
-  	 bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
-	 int  '  Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
+      source drivers/scsi/aic7xxx/Config.in
+      if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
+         dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI
+         if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "n" ]; then
+            bool '  Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+            int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE 8
+            bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_OLD_PROC_STATS
+         fi
       fi
       dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
       dep_tristate 'SYM53C8XX SCSI support' CONFIG_SCSI_SYM53C8XX $CONFIG_SCSI
@@ -196,8 +198,6 @@
    endmenu
 fi
 endmenu
-
-source drivers/message/fusion/Config.in
 
 source drivers/fc4/Config.in
 
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.4.2/linux/arch/sparc64/defconfig	Sat Feb  3 19:51:24 2001
+++ linux/arch/sparc64/defconfig	Tue Mar  6 22:44:16 2001
@@ -151,7 +151,6 @@
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
 # CONFIG_BLK_DEV_LVM is not set
-# CONFIG_LVM_PROC_FS is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
 
@@ -305,10 +304,12 @@
 CONFIG_SCSI_SUNESP=y
 CONFIG_SCSI_QLOGICPTI=m
 CONFIG_SCSI_AIC7XXX=m
-CONFIG_AIC7XXX_TAGGED_QUEUEING=y
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_PROC_STATS=y
-CONFIG_AIC7XXX_RESET_DELAY=5
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY=5000
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
+CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
+CONFIG_AIC7XXX_OLD_PROC_STATS=y
 CONFIG_SCSI_NCR53C8XX=m
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.4.2/linux/arch/sparc64/kernel/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/arch/sparc64/kernel/Makefile	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.63 2000/12/14 22:57:25 davem Exp $
+# $Id: Makefile,v 1.64 2001/02/28 05:59:45 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -27,7 +27,7 @@
 		   power.o sbus.o iommu_common.o sparc64_ksyms.o
 
 obj-$(CONFIG_PCI)	 += ebus.o pci_common.o pci_iommu.o \
-			    pci_psycho.o pci_sabre.o 
+			    pci_psycho.o pci_sabre.o pci_schizo.o
 obj-$(CONFIG_SMP)	 += smp.o trampoline.o
 obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o
 obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.4.2/linux/arch/sparc64/kernel/binfmt_aout32.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Mon Mar 19 12:35:10 2001
@@ -277,24 +277,24 @@
 			goto beyond_if;
 		}
 
-	        down(&current->mm->mmap_sem);
+	        down_write(&current->mm->mmap_sem);
 		error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 			PROT_READ | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 			fd_offset);
-	        up(&current->mm->mmap_sem);
+	        up_write(&current->mm->mmap_sem);
 
 		if (error != N_TXTADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
 
-	        down(&current->mm->mmap_sem);
+	        down_write(&current->mm->mmap_sem);
  		error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
-	        up(&current->mm->mmap_sem);
+	        up_write(&current->mm->mmap_sem);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -368,12 +368,12 @@
 	start_addr =  ex.a_entry & 0xfffff000;
 
 	/* Now use mmap to map the library into memory. */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
 			PROT_READ | PROT_WRITE | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
 			N_TXTOFF(ex));
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	retval = error;
 	if (error != start_addr)
 		goto out;
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.4.2/linux/arch/sparc64/kernel/cpu.c	Mon May  8 22:00:01 2000
+++ linux/arch/sparc64/kernel/cpu.c	Tue Mar  6 22:44:16 2001
@@ -34,6 +34,7 @@
   { 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
+  { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
   { 0x17, 0x14, 0, "UltraSparc III integrated FPU"},
 };
 
@@ -44,7 +45,8 @@
   { 0x22, 0x10, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x12, "TI UltraSparc IIi"},
-  { 0x17, 0x14, "TI UltraSparc III (Cheetah)"},  /* A guess... */
+  { 0x17, 0x13, "TI UltraSparc IIe"},
+  { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.4.2/linux/arch/sparc64/kernel/ebus.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/ebus.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.54 2001/02/13 01:16:44 davem Exp $
+/* $Id: ebus.c,v 1.57 2001/02/28 03:28:55 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -159,7 +159,7 @@
 			struct pci_controller_info *p = pbm->parent;
 
 			if (ebus_intmap_match(dev->bus, preg, &irqs[i]) != -1) {
-				dev->irqs[i] = p->irq_build(p,
+				dev->irqs[i] = p->irq_build(pbm,
 							    dev->bus->self,
 							    irqs[i]);
 			} else {
@@ -222,7 +222,7 @@
 			struct pci_controller_info *p = pbm->parent;
 
 			if (ebus_intmap_match(dev->bus, &regs[0], &irqs[i]) != -1) {
-				dev->irqs[i] = p->irq_build(p,
+				dev->irqs[i] = p->irq_build(pbm,
 							    dev->bus->self,
 							    irqs[i]);
 			} else {
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.4.2/linux/arch/sparc64/kernel/head.S	Mon May 22 09:50:54 2000
+++ linux/arch/sparc64/kernel/head.S	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.65 2000/05/09 17:40:13 davem Exp $
+/* $Id: head.S,v 1.67 2001/03/04 18:31:00 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,8 @@
 #include <asm/signal.h>
 #include <asm/processor.h>
 #include <asm/lsu.h>
+#include <asm/dcr.h>
+#include <asm/dcu.h>
 #include <asm/head.h>
 #include <asm/ttable.h>
 	
@@ -76,6 +78,138 @@
 	 * PROM entry point is on %o4
 	 */
 sparc64_boot:
+	rdpr	%ver, %g1
+	sethi	%hi(0x003e0014), %g5
+	srlx	%g1, 32, %g1
+	or	%g5, %lo(0x003e0014), %g5
+	cmp	%g1, %g5
+	bne,pt	%icc, spitfire_boot
+	 nop
+
+cheetah_boot:
+	mov	DCR_BPE | DCR_RPE | DCR_SI | DCR_MS, %g1
+	wr	%g1, %asr18
+
+	sethi	%uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	or	%g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sllx	%g5, 32, %g5
+	ldxa	[%g0] ASI_DCU_CONTROL_REG, %g1
+	or	%g1, %g5, %g1
+	stxa	%g5, [%g0] ASI_DCU_CONTROL_REG
+	membar	#Sync
+
+	wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+	wr	%g0, 0, %fprs
+
+	/* Just like for Spitfire, we probe itlb-2 for a mapping which
+	 * matches our current %pc.  We take the physical address in
+	 * that mapping and use it to make our own.
+	 */
+
+	/* %g5 holds the tlb data */
+        sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+        sllx    %g5, 32, %g5
+        or      %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+	/* Put PADDR tlb data mask into %g3. */
+	sethi	%uhi(_PAGE_PADDR), %g3
+	or	%g3, %ulo(_PAGE_PADDR), %g3
+	sllx	%g3, 32, %g3
+	sethi	%hi(_PAGE_PADDR), %g7
+	or	%g7, %lo(_PAGE_PADDR), %g7
+	or	%g3, %g7, %g3
+
+	set	2 << 16, %l0		/* TLB entry walker. */
+	set	0x1fff, %l2		/* Page mask. */
+	rd	%pc, %l3
+	andn	%l3, %l2, %g2		/* vaddr comparator */
+
+1:	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
+	membar	#Sync
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g2
+	be,pn	%xcc, cheetah_got_tlbentry
+	 nop
+	and	%l0, (127 << 3), %g1
+	cmp	%g1, (127 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+cheetah_got_tlbentry:
+	ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
+	membar	#Sync
+	and	%g1, %g3, %g1
+	sub	%g1, %g2, %g1
+	or	%g5, %g1, %g5
+
+	/* Clear out any KERNBASE area entries. */
+	set	2 << 16, %l0
+	sethi	%hi(KERNBASE), %g3
+	sethi	%hi(KERNBASE<<1), %g7
+	mov	TLB_TAG_ACCESS, %l7
+
+	/* First, check ITLB */
+1:	ldxa	[%l0] ASI_ITLB_TAG_READ, %g1
+	membar	#Sync
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	 cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_IMMU
+	membar	#Sync
+	stxa	%g0, [%l0] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+
+2:	and	%l0, (127 << 3), %g1
+	cmp	%g1, (127 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+	/* Next, check DTLB */
+	set	2 << 16, %l0
+1:	ldxa	[%l0] ASI_DTLB_TAG_READ, %g1
+	membar	#Sync
+	andn	%g1, %l2, %g1
+	cmp	%g1, %g3
+	blu,pn	%xcc, 2f
+	 cmp	%g1, %g7
+	bgeu,pn	%xcc, 2f
+	 nop
+	stxa	%g0, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	
+2:	and	%l0, (511 << 3), %g1
+	cmp	%g1, (511 << 3)
+	blu,pt	%xcc, 1b
+	 add	%l0, (1 << 3), %l0
+
+	/* Now lock the TTE we created into ITLB-0 and DTLB-0,
+	 * entry 15.
+	 */
+	sethi	%hi(KERNBASE), %g3
+	set	(0 << 16) | (15 << 3), %g7
+	stxa	%g3, [%l7] ASI_DMMU
+	membar	#Sync
+	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS
+	membar	#Sync
+	stxa	%g3, [%l7] ASI_IMMU
+	membar	#Sync
+	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
+	membar	#Sync
+	flush	%g3
+	membar	#Sync
+	ba,pt	%xcc, 1f
+	 nop
+
+1:	set	sun4u_init, %g2
+	jmpl    %g2 + %g0, %g0
+	 nop
+
+spitfire_boot:
 	/* Typically PROM has already enabled both MMU's and both on-chip
 	 * caches, but we do it here anyway just to be paranoid.
 	 */
@@ -93,7 +227,7 @@
 	wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
 	wr	%g0, 0, %fprs
 
-create_mappings:
+spitfire_create_mappings:
 	/* %g5 holds the tlb data */
         sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
         sllx    %g5, 32, %g5
@@ -104,11 +238,11 @@
 	 */
 
 	/* Put PADDR tlb data mask into %g3. */
-	sethi	%uhi(_PAGE_PADDR), %g3
-	or	%g3, %ulo(_PAGE_PADDR), %g3
+	sethi	%uhi(_PAGE_PADDR_SF), %g3
+	or	%g3, %ulo(_PAGE_PADDR_SF), %g3
 	sllx	%g3, 32, %g3
-	sethi	%hi(_PAGE_PADDR), %g7
-	or	%g7, %lo(_PAGE_PADDR), %g7
+	sethi	%hi(_PAGE_PADDR_SF), %g7
+	or	%g7, %lo(_PAGE_PADDR_SF), %g7
 	or	%g3, %g7, %g3
 
 	/* Walk through entire ITLB, looking for entry which maps
@@ -126,13 +260,14 @@
 	nop
 	andn	%g1, %l2, %g1		/* Get vaddr */
 	cmp	%g1, %g2
-	be,a,pn	%xcc, got_tlbentry
+	be,a,pn	%xcc, spitfire_got_tlbentry
 	 ldxa	[%l0] ASI_ITLB_DATA_ACCESS, %g1
+	/* XXX Spitfire dependency... */
 	cmp	%l0, (63 << 3)
 	blu,pt	%xcc, 1b
 	 add	%l0, (1 << 3), %l0
 
-got_tlbentry:
+spitfire_got_tlbentry:
 	/* Nops here again, perhaps Cheetah/Blackbird are better behaved... */
 	nop
 	nop
@@ -165,6 +300,7 @@
 	stxa	%g0, [%l7] ASI_IMMU
 	stxa	%g0, [%l0] ASI_ITLB_DATA_ACCESS
 2:
+	/* XXX Spitfire dependency... */
 	cmp	%l0, (63 << 3)
 	blu,pt	%xcc, 1b
 	 add	%l0, (1 << 3), %l0
@@ -187,6 +323,7 @@
 	stxa	%g0, [%l7] ASI_DMMU
 	stxa	%g0, [%l0] ASI_DTLB_DATA_ACCESS
 2:
+	/* XXX Spitfire dependency... */
 	cmp	%l0, (63 << 3)
 	blu,pt	%xcc, 1b
 	 add	%l0, (1 << 3), %l0
@@ -199,6 +336,7 @@
 	 */
 
 	sethi	%hi(KERNBASE), %g3
+	/* XXX Spitfire dependency... */
 	mov	(63 << 3), %g7
 	stxa	%g3, [%l7] ASI_DMMU		/* KERNBASE into TLB TAG	*/
 	stxa	%g5, [%g7] ASI_DTLB_DATA_ACCESS	/* TTE into TLB DATA		*/
@@ -236,6 +374,7 @@
 	stxa	%g3, [%g2] ASI_IMMU
 	stxa	%g3, [%g2] ASI_DMMU
 
+	/* XXX Spitfire dependency... */
 	mov	(63 << 3), %g7
 	ldxa	[%g7] ASI_ITLB_DATA_ACCESS, %g1
 	andn	%g1, (_PAGE_G), %g1
@@ -342,12 +481,10 @@
 	/* Set fixed globals used by dTLB miss handler. */
 #define KERN_HIGHBITS		((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#ifdef THIS_IS_CHEETAH
-#error Dave, make sure you took care of other issues in rest of sparc64 code...
-#define VPTE_BASE		0xffe0000000000000
-#else /* Spitfire/Blackbird */
-#define VPTE_BASE		0xfffffffe00000000
-#endif
+
+#define VPTE_BASE_CHEETAH	0xffe0000000000000
+#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
+
 	mov	TSB_REG, %g1
 	stxa	%g0, [%g1] ASI_DMMU
 	membar	#Sync
@@ -356,9 +493,25 @@
 	or	%g2, %ulo(KERN_HIGHBITS), %g2
 	sllx	%g2, 32, %g2
 	or	%g2, KERN_LOWBITS, %g2
-	sethi	%uhi(VPTE_BASE), %g3
-	or	%g3, %ulo(VPTE_BASE), %g3
-	sllx	%g3, 32, %g3
+
+	rdpr		%ver, %g3
+	sethi		%hi(0x003e0014), %g7
+	srlx		%g3, 32, %g3
+	or		%g7, %lo(0x003e0014), %g7
+	cmp		%g3, %g7
+	bne,pt		%icc, 1f
+	 nop
+
+	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
+	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
+	ba,pt		%xcc, 2f
+	sllx		%g3, 32, %g3
+1:
+	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
+	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
+	sllx		%g3, 32, %g3
+
+2:
 	clr	%g7
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.4.2/linux/arch/sparc64/kernel/ioctl32.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Mar 12 18:11:56 2001
@@ -3331,6 +3331,7 @@
 COMPATIBLE_IOCTL(PPPIOCCONNECT)
 COMPATIBLE_IOCTL(PPPIOCDISCONN)
 COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+COMPATIBLE_IOCTL(PPPIOCGCHAN)
 /* PPPOX */
 COMPATIBLE_IOCTL(PPPOEIOCSFWD);
 COMPATIBLE_IOCTL(PPPOEIOCDFWD);
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.4.2/linux/arch/sparc64/kernel/pci.c	Sat Feb  3 19:51:24 2001
+++ linux/arch/sparc64/kernel/pci.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.21 2001/01/10 18:22:59 davem Exp $
+/* $Id: pci.c,v 1.22 2001/02/28 05:59:45 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -78,9 +78,7 @@
 /* Probe for all PCI controllers in the system. */
 extern void sabre_init(int);
 extern void psycho_init(int);
-#if 0
 extern void schizo_init(int);
-#endif
 
 static struct {
 	char *model_name;
@@ -89,11 +87,9 @@
 	{ "SUNW,sabre", sabre_init },
 	{ "pci108e,a000", sabre_init },
 	{ "SUNW,psycho", psycho_init },
-	{ "pci108e,8000", psycho_init }
-#if 0
+	{ "pci108e,8000", psycho_init },
 	{ "SUNW,schizo", schizo_init },
 	{ "pci108e,8001", schizo_init }
-#endif
 };
 #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
 				  sizeof(pci_controller_table[0]))
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.4.2/linux/arch/sparc64/kernel/pci_common.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/pci_common.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.13 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_common.c,v 1.14 2001/02/28 03:28:55 davem Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -560,19 +560,19 @@
 
 	/* Fully specified already? */
 	if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) {
-		pdev->irq = p->irq_build(p, pdev, prom_irq);
+		pdev->irq = p->irq_build(pbm, pdev, prom_irq);
 		goto have_irq;
 	}
 
 	/* An onboard device? (bit 5 set) */
 	if ((prom_irq & PCI_IRQ_INO) & 0x20) {
-		pdev->irq = p->irq_build(p, pdev, (portid << 6 | prom_irq));
+		pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
 		goto have_irq;
 	}
 
 	/* Can we find a matching entry in the interrupt-map? */
 	if (pci_intmap_match(pdev, &prom_irq)) {
-		pdev->irq = p->irq_build(p, pdev, (portid << 6) | prom_irq);
+		pdev->irq = p->irq_build(pbm, pdev, (portid << 6) | prom_irq);
 		goto have_irq;
 	}
 
@@ -609,7 +609,7 @@
 		}
 		slot = slot << 2;
 
-		pdev->irq = p->irq_build(p, pdev,
+		pdev->irq = p->irq_build(pbm, pdev,
 					 ((portid << 6) & PCI_IRQ_IGN) |
 					 (bus | slot | line));
 	}
@@ -632,17 +632,11 @@
 		pci_fixup_irq(pbm, pci_bus_b(walk));
 }
 
-#undef DEBUG_BUSMASTERING
-
 static void pdev_setup_busmastering(struct pci_dev *pdev, int is_66mhz)
 {
 	u16 cmd;
 	u8 hdr_type, min_gnt, ltimer;
 
-#ifdef DEBUG_BUSMASTERING
-	printk("PCI: Checking DEV(%s), ", pdev->name);
-#endif
-
 	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
 	cmd |= PCI_COMMAND_MASTER;
 	pci_write_config_word(pdev, PCI_COMMAND, cmd);
@@ -652,43 +646,28 @@
 	 * mastering so we have nothing to do here.
 	 */
 	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-	if ((cmd & PCI_COMMAND_MASTER) == 0) {
-#ifdef DEBUG_BUSMASTERING
-		printk("no bus mastering...\n");
-#endif
+	if ((cmd & PCI_COMMAND_MASTER) == 0)
 		return;
-	}
 
 	/* Set correct cache line size, 64-byte on all
 	 * Sparc64 PCI systems.  Note that the value is
 	 * measured in 32-bit words.
 	 */
-#ifdef DEBUG_BUSMASTERING
-	printk("set cachelinesize, ");
-#endif
 	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
 			      64 / sizeof(u32));
 
 	pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr_type);
 	hdr_type &= ~0x80;
-	if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
-#ifdef DEBUG_BUSMASTERING
-		printk("hdr_type=%x, exit\n", hdr_type);
-#endif
+	if (hdr_type != PCI_HEADER_TYPE_NORMAL)
 		return;
-	}
 
 	/* If the latency timer is already programmed with a non-zero
 	 * value, assume whoever set it (OBP or whoever) knows what
 	 * they are doing.
 	 */
 	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &ltimer);
-	if (ltimer != 0) {
-#ifdef DEBUG_BUSMASTERING
-		printk("ltimer was %x, exit\n", ltimer);
-#endif
+	if (ltimer != 0)
 		return;
-	}
 
 	/* XXX Since I'm tipping off the min grant value to
 	 * XXX choose a suitable latency timer value, I also
@@ -738,9 +717,6 @@
 	}
 
 	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, ltimer);
-#ifdef DEBUG_BUSMASTERING
-	printk("set ltimer to %x\n", ltimer);
-#endif
 }
 
 void pci_determine_66mhz_disposition(struct pci_pbm_info *pbm,
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.4.2/linux/arch/sparc64/kernel/pci_psycho.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.19 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_psycho.c,v 1.21 2001/02/28 03:28:55 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -72,7 +72,7 @@
  * ---------------------------------------------------------
  */
 #define PSYCHO_CONFIG_BASE(PBM)	\
-	((PBM)->parent->config_space | (1UL << 24))
+	((PBM)->config_space | (1UL << 24))
 #define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)	\
 	(((unsigned long)(BUS)   << 16) |	\
 	 ((unsigned long)(DEVFN) << 8)  |	\
@@ -376,10 +376,11 @@
 	return ret;
 }
 
-static unsigned int __init psycho_irq_build(struct pci_controller_info *p,
+static unsigned int __init psycho_irq_build(struct pci_pbm_info *pbm,
 					    struct pci_dev *pdev,
 					    unsigned int ino)
 {
+	struct pci_controller_info *p = pbm->parent;
 	struct ino_bucket *bucket;
 	unsigned long imap, iclr;
 	unsigned long imap_off, iclr_off;
@@ -1002,12 +1003,13 @@
 #define PSYCHO_PCIERR_B_INO	0x31
 static void __init psycho_register_error_handlers(struct pci_controller_info *p)
 {
+	struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
 	unsigned long base = p->controller_regs;
 	unsigned int irq, portid = p->portid;
 	u64 tmp;
 
 	/* Build IRQs and register handlers. */
-	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO);
+	irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_UE_INO);
 	if (request_irq(irq, psycho_ue_intr,
 			SA_SHIRQ, "PSYCHO UE", p) < 0) {
 		prom_printf("PSYCHO%d: Cannot register UE interrupt.\n",
@@ -1015,7 +1017,7 @@
 		prom_halt();
 	}
 
-	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO);
+	irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_CE_INO);
 	if (request_irq(irq, psycho_ce_intr,
 			SA_SHIRQ, "PSYCHO CE", p) < 0) {
 		prom_printf("PSYCHO%d: Cannot register CE interrupt.\n",
@@ -1023,7 +1025,7 @@
 		prom_halt();
 	}
 
-	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO);
+	irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO);
 	if (request_irq(irq, psycho_pcierr_intr,
 			SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) {
 		prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n",
@@ -1031,7 +1033,7 @@
 		prom_halt();
 	}
 
-	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO);
+	irq = psycho_irq_build(pbm, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO);
 	if (request_irq(irq, psycho_pcierr_intr,
 			SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) {
 		prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n",
@@ -1574,8 +1576,10 @@
 	printk("PCI: Found PSYCHO, control regs at %016lx\n",
 	       p->controller_regs);
 
-	p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE;
-	printk("PSYCHO: PCI config space at %016lx\n", p->config_space);
+	p->pbm_A.config_space = p->pbm_B.config_space =
+		(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+	printk("PSYCHO: Shared PCI config space at %016lx\n",
+	       p->pbm_A.config_space);
 
 	/*
 	 * Psycho's PCI MEM space is mapped to a 2GB aligned area, so
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.4.2/linux/arch/sparc64/kernel/pci_sabre.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.23 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_sabre.c,v 1.25 2001/02/28 03:28:55 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -209,7 +209,7 @@
  * ---------------------------------------------------------
  */
 #define SABRE_CONFIG_BASE(PBM)	\
-	((PBM)->parent->config_space | (1UL << 24))
+	((PBM)->config_space | (1UL << 24))
 #define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
 	(((unsigned long)(BUS)   << 16) |	\
 	 ((unsigned long)(DEVFN) << 8)  |	\
@@ -604,10 +604,11 @@
 	return ret;
 }
 
-static unsigned int __init sabre_irq_build(struct pci_controller_info *p,
+static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,
 					   struct pci_dev *pdev,
 					   unsigned int ino)
 {
+	struct pci_controller_info *p = pbm->parent;
 	struct ino_bucket *bucket;
 	unsigned long imap, iclr;
 	unsigned long imap_off, iclr_off;
@@ -961,6 +962,7 @@
 #define SABRE_PCIERR_INO	0x30
 static void __init sabre_register_error_handlers(struct pci_controller_info *p)
 {
+	struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
 	unsigned long base = p->controller_regs;
 	unsigned long irq, portid = p->portid;
 	u64 tmp;
@@ -973,7 +975,7 @@
 		    (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
 		     SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
 		     SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
-	irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_UE_INO);
+	irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO);
 	if (request_irq(irq, sabre_ue_intr,
 			SA_SHIRQ, "SABRE UE", p) < 0) {
 		prom_printf("SABRE%d: Cannot register UE interrupt.\n",
@@ -984,7 +986,7 @@
 	sabre_write(base + SABRE_CE_AFSR,
 		    (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
 		     SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
-	irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_CE_INO);
+	irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO);
 	if (request_irq(irq, sabre_ce_intr,
 			SA_SHIRQ, "SABRE CE", p) < 0) {
 		prom_printf("SABRE%d: Cannot register CE interrupt.\n",
@@ -992,7 +994,7 @@
 		prom_halt();
 	}
 
-	irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO);
+	irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO);
 	if (request_irq(irq, sabre_pcierr_intr,
 			SA_SHIRQ, "SABRE PCIERR", p) < 0) {
 		prom_printf("SABRE%d: Cannot register PciERR interrupt.\n",
@@ -1434,8 +1436,10 @@
 		     SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
 
 	/* Now map in PCI config space for entire SABRE. */
-	p->config_space = p->controller_regs + SABRE_CONFIGSPACE;
-	printk("SABRE: PCI config space at %016lx\n", p->config_space);
+	p->pbm_A.config_space = p->pbm_B.config_space =
+		(p->controller_regs + SABRE_CONFIGSPACE);
+	printk("SABRE: Shared PCI config space at %016lx\n",
+	       p->pbm_A.config_space);
 
 	err = prom_getproperty(pnode, "virtual-dma",
 			       (char *)&vdma[0], sizeof(vdma));
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- v2.4.2/linux/arch/sparc64/kernel/pci_schizo.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.3 2001/02/13 01:16:44 davem Exp $
+/* $Id: pci_schizo.c,v 1.8 2001/03/01 08:05:32 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -16,34 +16,240 @@
 
 #include "pci_impl.h"
 
+/* All SCHIZO registers are 64-bits.  The following accessor
+ * routines are how they are accessed.  The REG parameter
+ * is a physical address.
+ */
+#define schizo_read(__reg) \
+({	u64 __ret; \
+	__asm__ __volatile__("ldxa [%1] %2, %0" \
+			     : "=r" (__ret) \
+			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+			     : "memory"); \
+	__ret; \
+})
+#define schizo_write(__reg, __val) \
+	__asm__ __volatile__("stxa %0, [%1] %2" \
+			     : /* no outputs */ \
+			     : "r" (__val), "r" (__reg), \
+			       "i" (ASI_PHYS_BYPASS_EC_E))
+
+/* This is a convention that at least Excalibur and Merlin
+ * follow.  I suppose the SCHIZO used in Starcat and friends
+ * will do similar.
+ *
+ * The only way I could see this changing is if the newlink
+ * block requires more space in Schizo's address space than
+ * they predicted, thus requiring an address space reorg when
+ * the newer Schizo is taped out.
+ *
+ * These offsets look weird because I keep in p->controller_regs
+ * the second PROM register property minus 0x10000 which is the
+ * base of the Safari and UPA64S registers of SCHIZO.
+ */
+#define SCHIZO_PBM_A_REGS_OFF	(0x600000UL - 0x400000UL)
+#define SCHIZO_PBM_B_REGS_OFF	(0x700000UL - 0x400000UL)
+
+/* Streaming buffer control register. */
+#define SCHIZO_STRBUF_CTRL_LPTR    0x00000000000000f0UL /* LRU Lock Pointer */
+#define SCHIZO_STRBUF_CTRL_LENAB   0x0000000000000008UL /* LRU Lock Enable */
+#define SCHIZO_STRBUF_CTRL_RRDIS   0x0000000000000004UL /* Rerun Disable */
+#define SCHIZO_STRBUF_CTRL_DENAB   0x0000000000000002UL /* Diagnostic Mode Enable */
+#define SCHIZO_STRBUF_CTRL_ENAB    0x0000000000000001UL /* Streaming Buffer Enable */
+
+/* IOMMU control register. */
+#define SCHIZO_IOMMU_CTRL_RESV     0xfffffffff9000000 /* Reserved                      */
+#define SCHIZO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status      */
+#define SCHIZO_IOMMU_CTRL_XLTEERR  0x0000000001000000 /* Translation Error encountered */
+#define SCHIZO_IOMMU_CTRL_LCKEN    0x0000000000800000 /* Enable translation locking    */
+#define SCHIZO_IOMMU_CTRL_LCKPTR   0x0000000000780000 /* Translation lock pointer      */
+#define SCHIZO_IOMMU_CTRL_TSBSZ    0x0000000000070000 /* TSB Size                      */
+#define SCHIZO_IOMMU_TSBSZ_1K      0x0000000000000000 /* TSB Table 1024 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_2K      0x0000000000010000 /* TSB Table 2048 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_4K      0x0000000000020000 /* TSB Table 4096 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_8K      0x0000000000030000 /* TSB Table 8192 8-byte entries */
+#define SCHIZO_IOMMU_TSBSZ_16K     0x0000000000040000 /* TSB Table 16k 8-byte entries  */
+#define SCHIZO_IOMMU_TSBSZ_32K     0x0000000000050000 /* TSB Table 32k 8-byte entries  */
+#define SCHIZO_IOMMU_TSBSZ_64K     0x0000000000060000 /* TSB Table 64k 8-byte entries  */
+#define SCHIZO_IOMMU_TSBSZ_128K    0x0000000000070000 /* TSB Table 128k 8-byte entries */
+#define SCHIZO_IOMMU_CTRL_RESV2    0x000000000000fff8 /* Reserved                      */
+#define SCHIZO_IOMMU_CTRL_TBWSZ    0x0000000000000004 /* Assumed page size, 0=8k 1=64k */
+#define SCHIZO_IOMMU_CTRL_DENAB    0x0000000000000002 /* Diagnostic mode enable        */
+#define SCHIZO_IOMMU_CTRL_ENAB     0x0000000000000001 /* IOMMU Enable                  */
+
+/* Schizo config space address format is nearly identical to
+ * that of PSYCHO:
+ *
+ *  32             24 23 16 15    11 10       8 7   2  1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 0| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define SCHIZO_CONFIG_BASE(PBM)	((PBM)->config_space)
+#define SCHIZO_CONFIG_ENCODE(BUS, DEVFN, REG)	\
+	(((unsigned long)(BUS)   << 16) |	\
+	 ((unsigned long)(DEVFN) << 8)  |	\
+	 ((unsigned long)(REG)))
+
+static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm,
+				      unsigned char bus,
+				      unsigned int devfn,
+				      int where)
+{
+	if (!pbm)
+		return NULL;
+	return (void *)
+		(SCHIZO_CONFIG_BASE(pbm) |
+		 SCHIZO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+/* 4 slots on pbm A, and 6 slots on pbm B.  In both cases
+ * slot 0 is the SCHIZO host bridge itself.
+ */
+static int schizo_out_of_range(struct pci_pbm_info *pbm,
+			       unsigned char bus,
+			       unsigned char devfn)
+{
+	return ((pbm->parent == 0) ||
+		((pbm == &pbm->parent->pbm_B) &&
+		 (bus == pbm->pci_first_busno) &&
+		 PCI_SLOT(devfn) > 6) ||
+		((pbm == &pbm->parent->pbm_A) &&
+		 (bus == pbm->pci_first_busno) &&
+		 PCI_SLOT(devfn) > 4));
+}
+
+/* SCHIZO PCI configuration space accessors. */
+
 static int schizo_read_byte(struct pci_dev *dev, int where, u8 *value)
 {
-	/* IMPLEMENT ME */
+	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	u8 *addr;
+
+	*value = 0xff;
+	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (schizo_out_of_range(pbm, bus, devfn))
+		return PCIBIOS_SUCCESSFUL;
+	pci_config_read8(addr, value);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int schizo_read_word(struct pci_dev *dev, int where, u16 *value)
 {
-	/* IMPLEMENT ME */
+	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	u16 *addr;
+
+	*value = 0xffff;
+	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (schizo_out_of_range(pbm, bus, devfn))
+		return PCIBIOS_SUCCESSFUL;
+
+	if (where & 0x01) {
+		printk("pcibios_read_config_word: misaligned reg [%x]\n",
+		       where);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	pci_config_read16(addr, value);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int schizo_read_dword(struct pci_dev *dev, int where, u32 *value)
 {
-	/* IMPLEMENT ME */
+	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	u32 *addr;
+
+	*value = 0xffffffff;
+	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (schizo_out_of_range(pbm, bus, devfn))
+		return PCIBIOS_SUCCESSFUL;
+
+	if (where & 0x03) {
+		printk("pcibios_read_config_dword: misaligned reg [%x]\n",
+		       where);
+		return PCIBIOS_SUCCESSFUL;
+	}
+
+	pci_config_read32(addr, value);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int schizo_write_byte(struct pci_dev *dev, int where, u8 value)
 {
-	/* IMPLEMENT ME */
+	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	u8 *addr;
+
+	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (schizo_out_of_range(pbm, bus, devfn))
+		return PCIBIOS_SUCCESSFUL;
+
+	pci_config_write8(addr, value);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int schizo_write_word(struct pci_dev *dev, int where, u16 value)
 {
-	/* IMPLEMENT ME */
+	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	u16 *addr;
+
+	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (schizo_out_of_range(pbm, bus, devfn))
+		return PCIBIOS_SUCCESSFUL;
+
+	if (where & 0x01) {
+		printk("pcibios_write_config_word: misaligned reg [%x]\n",
+		       where);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	pci_config_write16(addr, value);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int schizo_write_dword(struct pci_dev *dev, int where, u32 value)
 {
-	/* IMPLEMENT ME */
+	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];
+	unsigned char bus = dev->bus->number;
+	unsigned int devfn = dev->devfn;
+	u32 *addr;
+
+	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
+	if (!addr)
+		return PCIBIOS_SUCCESSFUL;
+
+	if (schizo_out_of_range(pbm, bus, devfn))
+		return PCIBIOS_SUCCESSFUL;
+
+	if (where & 0x03) {
+		printk("pcibios_write_config_dword: misaligned reg [%x]\n",
+		       where);
+		return PCIBIOS_SUCCESSFUL;
+	}
+	pci_config_write32(addr, value);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static struct pci_ops schizo_ops = {
@@ -55,34 +261,1383 @@
 	schizo_write_dword
 };
 
-static void __init schizo_scan_bus(struct pci_controller_info *p)
+/* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the
+ * imap/iclr registers are per-PBM.
+ */
+#define SCHIZO_IMAP_BASE	0x1000UL
+#define SCHIZO_ICLR_BASE	0x1400UL
+
+static unsigned long schizo_imap_offset(unsigned long ino)
 {
-	/* IMPLEMENT ME */
+	return SCHIZO_IMAP_BASE + (ino * 8UL);
 }
 
-static unsigned int __init schizo_irq_build(struct pci_controller_info *p,
+static unsigned long schizo_iclr_offset(unsigned long ino)
+{
+	return SCHIZO_ICLR_BASE + (ino * 8UL);
+}
+
+/* PCI SCHIZO INO number to Sparc PIL level.  This table only matters for
+ * INOs which will not have an associated PCI device struct, ie. onboard
+ * EBUS devices and PCI controller internal error interrupts.
+ */
+static unsigned char schizo_pil_table[] = {
+/*0x00*/0, 0, 0, 0,	/* PCI slot 0  Int A, B, C, D */
+/*0x04*/0, 0, 0, 0,	/* PCI slot 1  Int A, B, C, D */
+/*0x08*/0, 0, 0, 0,	/* PCI slot 2  Int A, B, C, D */
+/*0x0c*/0, 0, 0, 0,	/* PCI slot 3  Int A, B, C, D */
+/*0x10*/0, 0, 0, 0,	/* PCI slot 4  Int A, B, C, D */
+/*0x14*/0, 0, 0, 0,	/* PCI slot 5  Int A, B, C, D */
+/*0x18*/0, 0, 0, 0,	/* PCI slot 6  Int A, B, C, D */
+/*0x1c*/8,		/* Parallel			*/
+/*0x1d*/0,		/* UNKNOWN			*/
+/*0x1e*/0,		/* UNKNOWN			*/
+/*0x1f*/0,		/* UNKNOWN			*/
+/*0x20*/13,		/* Audio Record			*/
+/*0x21*/14,		/* Audio Playback		*/
+/*0x22*/12,		/* Serial			*/
+/*0x23*/2,		/* EBUS I2C 			*/
+/*0x24*/10,		/* RTC Clock			*/
+/*0x25*/11,		/* Floppy			*/
+/*0x26*/0,		/* UNKNOWN			*/
+/*0x27*/0,		/* UNKNOWN			*/
+/*0x28*/0,		/* UNKNOWN			*/
+/*0x29*/0,		/* UNKNOWN			*/
+/*0x2a*/10,		/* UPA 1			*/
+/*0x2b*/10,		/* UPA 2			*/
+/*0x2c*/0,		/* UNKNOWN			*/
+/*0x2d*/0,		/* UNKNOWN			*/
+/*0x2e*/0,		/* UNKNOWN			*/
+/*0x2f*/0,		/* UNKNOWN			*/
+/*0x30*/15,		/* Uncorrectable ECC		*/
+/*0x31*/15,		/* Correctable ECC		*/
+/*0x32*/15,		/* PCI Bus A Error		*/
+/*0x33*/15,		/* PCI Bus B Error		*/
+/*0x34*/15,		/* Safari Bus Error		*/
+/*0x35*/0,		/* Reserved			*/
+/*0x36*/0,		/* Reserved			*/
+/*0x37*/0,		/* Reserved			*/
+/*0x38*/0,		/* Reserved for NewLink		*/
+/*0x39*/0,		/* Reserved for NewLink		*/
+/*0x3a*/0,		/* Reserved for NewLink		*/
+/*0x3b*/0,		/* Reserved for NewLink		*/
+/*0x3c*/0,		/* Reserved for NewLink		*/
+/*0x3d*/0,		/* Reserved for NewLink		*/
+/*0x3e*/0,		/* Reserved for NewLink		*/
+/*0x3f*/0,		/* Reserved for NewLink		*/
+};
+
+static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
+{
+	int ret;
+
+	ret = schizo_pil_table[ino];
+	if (ret == 0 && pdev == NULL) {
+		ret = 1;
+	} else if (ret == 0) {
+		switch ((pdev->class >> 16) & 0x0f) {
+		case PCI_BASE_CLASS_STORAGE:
+			ret = 4;
+
+		case PCI_BASE_CLASS_NETWORK:
+			ret = 6;
+
+		case PCI_BASE_CLASS_DISPLAY:
+			ret = 9;
+
+		case PCI_BASE_CLASS_MULTIMEDIA:
+		case PCI_BASE_CLASS_MEMORY:
+		case PCI_BASE_CLASS_BRIDGE:
+			ret = 10;
+
+		default:
+			ret = 1;
+		};
+	}
+
+	return ret;
+}
+
+static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
 					    struct pci_dev *pdev,
 					    unsigned int ino)
 {
-	/* IMPLEMENT ME */
+	struct pci_controller_info *p = pbm->parent;
+	struct ino_bucket *bucket;
+	unsigned long imap, iclr, pbm_off;
+	unsigned long imap_off, iclr_off;
+	int pil, inofixup = 0;
+
+	if (pbm == &p->pbm_A)
+		pbm_off = SCHIZO_PBM_A_REGS_OFF;
+	else
+		pbm_off = SCHIZO_PBM_B_REGS_OFF;
+
+	ino &= PCI_IRQ_INO;
+	imap_off = schizo_imap_offset(ino);
+
+	/* Now build the IRQ bucket. */
+	pil = schizo_ino_to_pil(pdev, ino);
+	imap = p->controller_regs + pbm_off + imap_off;
+	imap += 4;
+
+	iclr_off = schizo_iclr_offset(ino);
+	iclr = p->controller_regs + pbm_off + iclr_off;
+	iclr += 4;
+
+	if ((ino & 0x20) == 0)
+		inofixup = ino & 0x03;
+
+	bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+	bucket->flags |= IBF_PCI;
+
+	return __irq(bucket);
+}
+
+/* SCHIZO error handling support. */
+enum schizo_error_type {
+	UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
+};
+
+static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long stc_error_buf[128];
+static unsigned long stc_tag_buf[16];
+static unsigned long stc_line_buf[16];
+
+#define SCHIZO_STC_ERR	0xb800UL /* --> 0xba00 */
+#define SCHIZO_STC_TAG	0xba00UL /* --> 0xba80 */
+#define SCHIZO_STC_LINE	0xbb00UL /* --> 0xbb80 */
+
+#define SCHIZO_STCERR_WRITE	0x2UL
+#define SCHIZO_STCERR_READ	0x1UL
+
+#define SCHIZO_STCTAG_PPN	0x3fffffff00000000UL
+#define SCHIZO_STCTAG_VPN	0x00000000ffffe000UL
+#define SCHIZO_STCTAG_VALID	0x8000000000000000UL
+#define SCHIZO_STCTAG_READ	0x4000000000000000UL
+
+#define SCHIZO_STCLINE_LINDX	0x0000000007800000UL
+#define SCHIZO_STCLINE_SPTR	0x000000000007e000UL
+#define SCHIZO_STCLINE_LADDR	0x0000000000001fc0UL
+#define SCHIZO_STCLINE_EPTR	0x000000000000003fUL
+#define SCHIZO_STCLINE_VALID	0x0000000000600000UL
+#define SCHIZO_STCLINE_FOFN	0x0000000000180000UL
+
+static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
+					 enum schizo_error_type type)
+{
+	struct pci_controller_info *p = pbm->parent;
+	struct pci_strbuf *strbuf = &pbm->stc;
+	unsigned long regbase = p->controller_regs;
+	unsigned long err_base, tag_base, line_base;
+	u64 control;
+	char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B');
+	int i;
+
+	if (pbm == &p->pbm_A)
+		regbase += SCHIZO_PBM_A_REGS_OFF;
+	else
+		regbase += SCHIZO_PBM_B_REGS_OFF;
+
+	err_base = regbase + SCHIZO_STC_ERR;
+	tag_base = regbase + SCHIZO_STC_TAG;
+	line_base = regbase + SCHIZO_STC_LINE;
+
+	spin_lock(&stc_buf_lock);
+
+	/* This is __REALLY__ dangerous.  When we put the
+	 * streaming buffer into diagnostic mode to probe
+	 * it's tags and error status, we _must_ clear all
+	 * of the line tag valid bits before re-enabling
+	 * the streaming buffer.  If any dirty data lives
+	 * in the STC when we do this, we will end up
+	 * invalidating it before it has a chance to reach
+	 * main memory.
+	 */
+	control = schizo_read(strbuf->strbuf_control);
+	schizo_write(strbuf->strbuf_control,
+		     (control | SCHIZO_STRBUF_CTRL_DENAB));
+	for (i = 0; i < 128; i++) {
+		unsigned long val;
+
+		val = schizo_read(err_base + (i * 8UL));
+		schizo_write(err_base + (i * 8UL), 0UL);
+		stc_error_buf[i] = val;
+	}
+	for (i = 0; i < 16; i++) {
+		stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
+		stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
+		schizo_write(tag_base + (i * 8UL), 0UL);
+		schizo_write(line_base + (i * 8UL), 0UL);
+	}
+
+	/* OK, state is logged, exit diagnostic mode. */
+	schizo_write(strbuf->strbuf_control, control);
+
+	for (i = 0; i < 16; i++) {
+		int j, saw_error, first, last;
+
+		saw_error = 0;
+		first = i * 8;
+		last = first + 8;
+		for (j = first; j < last; j++) {
+			unsigned long errval = stc_error_buf[j];
+			if (errval != 0) {
+				saw_error++;
+				printk("SCHIZO%d: PBM-%c STC_ERR(%d)[wr(%d)rd(%d)]\n",
+				       p->index, pbm_name,
+				       j,
+				       (errval & SCHIZO_STCERR_WRITE) ? 1 : 0,
+				       (errval & SCHIZO_STCERR_READ) ? 1 : 0);
+			}
+		}
+		if (saw_error != 0) {
+			unsigned long tagval = stc_tag_buf[i];
+			unsigned long lineval = stc_line_buf[i];
+			printk("SCHIZO%d: PBM-%c STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n",
+			       p->index, pbm_name,
+			       i,
+			       ((tagval & SCHIZO_STCTAG_PPN) >> 19UL),
+			       (tagval & SCHIZO_STCTAG_VPN),
+			       ((tagval & SCHIZO_STCTAG_VALID) ? 1 : 0),
+			       ((tagval & SCHIZO_STCTAG_READ) ? 1 : 0));
+
+			/* XXX Should spit out per-bank error information... -DaveM */
+			printk("SCHIZO%d: PBM-%c STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
+			       "V(%d)FOFN(%d)]\n",
+			       p->index, pbm_name,
+			       i,
+			       ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL),
+			       ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL),
+			       ((lineval & SCHIZO_STCLINE_LADDR) >> 6UL),
+			       ((lineval & SCHIZO_STCLINE_EPTR) >> 0UL),
+			       ((lineval & SCHIZO_STCLINE_VALID) ? 1 : 0),
+			       ((lineval & SCHIZO_STCLINE_FOFN) ? 1 : 0));
+		}
+	}
+
+	spin_unlock(&stc_buf_lock);
+}
+
+/* IOMMU is per-PBM in Schizo, so interrogate both for anonymous
+ * controller level errors.
+ */
+
+#define SCHIZO_IOMMU_TAG	0xa580UL
+#define SCHIZO_IOMMU_DATA	0xa600UL
+
+#define SCHIZO_IOMMU_TAG_CTXT	0x0000001ffe000000UL
+#define SCHIZO_IOMMU_TAG_ERRSTS	0x0000000001800000UL
+#define SCHIZO_IOMMU_TAG_ERR	0x0000000000400000UL
+#define SCHIZO_IOMMU_TAG_WRITE	0x0000000000200000UL
+#define SCHIZO_IOMMU_TAG_STREAM	0x0000000000100000UL
+#define SCHIZO_IOMMU_TAG_SIZE	0x0000000000080000UL
+#define SCHIZO_IOMMU_TAG_VPAGE	0x000000000007ffffUL
+
+#define SCHIZO_IOMMU_DATA_VALID	0x0000000100000000UL
+#define SCHIZO_IOMMU_DATA_CACHE	0x0000000040000000UL
+#define SCHIZO_IOMMU_DATA_PPAGE	0x000000003fffffffUL
+
+static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
+					 enum schizo_error_type type)
+{
+	struct pci_controller_info *p = pbm->parent;
+	struct pci_iommu *iommu = pbm->iommu;
+	unsigned long iommu_tag[16];
+	unsigned long iommu_data[16];
+	unsigned long flags;
+	u64 control;
+	char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B');
+	int i;
+
+	spin_lock_irqsave(&iommu->lock, flags);
+	control = schizo_read(iommu->iommu_control);
+	if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
+		unsigned long base;
+		char *type_string;
+
+		/* Clear the error encountered bit. */
+		control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
+		schizo_write(iommu->iommu_control, control);
+
+		switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
+		case 0:
+			type_string = "Protection Error";
+			break;
+		case 1:
+			type_string = "Invalid Error";
+			break;
+		case 2:
+			type_string = "TimeOut Error";
+			break;
+		case 3:
+		default:
+			type_string = "ECC Error";
+			break;
+		};
+		printk("SCHIZO%d: PBM-%c IOMMU Error, type[%s]\n",
+		       p->index, pbm_name, type_string);
+
+		/* Put the IOMMU into diagnostic mode and probe
+		 * it's TLB for entries with error status.
+		 *
+		 * It is very possible for another DVMA to occur
+		 * while we do this probe, and corrupt the system
+		 * further.  But we are so screwed at this point
+		 * that we are likely to crash hard anyways, so
+		 * get as much diagnostic information to the
+		 * console as we can.
+		 */
+		schizo_write(iommu->iommu_control,
+			     control | SCHIZO_IOMMU_CTRL_DENAB);
+
+		base = p->controller_regs;
+		if (pbm == &p->pbm_A)
+			base += SCHIZO_PBM_A_REGS_OFF;
+		else
+			base += SCHIZO_PBM_B_REGS_OFF;
+
+		for (i = 0; i < 16; i++) {
+			iommu_tag[i] =
+				schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+			iommu_data[i] =
+				schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+
+			/* Now clear out the entry. */
+			schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
+			schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+		}
+
+		/* Leave diagnostic mode. */
+		schizo_write(iommu->iommu_control, control);
+
+		for (i = 0; i < 16; i++) {
+			unsigned long tag, data;
+
+			tag = iommu_tag[i];
+			if (!(tag & SCHIZO_IOMMU_TAG_ERR))
+				continue;
+
+			data = iommu_data[i];
+			switch((tag & SCHIZO_IOMMU_TAG_ERRSTS) >> 23UL) {
+			case 0:
+				type_string = "Protection Error";
+				break;
+			case 1:
+				type_string = "Invalid Error";
+				break;
+			case 2:
+				type_string = "TimeOut Error";
+				break;
+			case 3:
+			default:
+				type_string = "ECC Error";
+				break;
+			};
+			printk("SCHIZO%d: PBM-%c IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) "
+			       "sz(%dK) vpg(%08lx)]\n",
+			       p->index, pbm_name, i, type_string,
+			       (int)((tag & SCHIZO_IOMMU_TAG_CTXT) >> 25UL),
+			       ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0),
+			       ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0),
+			       ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8),
+			       (tag & SCHIZO_IOMMU_TAG_VPAGE) << PAGE_SHIFT);
+			printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
+			       p->index, pbm_name, i,
+			       ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0),
+			       ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0),
+			       (data & SCHIZO_IOMMU_DATA_PPAGE) << PAGE_SHIFT);
+		}
+	}
+	__schizo_check_stc_error_pbm(pbm, type);
+	spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void schizo_check_iommu_error(struct pci_controller_info *p,
+				     enum schizo_error_type type)
+{
+	schizo_check_iommu_error_pbm(&p->pbm_A, type);
+	schizo_check_iommu_error_pbm(&p->pbm_B, type);
+}
+
+/* Uncorrectable ECC error status gathering. */
+#define SCHIZO_UE_AFSR	0x10030UL
+#define SCHIZO_UE_AFAR	0x10038UL
+
+#define SCHIZO_UEAFSR_PPIO	0x8000000000000000UL
+#define SCHIZO_UEAFSR_PDRD	0x4000000000000000UL
+#define SCHIZO_UEAFSR_PDWR	0x2000000000000000UL
+#define SCHIZO_UEAFSR_SPIO	0x1000000000000000UL
+#define SCHIZO_UEAFSR_SDMA	0x0800000000000000UL
+#define SCHIZO_UEAFSR_ERRPNDG	0x0300000000000000UL
+#define SCHIZO_UEAFSR_BMSK	0x000003ff00000000UL
+#define SCHIZO_UEAFSR_QOFF	0x00000000c0000000UL
+#define SCHIZO_UEAFSR_AID	0x000000001f000000UL
+#define SCHIZO_UEAFSR_PARTIAL	0x0000000000800000UL
+#define SCHIZO_UEAFSR_OWNEDIN	0x0000000000400000UL
+#define SCHIZO_UEAFSR_MTAGSYND	0x00000000000f0000UL
+#define SCHIZO_UEAFSR_MTAG	0x000000000000e000UL
+#define SCHIZO_UEAFSR_ECCSYND	0x00000000000001ffUL
+
+static void schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pci_controller_info *p = dev_id;
+	unsigned long afsr_reg = p->controller_regs + SCHIZO_UE_AFSR;
+	unsigned long afar_reg = p->controller_regs + SCHIZO_UE_AFAR;
+	unsigned long afsr, afar, error_bits;
+	int reported, limit;
+
+	/* Latch uncorrectable error status. */
+	afar = schizo_read(afar_reg);
+
+	/* If either of the error pending bits are set in the
+	 * AFSR, the error status is being actively updated by
+	 * the hardware and we must re-read to get a clean value.
+	 */
+	limit = 1000;
+	do {
+		afsr = schizo_read(afsr_reg);
+	} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
+
+	/* Clear the primary/secondary error status bits. */
+	error_bits = afsr &
+		(SCHIZO_UEAFSR_PPIO | SCHIZO_UEAFSR_PDRD | SCHIZO_UEAFSR_PDWR |
+		 SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
+	schizo_write(afsr_reg, error_bits);
+
+	/* Log the error. */
+	printk("SCHIZO%d: Uncorrectable Error, primary error type[%s]\n",
+	       p->index,
+	       (((error_bits & SCHIZO_UEAFSR_PPIO) ?
+		 "PIO" :
+		 ((error_bits & SCHIZO_UEAFSR_PDRD) ?
+		  "DMA Read" :
+		  ((error_bits & SCHIZO_UEAFSR_PDWR) ?
+		   "DMA Write" : "???")))));
+	printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+	       p->index,
+	       (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
+	       (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
+	       (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
+	printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+	       p->index,
+	       (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
+	       (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
+	       (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
+	       (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
+	       (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
+	printk("SCHIZO%d: UE AFAR [%016lx]\n", p->index, afar);
+	printk("SCHIZO%d: UE Secondary errors [", p->index);
+	reported = 0;
+	if (afsr & SCHIZO_UEAFSR_SPIO) {
+		reported++;
+		printk("(PIO)");
+	}
+	if (afsr & SCHIZO_UEAFSR_SDMA) {
+		reported++;
+		printk("(DMA)");
+	}
+	if (!reported)
+		printk("(none)");
+	printk("]\n");
+
+	/* Interrogate IOMMU for error status. */
+	schizo_check_iommu_error(p, UE_ERR);
+}
+
+#define SCHIZO_CE_AFSR	0x10040UL
+#define SCHIZO_CE_AFAR	0x10048UL
+
+#define SCHIZO_CEAFSR_PPIO	0x8000000000000000UL
+#define SCHIZO_CEAFSR_PDRD	0x4000000000000000UL
+#define SCHIZO_CEAFSR_PDWR	0x2000000000000000UL
+#define SCHIZO_CEAFSR_SPIO	0x1000000000000000UL
+#define SCHIZO_CEAFSR_SDMA	0x0800000000000000UL
+#define SCHIZO_CEAFSR_ERRPNDG	0x0300000000000000UL
+#define SCHIZO_CEAFSR_BMSK	0x000003ff00000000UL
+#define SCHIZO_CEAFSR_QOFF	0x00000000c0000000UL
+#define SCHIZO_CEAFSR_AID	0x000000001f000000UL
+#define SCHIZO_CEAFSR_PARTIAL	0x0000000000800000UL
+#define SCHIZO_CEAFSR_OWNEDIN	0x0000000000400000UL
+#define SCHIZO_CEAFSR_MTAGSYND	0x00000000000f0000UL
+#define SCHIZO_CEAFSR_MTAG	0x000000000000e000UL
+#define SCHIZO_CEAFSR_ECCSYND	0x00000000000001ffUL
+
+static void schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pci_controller_info *p = dev_id;
+	unsigned long afsr_reg = p->controller_regs + SCHIZO_CE_AFSR;
+	unsigned long afar_reg = p->controller_regs + SCHIZO_CE_AFAR;
+	unsigned long afsr, afar, error_bits;
+	int reported, limit;
+
+	/* Latch error status. */
+	afar = schizo_read(afar_reg);
+
+	/* If either of the error pending bits are set in the
+	 * AFSR, the error status is being actively updated by
+	 * the hardware and we must re-read to get a clean value.
+	 */
+	limit = 1000;
+	do {
+		afsr = schizo_read(afsr_reg);
+	} while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
+
+	/* Clear primary/secondary error status bits. */
+	error_bits = afsr &
+		(SCHIZO_CEAFSR_PPIO | SCHIZO_CEAFSR_PDRD | SCHIZO_CEAFSR_PDWR |
+		 SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
+	schizo_write(afsr_reg, error_bits);
+
+	/* Log the error. */
+	printk("SCHIZO%d: Correctable Error, primary error type[%s]\n",
+	       p->index,
+	       (((error_bits & SCHIZO_CEAFSR_PPIO) ?
+		 "PIO" :
+		 ((error_bits & SCHIZO_CEAFSR_PDRD) ?
+		  "DMA Read" :
+		  ((error_bits & SCHIZO_CEAFSR_PDWR) ?
+		   "DMA Write" : "???")))));
+
+	/* XXX Use syndrome and afar to print out module string just like
+	 * XXX UDB CE trap handler does... -DaveM
+	 */
+	printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+	       p->index,
+	       (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
+	       (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
+	       (afsr & SCHIZO_UEAFSR_AID) >> 24UL);
+	printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+	       p->index,
+	       (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
+	       (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
+	       (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
+	       (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
+	       (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
+	printk("SCHIZO%d: CE AFAR [%016lx]\n", p->index, afar);
+	printk("SCHIZO%d: CE Secondary errors [", p->index);
+	reported = 0;
+	if (afsr & SCHIZO_CEAFSR_SPIO) {
+		reported++;
+		printk("(PIO)");
+	}
+	if (afsr & SCHIZO_CEAFSR_SDMA) {
+		reported++;
+		printk("(DMA)");
+	}
+	if (!reported)
+		printk("(none)");
+	printk("]\n");
+}
+
+#define SCHIZO_PCI_AFSR	0x2010UL
+#define SCHIZO_PCI_AFAR	0x2018UL
+
+#define SCHIZO_PCIAFSR_PMA	0x8000000000000000UL
+#define SCHIZO_PCIAFSR_PTA	0x4000000000000000UL
+#define SCHIZO_PCIAFSR_PRTRY	0x2000000000000000UL
+#define SCHIZO_PCIAFSR_PPERR	0x1000000000000000UL
+#define SCHIZO_PCIAFSR_PTTO	0x0800000000000000UL
+#define SCHIZO_PCIAFSR_PUNUS	0x0400000000000000UL
+#define SCHIZO_PCIAFSR_SMA	0x0200000000000000UL
+#define SCHIZO_PCIAFSR_STA	0x0100000000000000UL
+#define SCHIZO_PCIAFSR_SRTRY	0x0080000000000000UL
+#define SCHIZO_PCIAFSR_SPERR	0x0040000000000000UL
+#define SCHIZO_PCIAFSR_STTO	0x0020000000000000UL
+#define SCHIZO_PCIAFSR_SUNUS	0x0010000000000000UL
+#define SCHIZO_PCIAFSR_BMSK	0x000003ff00000000UL
+#define SCHIZO_PCIAFSR_BLK	0x0000000080000000UL
+#define SCHIZO_PCIAFSR_CFG	0x0000000040000000UL
+#define SCHIZO_PCIAFSR_MEM	0x0000000020000000UL
+#define SCHIZO_PCIAFSR_IO	0x0000000010000000UL
+
+static void schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pci_pbm_info *pbm = dev_id;
+	struct pci_controller_info *p = pbm->parent;
+	unsigned long afsr_reg, afar_reg, base;
+	unsigned long afsr, afar, error_bits;
+	int reported;
+	char pbm_name;
+
+	base = p->controller_regs;
+	if (pbm == &pbm->parent->pbm_A) {
+		base += SCHIZO_PBM_A_REGS_OFF;
+		pbm_name = 'A';
+	} else {
+		base += SCHIZO_PBM_B_REGS_OFF;
+		pbm_name = 'B';
+	}
+
+	afsr_reg = base + SCHIZO_PCI_AFSR;
+	afar_reg = base + SCHIZO_PCI_AFAR;
+
+	/* Latch error status. */
+	afar = schizo_read(afar_reg);
+	afsr = schizo_read(afsr_reg);
+
+	/* Clear primary/secondary error status bits. */
+	error_bits = afsr &
+		(SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+		 SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+		 SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+		 SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+		 SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+		 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
+	schizo_write(afsr_reg, error_bits);
+
+	/* Log the error. */
+	printk("SCHIZO%d: PBM-%c PCI Error, primary error type[%s]\n",
+	       p->index, pbm_name,
+	       (((error_bits & SCHIZO_PCIAFSR_PMA) ?
+		 "Master Abort" :
+		 ((error_bits & SCHIZO_PCIAFSR_PTA) ?
+		  "Target Abort" :
+		  ((error_bits & SCHIZO_PCIAFSR_PRTRY) ?
+		   "Excessive Retries" :
+		   ((error_bits & SCHIZO_PCIAFSR_PPERR) ?
+		    "Parity Error" :
+		    ((error_bits & SCHIZO_PCIAFSR_PTTO) ?
+		     "Timeout" :
+		     ((error_bits & SCHIZO_PCIAFSR_PUNUS) ?
+		      "Bus Unusable" : "???"))))))));
+	printk("SCHIZO%d: PBM-%c bytemask[%04lx] was_block(%d) space(%s)\n",
+	       p->index, pbm_name,
+	       (afsr & SCHIZO_PCIAFSR_BMSK) >> 32UL,
+	       (afsr & SCHIZO_PCIAFSR_BLK) ? 1 : 0,
+	       ((afsr & SCHIZO_PCIAFSR_CFG) ?
+		"Config" :
+		((afsr & SCHIZO_PCIAFSR_MEM) ?
+		 "Memory" :
+		 ((afsr & SCHIZO_PCIAFSR_IO) ?
+		  "I/O" : "???"))));
+	printk("SCHIZO%d: PBM-%c PCI AFAR [%016lx]\n",
+	       p->index, pbm_name, afar);
+	printk("SCHIZO%d: PBM-%c PCI Secondary errors [",
+	       p->index, pbm_name);
+	reported = 0;
+	if (afsr & SCHIZO_PCIAFSR_SMA) {
+		reported++;
+		printk("(Master Abort)");
+	}
+	if (afsr & SCHIZO_PCIAFSR_STA) {
+		reported++;
+		printk("(Target Abort)");
+	}
+	if (afsr & SCHIZO_PCIAFSR_SRTRY) {
+		reported++;
+		printk("(Excessive Retries)");
+	}
+	if (afsr & SCHIZO_PCIAFSR_SPERR) {
+		reported++;
+		printk("(Parity Error)");
+	}
+	if (afsr & SCHIZO_PCIAFSR_STTO) {
+		reported++;
+		printk("(Timeout)");
+	}
+	if (afsr & SCHIZO_PCIAFSR_SUNUS) {
+		reported++;
+		printk("(Bus Unusable)");
+	}
+	if (!reported)
+		printk("(none)");
+	printk("]\n");
+
+	/* For the error types shown, scan PBM's PCI bus for devices
+	 * which have logged that error type.
+	 */
+
+	/* If we see a Target Abort, this could be the result of an
+	 * IOMMU translation error of some sort.  It is extremely
+	 * useful to log this information as usually it indicates
+	 * a bug in the IOMMU support code or a PCI device driver.
+	 */
+	if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
+		schizo_check_iommu_error(p, PCI_ERR);
+		pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+	}
+	if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
+		pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+
+	/* For excessive retries, PSYCHO/PBM will abort the device
+	 * and there is no way to specifically check for excessive
+	 * retries in the config space status registers.  So what
+	 * we hope is that we'll catch it via the master/target
+	 * abort events.
+	 */
+
+	if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
+		pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+}
+
+#define SCHIZO_SAFARI_ERRLOG	0x10018UL
+
+#define SAFARI_ERRLOG_ERROUT	0x8000000000000000UL
+
+#define SAFARI_ERROR_BADCMD	0x4000000000000000UL
+#define SAFARI_ERROR_SSMDIS	0x2000000000000000UL
+#define SAFARI_ERROR_BADMA	0x1000000000000000UL
+#define SAFARI_ERROR_BADMB	0x0800000000000000UL
+#define SAFARI_ERROR_BADMC	0x0400000000000000UL
+#define SAFARI_ERROR_CPU1PS	0x0000000000002000UL
+#define SAFARI_ERROR_CPU1PB	0x0000000000001000UL
+#define SAFARI_ERROR_CPU0PS	0x0000000000000800UL
+#define SAFARI_ERROR_CPU0PB	0x0000000000000400UL
+#define SAFARI_ERROR_CIQTO	0x0000000000000200UL
+#define SAFARI_ERROR_LPQTO	0x0000000000000100UL
+#define SAFARI_ERROR_SFPQTO	0x0000000000000080UL
+#define SAFARI_ERROR_UFPQTO	0x0000000000000040UL
+#define SAFARI_ERROR_APERR	0x0000000000000020UL
+#define SAFARI_ERROR_UNMAP	0x0000000000000010UL
+#define SAFARI_ERROR_BUSERR	0x0000000000000004UL
+#define SAFARI_ERROR_TIMEOUT	0x0000000000000002UL
+#define SAFARI_ERROR_ILL	0x0000000000000001UL
+
+/* We only expect UNMAP errors here.  The rest of the Safari errors
+ * are marked fatal and thus cause a system reset.
+ */
+static void schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct pci_controller_info *p = dev_id;
+	u64 errlog;
+
+	errlog = schizo_read(p->controller_regs + SCHIZO_SAFARI_ERRLOG);
+	schizo_write(p->controller_regs + SCHIZO_SAFARI_ERRLOG,
+		     errlog & ~(SAFARI_ERRLOG_ERROUT));
+
+	if (!(errlog & SAFARI_ERROR_UNMAP)) {
+		printk("SCHIZO%d: Unexpected Safari error interrupt, errlog[%016lx]\n",
+		       p->index, errlog);
+		return;
+	}
+
+	printk("SCHIZO%d: Safari interrupt, UNMAPPED error, interrogating IOMMUs.\n",
+	       p->index);
+	schizo_check_iommu_error(p, SAFARI_ERR);
+}
+
+/* Nearly identical to PSYCHO equivalents... */
+#define SCHIZO_ECC_CTRL		0x10020UL
+#define  SCHIZO_ECCCTRL_EE	 0x8000000000000000 /* Enable ECC Checking */
+#define  SCHIZO_ECCCTRL_UE	 0x4000000000000000 /* Enable UE Interrupts */
+#define  SCHIZO_ECCCTRL_CE	 0x2000000000000000 /* Enable CE INterrupts */
+
+#define SCHIZO_SAFARI_ERRCTRL	0x10008UL
+#define  SCHIZO_SAFERRCTRL_EN	 0x8000000000000000UL
+#define SCHIZO_SAFARI_IRQCTRL	0x10010UL
+#define  SCHIZO_SAFIRQCTRL_EN	 0x8000000000000000UL
+
+#define SCHIZO_UE_INO		0x30 /* Uncorrectable ECC error */
+#define SCHIZO_CE_INO		0x31 /* Correctable ECC error */
+#define SCHIZO_PCIERR_A_INO	0x32 /* PBM A PCI bus error */
+#define SCHIZO_PCIERR_B_INO	0x33 /* PBM B PCI bus error */
+#define SCHIZO_SERR_INO		0x34 /* Safari interface error */
+
+#define SCHIZO_PCIA_CTRL	(SCHIZO_PBM_A_REGS_OFF + 0x2000UL)
+#define SCHIZO_PCIB_CTRL	(SCHIZO_PBM_B_REGS_OFF + 0x2000UL)
+#define SCHIZO_PCICTRL_SBH_ERR	(1UL << 35UL)
+#define SCHIZO_PCICTRL_SERR	(1UL << 34UL)
+#define SCHIZO_PCICTRL_SBH_INT	(1UL << 18UL)
+#define SCHIZO_PCICTRL_EEN	(1UL << 17UL)
+
+/* XXX It is not entirely clear if I need to enable the PCI controller interrupts
+ * XXX in both PBMs, the documentation is very vague about this point.  For now
+ * XXX I'll just enable it on PBM A but this needs to be verified! -DaveM
+ */
+static void __init schizo_register_error_handlers(struct pci_controller_info *p)
+{
+	struct pci_pbm_info *pbm = &p->pbm_A; /* XXX verify me XXX */
+	unsigned long base = p->controller_regs;
+	unsigned int irq, portid = p->portid;
+	u64 tmp;
+
+	/* Build IRQs and register handlers. */
+	irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_UE_INO);
+	if (request_irq(irq, schizo_ue_intr,
+			SA_SHIRQ, "SCHIZO UE", p) < 0) {
+		prom_printf("SCHIZO%d: Cannot register UE interrupt.\n",
+			    p->index);
+		prom_halt();
+	}
+
+	irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_CE_INO);
+	if (request_irq(irq, schizo_ce_intr,
+			SA_SHIRQ, "SCHIZO CE", p) < 0) {
+		prom_printf("SCHIZO%d: Cannot register CE interrupt.\n",
+			    p->index);
+		prom_halt();
+	}
+
+	irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_PCIERR_A_INO);
+	if (request_irq(irq, schizo_pcierr_intr,
+			SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_A) < 0) {
+		prom_printf("SCHIZO%d(PBMA): Cannot register PciERR interrupt.\n",
+			    p->index);
+		prom_halt();
+	}
+
+	irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
+	if (request_irq(irq, schizo_pcierr_intr,
+			SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) {
+		prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n",
+			    p->index);
+		prom_halt();
+	}
+
+	irq = schizo_irq_build(pbm, NULL, (portid << 6) | SCHIZO_SERR_INO);
+	if (request_irq(irq, schizo_safarierr_intr,
+			SA_SHIRQ, "SCHIZO SERR", p) < 0) {
+		prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n",
+			    p->index);
+		prom_halt();
+	}
+
+	/* Enable UE and CE interrupts for controller. */
+	schizo_write(base + SCHIZO_ECC_CTRL,
+		     (SCHIZO_ECCCTRL_EE |
+		      SCHIZO_ECCCTRL_UE |
+		      SCHIZO_ECCCTRL_CE));
+
+	/* Enable PCI Error interrupts and clear error
+	 * bits for each PBM.
+	 *
+	 * XXX More error bits should be cleared, this is
+	 * XXX just the stuff which is identical on Psycho. -DaveM
+	 */
+	tmp = schizo_read(base + SCHIZO_PCIA_CTRL);
+	tmp |= (SCHIZO_PCICTRL_SBH_ERR |
+		SCHIZO_PCICTRL_SERR |
+		SCHIZO_PCICTRL_SBH_INT |
+		SCHIZO_PCICTRL_EEN);
+	schizo_write(base + SCHIZO_PCIA_CTRL, tmp);
+
+	tmp = schizo_read(base + SCHIZO_PCIB_CTRL);
+	tmp |= (SCHIZO_PCICTRL_SBH_ERR |
+		SCHIZO_PCICTRL_SERR |
+		SCHIZO_PCICTRL_SBH_INT |
+		SCHIZO_PCICTRL_EEN);
+	schizo_write(base + SCHIZO_PCIB_CTRL, tmp);
+
+	/* Make all Safari error conditions fatal except unmapped errors
+	 * which we make generate interrupts.
+	 */
+	schizo_write(base + SCHIZO_SAFARI_ERRCTRL,
+		     (SCHIZO_SAFERRCTRL_EN |
+		      (SAFARI_ERROR_BADCMD | SAFARI_ERROR_SSMDIS |
+		       SAFARI_ERROR_BADMA | SAFARI_ERROR_BADMB |
+		       SAFARI_ERROR_BADMC | SAFARI_ERROR_CPU1PS |
+		       SAFARI_ERROR_CPU1PB | SAFARI_ERROR_CPU0PS |
+		       SAFARI_ERROR_CPU0PB | SAFARI_ERROR_CIQTO |
+		       SAFARI_ERROR_LPQTO | SAFARI_ERROR_SFPQTO |
+		       SAFARI_ERROR_UFPQTO | SAFARI_ERROR_APERR |
+		       SAFARI_ERROR_BUSERR | SAFARI_ERROR_TIMEOUT |
+		       SAFARI_ERROR_ILL)));
+
+	schizo_write(base + SCHIZO_SAFARI_IRQCTRL,
+		     (SCHIZO_SAFIRQCTRL_EN | (SAFARI_ERROR_UNMAP)));
+}
+
+/* We have to do the config space accesses by hand, thus... */
+#define PBM_BRIDGE_BUS		0x40
+#define PBM_BRIDGE_SUBORDINATE	0x41
+static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno)
+{
+	u8 *addr, busno;
+	int nbus;
+
+	busno = pci_highest_busnum;
+	nbus = pbm->pci_last_busno - pbm->pci_first_busno;
+
+	addr = schizo_pci_config_mkaddr(pbm, orig_busno,
+					0, PBM_BRIDGE_BUS);
+	pci_config_write8(addr, busno);
+	addr = schizo_pci_config_mkaddr(pbm, busno,
+					0, PBM_BRIDGE_SUBORDINATE);
+	pci_config_write8(addr, busno + nbus);
+
+	pbm->pci_first_busno = busno;
+	pbm->pci_last_busno = busno + nbus;
+	pci_highest_busnum = busno + nbus + 1;
+
+	do {
+		pci_bus2pbm[busno++] = pbm;
+	} while (nbus--);
+}
+
+/* We have to do the config space accesses by hand here since
+ * the pci_bus2pbm array is not ready yet.
+ */
+static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm,
+					   u8 busno)
+{
+	u32 devfn, l, class;
+	u8 hdr_type;
+	int is_multi = 0;
+
+	for(devfn = 0; devfn < 0xff; ++devfn) {
+		u32 *dwaddr;
+		u8 *baddr;
+
+		if (PCI_FUNC(devfn) != 0 && is_multi == 0)
+			continue;
+
+		/* Anything there? */
+		dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID);
+		l = 0xffffffff;
+		pci_config_read32(dwaddr, &l);
+		if (l == 0xffffffff || l == 0x00000000 ||
+		    l == 0x0000ffff || l == 0xffff0000) {
+			is_multi = 0;
+			continue;
+		}
+
+		baddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE);
+		pci_config_read8(baddr, &hdr_type);
+		if (PCI_FUNC(devfn) == 0)
+			is_multi = hdr_type & 0x80;
+
+		dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION);
+		class = 0xffffffff;
+		pci_config_read32(dwaddr, &class);
+		if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+			u32 buses = 0xffffffff;
+
+			dwaddr = schizo_pci_config_mkaddr(pbm, busno, devfn,
+							  PCI_PRIMARY_BUS);
+			pci_config_read32(dwaddr, &buses);
+			pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff);
+			buses &= 0xff000000;
+			pci_config_write32(dwaddr, buses);
+		}
+	}
+}
+
+static void __init pbm_bridge_reconfigure(struct pci_controller_info *p)
+{
+	struct pci_pbm_info *pbm;
+	u8 *addr;
+
+	/* Clear out primary/secondary/subordinate bus numbers on
+	 * all PCI-to-PCI bridges under each PBM.  The generic bus
+	 * probing will fix them up.
+	 */
+	pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno);
+	pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno);
+
+	/* Move PBM A out of the way. */
+	pbm = &p->pbm_A;
+	addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+					0, PBM_BRIDGE_BUS);
+	pci_config_write8(addr, 0xff);
+	addr = schizo_pci_config_mkaddr(pbm, 0xff,
+					0, PBM_BRIDGE_SUBORDINATE);
+	pci_config_write8(addr, 0xff);
+
+	/* Now we can safely renumber both PBMs. */
+	pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno);
+	pbm_renumber(&p->pbm_A, 0xff);
+}
+
+static void __init pbm_config_busmastering(struct pci_pbm_info *pbm)
+{
+	u8 *addr;
+
+	/* Set cache-line size to 64 bytes, this is actually
+	 * a nop but I do it for completeness.
+	 */
+	addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+					0, PCI_CACHE_LINE_SIZE);
+	pci_config_write8(addr, 64 / sizeof(u32));
+
+	/* Set PBM latency timer to 64 PCI clocks. */
+	addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+					0, PCI_LATENCY_TIMER);
+	pci_config_write8(addr, 64);
+}
+
+static void __init pbm_scan_bus(struct pci_controller_info *p,
+				struct pci_pbm_info *pbm)
+{
+	pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno,
+				    p->pci_ops,
+				    pbm);
+	pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
+	pci_record_assignments(pbm, pbm->pci_bus);
+	pci_assign_unassigned(pbm, pbm->pci_bus);
+	pci_fixup_irq(pbm, pbm->pci_bus);
+	pci_determine_66mhz_disposition(pbm, pbm->pci_bus);
+	pci_setup_busmastering(pbm, pbm->pci_bus);
+}
+
+static void __init schizo_scan_bus(struct pci_controller_info *p)
+{
+	pbm_bridge_reconfigure(p);
+	pbm_config_busmastering(&p->pbm_B);
+	p->pbm_B.is_66mhz_capable = 0;
+	pbm_config_busmastering(&p->pbm_A);
+	p->pbm_A.is_66mhz_capable = 1;
+	pbm_scan_bus(p, &p->pbm_B);
+	pbm_scan_bus(p, &p->pbm_A);
+
+	/* After the PCI bus scan is complete, we can register
+	 * the error interrupt handlers.
+	 */
+	schizo_register_error_handlers(p);
 }
 
 static void __init schizo_base_address_update(struct pci_dev *pdev, int resource)
 {
-	/* IMPLEMENT ME */
+	struct pcidev_cookie *pcp = pdev->sysdata;
+	struct pci_pbm_info *pbm = pcp->pbm;
+	struct resource *res, *root;
+	u32 reg;
+	int where, size, is_64bit;
+
+	res = &pdev->resource[resource];
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+
+	is_64bit = 0;
+	if (res->flags & IORESOURCE_IO)
+		root = &pbm->io_space;
+	else {
+		root = &pbm->mem_space;
+		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)
+		    == PCI_BASE_ADDRESS_MEM_TYPE_64)
+			is_64bit = 1;
+	}
+
+	size = res->end - res->start;
+	pci_read_config_dword(pdev, where, &reg);
+	reg = ((reg & size) |
+	       (((u32)(res->start - root->start)) & ~size));
+	pci_write_config_dword(pdev, where, reg);
+
+	/* This knows that the upper 32-bits of the address
+	 * must be zero.  Our PCI common layer enforces this.
+	 */
+	if (is_64bit)
+		pci_write_config_dword(pdev, where + 4, 0);
 }
 
 static void __init schizo_resource_adjust(struct pci_dev *pdev,
 					  struct resource *res,
 					  struct resource *root)
 {
-	/* IMPLEMENT ME */
+	res->start += root->start;
+	res->end += root->start;
+}
+
+/* Interrogate Safari match/mask registers to figure out where
+ * PCI MEM, I/O, and Config space are for this PCI bus module.
+ */
+
+#define SCHIZO_PCI_A_MEM_MATCH		0x00040UL
+#define SCHIZO_PCI_A_MEM_MASK		0x00048UL
+#define SCHIZO_PCI_A_IO_MATCH		0x00050UL
+#define SCHIZO_PCI_A_IO_MASK		0x00058UL
+#define SCHIZO_PCI_B_MEM_MATCH		0x00060UL
+#define SCHIZO_PCI_B_MEM_MASK		0x00068UL
+#define SCHIZO_PCI_B_IO_MATCH		0x00070UL
+#define SCHIZO_PCI_B_IO_MASK		0x00078UL
+
+/* VAL must be non-zero. */
+static unsigned long strip_to_lowest_bit_set(unsigned long val)
+{
+	unsigned long tmp;
+
+	tmp = 1UL;
+	while (!(tmp & val))
+		tmp <<= 1UL;
+
+	return tmp;
+}
+
+static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,
+					  int is_pbm_a, unsigned long reg_base)
+{
+	u64 mem_match, mem_mask;
+	u64 io_match;
+	u64 long a, b;
+
+	if (is_pbm_a) {
+		mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH;
+		io_match = reg_base + SCHIZO_PCI_A_IO_MATCH;
+	} else {
+		mem_match = reg_base + SCHIZO_PCI_B_MEM_MATCH;
+		io_match = reg_base + SCHIZO_PCI_B_IO_MATCH;
+	}
+	mem_mask = mem_match + 0x8UL;
+
+	a = schizo_read(mem_match) & ~0x8000000000000000UL;
+	b = strip_to_lowest_bit_set(schizo_read(mem_mask));
+
+	/* It should be 2GB in size. */
+	pbm->mem_space.start = a;
+	pbm->mem_space.end = a + (b - 1UL);
+	pbm->mem_space.flags = IORESOURCE_MEM;
+
+	/* This 32MB area is divided into two pieces.  The first
+	 * 16MB is Config space, the next 16MB is I/O space.
+	 */
+
+	a = schizo_read(io_match) & ~0x8000000000000000UL;
+	pbm->config_space = a;
+	printk("SCHIZO PBM%c: Local PCI config space at %016lx\n",
+	       (is_pbm_a ? 'A' : 'B'), pbm->config_space);
+
+	a += (16UL * 1024UL * 1024UL);
+	pbm->io_space.start = a;
+	pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL);
+	pbm->io_space.flags = IORESOURCE_IO;
+}
+
+static void __init pbm_register_toplevel_resources(struct pci_controller_info *p,
+						   struct pci_pbm_info *pbm)
+{
+	char *name = pbm->name;
+
+	sprintf(name, "SCHIZO%d PBM%c",
+		p->index,
+		(pbm == &p->pbm_A ? 'A' : 'B'));
+	pbm->io_space.name = pbm->mem_space.name = name;
+
+	request_resource(&ioport_resource, &pbm->io_space);
+	request_resource(&iomem_resource, &pbm->mem_space);
+}
+
+#define SCHIZO_STRBUF_CONTROL_A		(SCHIZO_PBM_A_REGS_OFF + 0x02800UL)
+#define SCHIZO_STRBUF_FLUSH_A		(SCHIZO_PBM_A_REGS_OFF + 0x02808UL)
+#define SCHIZO_STRBUF_FSYNC_A		(SCHIZO_PBM_A_REGS_OFF + 0x02810UL)
+#define SCHIZO_STRBUF_CTXFLUSH_A	(SCHIZO_PBM_A_REGS_OFF + 0x02818UL)
+#define SCHIZO_STRBUF_CTXMATCH_A	(SCHIZO_PBM_A_REGS_OFF + 0x10000UL)
+
+#define SCHIZO_STRBUF_CONTROL_B		(SCHIZO_PBM_B_REGS_OFF + 0x02800UL)
+#define SCHIZO_STRBUF_FLUSH_B		(SCHIZO_PBM_B_REGS_OFF + 0x02808UL)
+#define SCHIZO_STRBUF_FSYNC_B		(SCHIZO_PBM_B_REGS_OFF + 0x02810UL)
+#define SCHIZO_STRBUF_CTXFLUSH_B	(SCHIZO_PBM_B_REGS_OFF + 0x02818UL)
+#define SCHIZO_STRBUF_CTXMATCH_B	(SCHIZO_PBM_B_REGS_OFF + 0x10000UL)
+
+static void schizo_pbm_strbuf_init(struct pci_controller_info *p,
+				   struct pci_pbm_info *pbm,
+				   int is_pbm_a)
+{
+	unsigned long base = p->controller_regs;
+	u64 control;
+
+	/* SCHIZO has context flushing. */
+	if (is_pbm_a) {
+		pbm->stc.strbuf_control		= base + SCHIZO_STRBUF_CONTROL_A;
+		pbm->stc.strbuf_pflush		= base + SCHIZO_STRBUF_FLUSH_A;
+		pbm->stc.strbuf_fsync		= base + SCHIZO_STRBUF_FSYNC_A;
+		pbm->stc.strbuf_ctxflush	= base + SCHIZO_STRBUF_CTXFLUSH_A;
+		pbm->stc.strbuf_ctxmatch_base	= base + SCHIZO_STRBUF_CTXMATCH_A;
+	} else {
+		pbm->stc.strbuf_control		= base + SCHIZO_STRBUF_CONTROL_B;
+		pbm->stc.strbuf_pflush		= base + SCHIZO_STRBUF_FLUSH_B;
+		pbm->stc.strbuf_fsync		= base + SCHIZO_STRBUF_FSYNC_B;
+		pbm->stc.strbuf_ctxflush	= base + SCHIZO_STRBUF_CTXFLUSH_B;
+		pbm->stc.strbuf_ctxmatch_base	= base + SCHIZO_STRBUF_CTXMATCH_B;
+	}
+
+	pbm->stc.strbuf_flushflag = (volatile unsigned long *)
+		((((unsigned long)&pbm->stc.__flushflag_buf[0])
+		  + 63UL)
+		 & ~63UL);
+	pbm->stc.strbuf_flushflag_pa = (unsigned long)
+		__pa(pbm->stc.strbuf_flushflag);
+
+	/* Turn off LRU locking and diag mode, enable the
+	 * streaming buffer and leave the rerun-disable
+	 * setting however OBP set it.
+	 */
+	control = schizo_read(pbm->stc.strbuf_control);
+	control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
+		     SCHIZO_STRBUF_CTRL_LENAB |
+		     SCHIZO_STRBUF_CTRL_DENAB);
+	control |= SCHIZO_STRBUF_CTRL_ENAB;
+	schizo_write(pbm->stc.strbuf_control, control);
+
+	pbm->stc.strbuf_enabled = 1;
+}
+
+#define SCHIZO_IOMMU_CONTROL_A		(SCHIZO_PBM_A_REGS_OFF + 0x00200UL)
+#define SCHIZO_IOMMU_TSBBASE_A		(SCHIZO_PBM_A_REGS_OFF + 0x00208UL)
+#define SCHIZO_IOMMU_FLUSH_A		(SCHIZO_PBM_A_REGS_OFF + 0x00210UL)
+#define SCHIZO_IOMMU_CTXFLUSH_A		(SCHIZO_PBM_A_REGS_OFF + 0x00218UL)
+#define SCHIZO_IOMMU_TAG_A		(SCHIZO_PBM_A_REGS_OFF + 0x0a580UL)
+#define SCHIZO_IOMMU_DATA_A		(SCHIZO_PBM_A_REGS_OFF + 0x0a600UL)
+#define SCHIZO_IOMMU_CONTROL_B		(SCHIZO_PBM_B_REGS_OFF + 0x00200UL)
+#define SCHIZO_IOMMU_TSBBASE_B		(SCHIZO_PBM_B_REGS_OFF + 0x00208UL)
+#define SCHIZO_IOMMU_FLUSH_B		(SCHIZO_PBM_B_REGS_OFF + 0x00210UL)
+#define SCHIZO_IOMMU_CTXFLUSH_B		(SCHIZO_PBM_B_REGS_OFF + 0x00218UL)
+#define SCHIZO_IOMMU_TAG_B		(SCHIZO_PBM_B_REGS_OFF + 0x0a580UL)
+#define SCHIZO_IOMMU_DATA_B		(SCHIZO_PBM_B_REGS_OFF + 0x0a600UL)
+
+static void schizo_pbm_iommu_init(struct pci_controller_info *p,
+				  struct pci_pbm_info *pbm,
+				  int is_pbm_a)
+{
+	struct pci_iommu *iommu = pbm->iommu;
+	unsigned long tsbbase, i, tagbase, database;
+	u64 control;
+
+	/* Setup initial software IOMMU state. */
+	spin_lock_init(&iommu->lock);
+	iommu->iommu_cur_ctx = 0;
+
+	/* Register addresses, SCHIZO has iommu ctx flushing. */
+	if (is_pbm_a) {
+		iommu->iommu_control  = p->controller_regs + SCHIZO_IOMMU_CONTROL_A;
+		iommu->iommu_tsbbase  = p->controller_regs + SCHIZO_IOMMU_TSBBASE_A;
+		iommu->iommu_flush    = p->controller_regs + SCHIZO_IOMMU_FLUSH_A;
+		iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_A;
+	} else {
+		iommu->iommu_control  = p->controller_regs + SCHIZO_IOMMU_CONTROL_B;
+		iommu->iommu_tsbbase  = p->controller_regs + SCHIZO_IOMMU_TSBBASE_B;
+		iommu->iommu_flush    = p->controller_regs + SCHIZO_IOMMU_FLUSH_B;
+		iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_B;
+	}
+
+	/* We use the main control/status register of SCHIZO as the write
+	 * completion register.
+	 */
+	iommu->write_complete_reg = p->controller_regs + 0x10000UL;
+
+	/*
+	 * Invalidate TLB Entries.
+	 */
+	control = schizo_read(iommu->iommu_control);
+	control |= SCHIZO_IOMMU_CTRL_DENAB;
+	schizo_write(iommu->iommu_control, control);
+
+	if (is_pbm_a)
+		tagbase = SCHIZO_IOMMU_TAG_A, database = SCHIZO_IOMMU_DATA_A;
+	else
+		tagbase = SCHIZO_IOMMU_TAG_B, database = SCHIZO_IOMMU_DATA_B;
+	for(i = 0; i < 16; i++) {
+		schizo_write(p->controller_regs + tagbase + (i * 8UL), 0);
+		schizo_write(p->controller_regs + database + (i * 8UL), 0);
+	}
+
+	/* Leave diag mode enabled for full-flushing done
+	 * in pci_iommu.c
+	 */
+
+	/* Using assumed page size 8K with 128K entries we need 1MB iommu page
+	 * table (128K ioptes * 8 bytes per iopte).  This is
+	 * page order 7 on UltraSparc.
+	 */
+	tsbbase = __get_free_pages(GFP_KERNEL, 7);
+	if (!tsbbase) {
+		prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n");
+		prom_halt();
+	}
+	iommu->page_table = (iopte_t *)tsbbase;
+	iommu->page_table_sz_bits = 17;
+	iommu->page_table_map_base = 0xc0000000;
+	iommu->dma_addr_mask = 0xffffffff;
+	memset((char *)tsbbase, 0, PAGE_SIZE << 7);
+
+	/* We start with no consistent mappings. */
+	iommu->lowest_consistent_map =
+		1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS);
+
+	for (i = 0; i < PBM_NCLUSTERS; i++) {
+		iommu->alloc_info[i].flush = 0;
+		iommu->alloc_info[i].next = 0;
+	}
+
+	schizo_write(iommu->iommu_tsbbase, __pa(tsbbase));
+
+	control = schizo_read(iommu->iommu_control);
+	control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
+	control |= (SCHIZO_IOMMU_TSBSZ_128K | SCHIZO_IOMMU_CTRL_ENAB);
+	schizo_write(iommu->iommu_control, control);
 }
 
 static void schizo_pbm_init(struct pci_controller_info *p,
 			    int prom_node, int is_pbm_a)
 {
-	/* IMPLEMENT ME */
+	unsigned int busrange[2];
+	struct pci_pbm_info *pbm;
+	int err;
+
+	if (is_pbm_a)
+		pbm = &p->pbm_A;
+	else
+		pbm = &p->pbm_B;
+
+	schizo_determine_mem_io_space(pbm, is_pbm_a, p->controller_regs);
+	pbm_register_toplevel_resources(p, pbm);
+
+	pbm->parent = p;
+	pbm->prom_node = prom_node;
+	prom_getstring(prom_node, "name",
+		       pbm->prom_name,
+		       sizeof(pbm->prom_name));
+
+	err = prom_getproperty(prom_node, "ranges",
+			       (char *) pbm->pbm_ranges,
+			       sizeof(pbm->pbm_ranges));
+	if (err != -1)
+		pbm->num_pbm_ranges =
+			(err / sizeof(struct linux_prom_pci_ranges));
+	else
+		pbm->num_pbm_ranges = 0;
+
+	err = prom_getproperty(prom_node, "interrupt-map",
+			       (char *)pbm->pbm_intmap,
+			       sizeof(pbm->pbm_intmap));
+	if (err != -1) {
+		pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
+		err = prom_getproperty(prom_node, "interrupt-map-mask",
+				       (char *)&pbm->pbm_intmask,
+				       sizeof(pbm->pbm_intmask));
+		if (err == -1) {
+			prom_printf("SCHIZO-PBM: Fatal error, no "
+				    "interrupt-map-mask.\n");
+			prom_halt();
+		}
+	} else {
+		pbm->num_pbm_intmap = 0;
+		memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
+	}
+
+	err = prom_getproperty(prom_node, "bus-range",
+			       (char *)&busrange[0],
+			       sizeof(busrange));
+	if (err == 0 || err == -1) {
+		prom_printf("SCHIZO-PBM: Fatal error, no bus-range.\n");
+		prom_halt();
+	}
+	pbm->pci_first_busno = busrange[0];
+	pbm->pci_last_busno = busrange[1];
+
+	schizo_pbm_iommu_init(p, pbm, is_pbm_a);
+	schizo_pbm_strbuf_init(p, pbm, is_pbm_a);
+}
+
+static void schizo_controller_hwinit(struct pci_controller_info *p)
+{
+	unsigned long pbm_a_base, pbm_b_base;
+	u64 tmp;
+
+	pbm_a_base = p->controller_regs + SCHIZO_PBM_A_REGS_OFF;
+	pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF;
+
+	/* Set IRQ retry to infinity. */
+	schizo_write(pbm_a_base + 0x1a00UL, 0xff);
+	schizo_write(pbm_b_base + 0x1a00UL, 0xff);
+
+	/* Enable arbiter for all PCI slots. */
+	tmp = schizo_read(pbm_a_base + 0x2000UL);
+	tmp |= 0x3fUL;
+	schizo_write(pbm_a_base + 0x2000UL, tmp);
+
+	tmp = schizo_read(pbm_b_base + 0x2000UL);
+	tmp |= 0x3fUL;
+	schizo_write(pbm_b_base + 0x2000UL, tmp);
 }
 
 void __init schizo_init(int node)
@@ -90,6 +1645,7 @@
 	struct linux_prom64_registers pr_regs[3];
 	struct pci_controller_info *p;
 	struct pci_iommu *iommu;
+	unsigned long flags;
 	u32 portid;
 	int is_pbm_a, err;
 
@@ -142,7 +1698,6 @@
 	p->resource_adjust = schizo_resource_adjust;
 	p->pci_ops = &schizo_ops;
 
-pbm_init:
 	/* Three OBP regs:
 	 * 1) PBM controller regs
 	 * 2) Schizo front-end controller regs (same for both PBMs)
@@ -156,14 +1711,16 @@
 		prom_halt();
 	}
 
-	/* XXX Read REG base, record in controller/pbm structures. */
-
-	/* XXX Report controller to console. */
+	p->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+	printk("PCI: Found SCHIZO, control regs at %016lx\n",
+	       p->controller_regs);
 
-	/* XXX Setup pci_memspace_mask */
+	/* Like PSYCHO we have a 2GB aligned area for memory space. */
+	pci_memspace_mask = 0x7fffffffUL;
 
-	/* XXX Init core controller and IOMMU */
+	/* Init core controller. */
+	schizo_controller_hwinit(p);
 
-	is_pbm_a = XXX; /* Figure out this test */
+	is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
 	schizo_pbm_init(p, node, is_pbm_a);
 }
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c
--- v2.4.2/linux/arch/sparc64/kernel/setup.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/setup.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.59 2001/02/13 01:16:44 davem Exp $
+/*  $Id: setup.c,v 1.62 2001/03/03 10:34:45 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -166,10 +166,14 @@
 					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
 			/*
-			 * Locked down tlb entry 63.
+			 * Locked down tlb entry.
 			 */
 
-			tte = spitfire_get_dtlb_data(63);
+			if (tlb_type == spitfire)
+				tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
+			else if (tlb_type == cheetah)
+				tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
+
 			res = PROM_TRUE;
 			goto done;
 		}
@@ -253,7 +257,7 @@
 		unsigned long tte;
 
 		tte = args[3];
-		prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50);
+		prom_printf("%lx ", (tte & 0x07FC000000000000) >> 50);
 
 		args[2] = 2;
 		args[args[1] + 3] = 0;
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.4.2/linux/arch/sparc64/kernel/sys_sparc.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/sys_sparc.c	Mon Mar 19 12:35:10 2001
@@ -243,9 +243,9 @@
 	if (flags & MAP_SHARED)
 		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	retval = do_mmap(file, addr, len, prot, flags, off);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
 
@@ -263,9 +263,9 @@
 	if (len > -PAGE_OFFSET ||
 	    (addr < PAGE_OFFSET && addr + len > -PAGE_OFFSET))
 		return -EINVAL;
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	ret = do_munmap(current->mm, addr, len);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return ret;
 }
 
@@ -285,7 +285,7 @@
 		goto out;
 	if (addr < PAGE_OFFSET && addr + old_len > -PAGE_OFFSET)
 		goto out;
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	vma = find_vma(current->mm, addr);
 	if (vma && (vma->vm_flags & VM_SHARED))
 		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
@@ -305,7 +305,7 @@
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
 	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 out:
 	return ret;       
 }
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.4.2/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Mon Mar 19 12:35:10 2001
@@ -4133,7 +4133,7 @@
 		goto out;
 	if (addr > 0xf0000000UL - old_len)
 		goto out;
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	vma = find_vma(current->mm, addr);
 	if (vma && (vma->vm_flags & VM_SHARED))
 		current->thread.flags |= SPARC_FLAG_MMAPSHARED;
@@ -4152,7 +4152,7 @@
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 out_sem:
 	current->thread.flags &= ~(SPARC_FLAG_MMAPSHARED);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 out:
 	return ret;       
 }
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.4.2/linux/arch/sparc64/kernel/sys_sunos32.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Mar 19 12:35:10 2001
@@ -100,12 +100,12 @@
 	flags &= ~_MAP_NEW;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	retval = do_mmap(file,
 			 (unsigned long) addr, (unsigned long) len,
 			 (unsigned long) prot, (unsigned long) flags,
 			 (unsigned long) off);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if(!ret_type)
 		retval = ((retval < 0xf0000000) ? 0 : retval);
 out_putf:
@@ -126,7 +126,7 @@
 	unsigned long rlim;
 	unsigned long newbrk, oldbrk, brk = (unsigned long) baddr;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	if (brk < current->mm->end_code)
 		goto out;
 	newbrk = PAGE_ALIGN(brk);
@@ -170,7 +170,7 @@
 	do_brk(oldbrk, newbrk-oldbrk);
 	retval = 0;
 out:
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return retval;
 }
 
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.4.2/linux/arch/sparc64/kernel/trampoline.S	Mon Dec 20 22:05:52 1999
+++ linux/arch/sparc64/kernel/trampoline.S	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.12 1999/12/15 15:45:12 davem Exp $
+/* $Id: trampoline.S,v 1.14 2001/03/04 18:31:00 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,8 @@
 #include <asm/head.h>
 #include <asm/asi.h>
 #include <asm/lsu.h>
+#include <asm/dcr.h>
+#include <asm/dcu.h>
 #include <asm/pstate.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -30,177 +32,235 @@
 sparc64_cpu_startup:
 	flushw
 
-	mov	(LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
-	stxa	%g1, [%g0] ASI_LSU_CONTROL
-	membar	#Sync
+	rdpr		%ver, %g1
+	sethi		%hi(0x003e0014), %g5
+	srlx		%g1, 32, %g1
+	or		%g5, %lo(0x003e0014), %g5
+	cmp		%g1, %g5
+	bne,pt		%icc, spitfire_startup
+	 nop
+
+cheetah_startup:
+	mov		DCR_BPE | DCR_RPE | DCR_SI | DCR_MS, %g1
+	wr		%g1, %asr18
+
+	sethi		%uhi(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	or		%g5, %ulo(DCU_ME | DCU_RE | DCU_PE | DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5
+	sllx		%g5, 32, %g5
+	ldxa		[%g0] ASI_DCU_CONTROL_REG, %g1
+	or		%g1, %g5, %g1
+	stxa		%g5, [%g0] ASI_DCU_CONTROL_REG
+	membar		#Sync
 
-	wrpr	%g0, 15, %pil
-	wr	%g0, 0, %tick_cmpr
+	ba,pt		%xcc, startup_continue
+	 nop
+
+spitfire_startup:
+	mov		(LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+	stxa		%g1, [%g0] ASI_LSU_CONTROL
+	membar		#Sync
+
+startup_continue:
+	wrpr		%g0, 15, %pil
+	wr		%g0, 0, %tick_cmpr
 
 	/* Call OBP by hand to lock KERNBASE into i/d tlbs. */
-	mov	%o0, %l0
+	mov		%o0, %l0
 
-	sethi	%hi(prom_entry_lock), %g2
-1:	ldstub	[%g2 + %lo(prom_entry_lock)], %g1
-	brnz,pn	%g1, 1b
-	 membar	#StoreLoad | #StoreStore
-
-	sethi	%hi(p1275buf), %g2
-	or	%g2, %lo(p1275buf), %g2
-	ldx	[%g2 + 0x10], %l2
-	mov	%sp, %l1
-	add	%l2, -(192 + 128), %sp
+	sethi		%hi(prom_entry_lock), %g2
+1:	ldstub		[%g2 + %lo(prom_entry_lock)], %g1
+	brnz,pn		%g1, 1b
+	 membar		#StoreLoad | #StoreStore
+
+	sethi		%hi(p1275buf), %g2
+	or		%g2, %lo(p1275buf), %g2
+	ldx		[%g2 + 0x10], %l2
+	mov		%sp, %l1
+	add		%l2, -(192 + 128), %sp
 	flushw
 
-	sethi	%hi(call_method), %g2
-	or	%g2, %lo(call_method), %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x00]
-	mov	5, %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x08]
-	mov	1, %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x10]
-	sethi	%hi(itlb_load), %g2
-	or	%g2, %lo(itlb_load), %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x18]
-	sethi	%hi(mmu_ihandle_cache), %g2
-	lduw	[%g2 + %lo(mmu_ihandle_cache)], %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x20]
-	sethi	%hi(KERNBASE), %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x28]
-	sethi	%hi(kern_locked_tte_data), %g2
-	ldx	[%g2 + %lo(kern_locked_tte_data)], %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x30]
-	mov	63, %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x38]
-	sethi	%hi(p1275buf), %g2
-	or	%g2, %lo(p1275buf), %g2
-	ldx	[%g2 + 0x08], %o1
-	call	%o1
-	 add	%sp, (2047 + 128), %o0
-
-	sethi	%hi(call_method), %g2
-	or	%g2, %lo(call_method), %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x00]
-	mov	5, %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x08]
-	mov	1, %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x10]
-	sethi	%hi(dtlb_load), %g2
-	or	%g2, %lo(dtlb_load), %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x18]
-	sethi	%hi(mmu_ihandle_cache), %g2
-	lduw	[%g2 + %lo(mmu_ihandle_cache)], %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x20]
-	sethi	%hi(KERNBASE), %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x28]
-	sethi	%hi(kern_locked_tte_data), %g2
-	ldx	[%g2 + %lo(kern_locked_tte_data)], %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x30]
-	mov	63, %g2
-	stx	%g2, [%sp + 2047 + 128 + 0x38]
-	sethi	%hi(p1275buf), %g2
-	or	%g2, %lo(p1275buf), %g2
-	ldx	[%g2 + 0x08], %o1
-	call	%o1
-	 add	%sp, (2047 + 128), %o0
-
-	sethi	%hi(prom_entry_lock), %g2
-	stb	%g0, [%g2 + %lo(prom_entry_lock)]
-	membar	#StoreStore | #StoreLoad
+	sethi		%hi(call_method), %g2
+	or		%g2, %lo(call_method), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x00]
+	mov		5, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x08]
+	mov		1, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x10]
+	sethi		%hi(itlb_load), %g2
+	or		%g2, %lo(itlb_load), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x18]
+	sethi		%hi(mmu_ihandle_cache), %g2
+	lduw		[%g2 + %lo(mmu_ihandle_cache)], %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x20]
+	sethi		%hi(KERNBASE), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x28]
+	sethi		%hi(kern_locked_tte_data), %g2
+	ldx		[%g2 + %lo(kern_locked_tte_data)], %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x30]
+
+	rdpr		%ver, %g1
+	sethi		%hi(0x003e0014), %g5
+	srlx		%g1, 32, %g1
+	or		%g5, %lo(0x003e0014), %g5
+	cmp		%g1, %g5
+	bne,a,pt	%icc, 1f
+	 mov		63, %g2
+	mov		15, %g2
+1:
+	stx		%g2, [%sp + 2047 + 128 + 0x38]
+	sethi		%hi(p1275buf), %g2
+	or		%g2, %lo(p1275buf), %g2
+	ldx		[%g2 + 0x08], %o1
+	call		%o1
+	 add		%sp, (2047 + 128), %o0
+
+	sethi		%hi(call_method), %g2
+	or		%g2, %lo(call_method), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x00]
+	mov		5, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x08]
+	mov		1, %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x10]
+	sethi		%hi(dtlb_load), %g2
+	or		%g2, %lo(dtlb_load), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x18]
+	sethi		%hi(mmu_ihandle_cache), %g2
+	lduw		[%g2 + %lo(mmu_ihandle_cache)], %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x20]
+	sethi		%hi(KERNBASE), %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x28]
+	sethi		%hi(kern_locked_tte_data), %g2
+	ldx		[%g2 + %lo(kern_locked_tte_data)], %g2
+	stx		%g2, [%sp + 2047 + 128 + 0x30]
+
+	rdpr		%ver, %g1
+	sethi		%hi(0x003e0014), %g5
+	srlx		%g1, 32, %g1
+	or		%g5, %lo(0x003e0014), %g5
+	cmp		%g1, %g5
+	bne,a,pt	%icc, 1f
+	 mov		63, %g2
+	mov		15, %g2
+1:
+
+	stx		%g2, [%sp + 2047 + 128 + 0x38]
+	sethi		%hi(p1275buf), %g2
+	or		%g2, %lo(p1275buf), %g2
+	ldx		[%g2 + 0x08], %o1
+	call		%o1
+	 add		%sp, (2047 + 128), %o0
+
+	sethi		%hi(prom_entry_lock), %g2
+	stb		%g0, [%g2 + %lo(prom_entry_lock)]
+	membar		#StoreStore | #StoreLoad
 
-	mov	%l1, %sp
+	mov		%l1, %sp
 	flushw
 
-	mov	%l0, %o0
+	mov		%l0, %o0
 
-	wrpr	%g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
-	wr	%g0, 0, %fprs
+	wrpr		%g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+	wr		%g0, 0, %fprs
 
-	sethi	%uhi(PAGE_OFFSET), %g4
-	sllx	%g4, 32, %g4
+	sethi		%uhi(PAGE_OFFSET), %g4
+	sllx		%g4, 32, %g4
 
 	/* XXX Buggy PROM... */
-	srl	%o0, 0, %o0
-	ldx	[%o0], %g6
+	srl		%o0, 0, %o0
+	ldx		[%o0], %g6
 
-	wr	%g0, ASI_P, %asi
+	wr		%g0, ASI_P, %asi
 
-	mov	PRIMARY_CONTEXT, %g7
-	stxa	%g0, [%g7] ASI_DMMU
-	membar	#Sync
-	mov	SECONDARY_CONTEXT, %g7
-	stxa	%g0, [%g7] ASI_DMMU
-	membar	#Sync
-
-	mov	1, %g5
-	sllx	%g5, (PAGE_SHIFT + 1), %g5
-	sub	%g5, (REGWIN_SZ + STACK_BIAS), %g5
-	add	%g6, %g5, %sp
-	mov	0, %fp
+	mov		PRIMARY_CONTEXT, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	membar		#Sync
+	mov		SECONDARY_CONTEXT, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	membar		#Sync
+
+	mov		1, %g5
+	sllx		%g5, (PAGE_SHIFT + 1), %g5
+	sub		%g5, (REGWIN_SZ + STACK_BIAS), %g5
+	add		%g6, %g5, %sp
+	mov		0, %fp
 
-	wrpr	%g0, 0, %wstate
-	wrpr	%g0, 0, %tl
+	wrpr		%g0, 0, %wstate
+	wrpr		%g0, 0, %tl
 
 	/* Setup the trap globals, then we can resurface. */
-	rdpr	%pstate, %o1
-	mov	%g6, %o2
-	wrpr	%o1, PSTATE_AG, %pstate
-	sethi	%hi(sparc64_ttable_tl0), %g5
-	wrpr	%g5, %tba
-	mov	%o2, %g6
+	rdpr		%pstate, %o1
+	mov		%g6, %o2
+	wrpr		%o1, PSTATE_AG, %pstate
+	sethi		%hi(sparc64_ttable_tl0), %g5
+	wrpr		%g5, %tba
+	mov		%o2, %g6
 
-	wrpr	%o1, PSTATE_MG, %pstate
+	wrpr		%o1, PSTATE_MG, %pstate
 #define KERN_HIGHBITS		((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-#ifdef THIS_IS_CHEETAH
-#error Dave, make sure you took care of other issues in rest of sparc64 code...
-#define VPTE_BASE		0xffe0000000000000
-#else /* Spitfire/Blackbird */
-#define VPTE_BASE		0xfffffffe00000000
-#endif
-	mov	TSB_REG, %g1
-	stxa	%g0, [%g1] ASI_DMMU
-	membar	#Sync
-	mov	TLB_SFSR, %g1
-	sethi	%uhi(KERN_HIGHBITS), %g2
-	or	%g2, %ulo(KERN_HIGHBITS), %g2
-	sllx	%g2, 32, %g2
-	or	%g2, KERN_LOWBITS, %g2
-	sethi	%uhi(VPTE_BASE), %g3
-	or	%g3, %ulo(VPTE_BASE), %g3
-	sllx	%g3, 32, %g3
+
+#define VPTE_BASE_CHEETAH	0xffe0000000000000
+#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
+
+	mov		TSB_REG, %g1
+	stxa		%g0, [%g1] ASI_DMMU
+	membar		#Sync
+	mov		TLB_SFSR, %g1
+	sethi		%uhi(KERN_HIGHBITS), %g2
+	or		%g2, %ulo(KERN_HIGHBITS), %g2
+	sllx		%g2, 32, %g2
+	or		%g2, KERN_LOWBITS, %g2
+
+	rdpr		%ver, %g3
+	sethi		%hi(0x003e0014), %g7
+	srlx		%g3, 32, %g3
+	or		%g7, %lo(0x003e0014), %g7
+	cmp		%g3, %g7
+	bne,pt		%icc, 1f
+	 nop
+
+	sethi		%uhi(VPTE_BASE_CHEETAH), %g3
+	or		%g3, %ulo(VPTE_BASE_CHEETAH), %g3
+	ba,pt		%xcc, 2f
+	sllx		%g3, 32, %g3
+1:
+	sethi		%uhi(VPTE_BASE_SPITFIRE), %g3
+	or		%g3, %ulo(VPTE_BASE_SPITFIRE), %g3
+	sllx		%g3, 32, %g3
+
+2:
 	clr	%g7
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
 #undef VPTE_BASE
 
 	/* Setup interrupt globals, we are always SMP. */
-	wrpr	%o1, PSTATE_IG, %pstate
+	wrpr		%o1, PSTATE_IG, %pstate
 
 	/* Get our UPA MID. */
-	lduw	[%o2 + AOFF_task_processor], %g1
-	sethi	%hi(cpu_data), %g5
-	or	%g5, %lo(cpu_data), %g5
+	lduw		[%o2 + AOFF_task_processor], %g1
+	sethi		%hi(cpu_data), %g5
+	or		%g5, %lo(cpu_data), %g5
 
 	/* In theory this is: &(cpu_data[this_upamid].irq_worklists[0]) */
-	sllx	%g1, 7, %g1
-	add	%g5, %g1, %g1
-	add	%g1, 64, %g6
-
-	wrpr	%g0, 0, %wstate
-	or	%o1, PSTATE_IE, %o1
-	wrpr	%o1, 0, %pstate
+	sllx		%g1, 7, %g1
+	add		%g5, %g1, %g1
+	add		%g1, 64, %g6
+
+	wrpr		%g0, 0, %wstate
+	or		%o1, PSTATE_IE, %o1
+	wrpr		%o1, 0, %pstate
 
-	call	prom_set_trap_table
-	 sethi	%hi(sparc64_ttable_tl0), %o0
+	call		prom_set_trap_table
+	 sethi		%hi(sparc64_ttable_tl0), %o0
 
-	call	smp_callin
+	call		smp_callin
 	 nop
-	call	cpu_idle
-	 mov	0, %o0
-	call	cpu_panic
+	call		cpu_idle
+	 mov		0, %o0
+	call		cpu_panic
 	 nop
-1:	b,a,pt	%xcc, 1b
+1:	b,a,pt		%xcc, 1b
 
 	.align		8
 sparc64_cpu_startup_end:
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.4.2/linux/arch/sparc64/mm/fault.c	Sun Sep 17 10:01:50 2000
+++ linux/arch/sparc64/mm/fault.c	Mon Mar 19 12:35:10 2001
@@ -234,7 +234,7 @@
 	if (in_interrupt() || !mm)
 		goto handle_kernel_fault;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -308,7 +308,7 @@
 		goto out_of_memory;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	goto fault_done;
 
 	/*
@@ -316,7 +316,7 @@
 	 * Fix it, but check if it's kernel or user first..
 	 */
 bad_area:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 handle_kernel_fault:
 	do_kernel_fault(regs, si_code, fault_code, insn, address);
@@ -328,14 +328,14 @@
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
 	if (!(regs->tstate & TSTATE_PRIV))
 		do_exit(SIGKILL);
 	goto handle_kernel_fault;
 
 do_sigbus:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/*
 	 * Send a sigbus, regardless of whether we were in kernel
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.4.2/linux/arch/sparc64/mm/init.c	Wed Feb 21 18:20:15 2001
+++ linux/arch/sparc64/mm/init.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.162 2001/02/13 01:16:44 davem Exp $
+/*  $Id: init.c,v 1.164 2001/03/03 10:34:45 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -40,6 +40,8 @@
 /* Ugly, but necessary... -DaveM */
 unsigned long phys_base;
 
+enum ultra_tlb_layout tlb_type = spitfire;
+
 /* get_new_mmu_context() uses "cache + 1".  */
 spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED;
 unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
@@ -57,17 +59,17 @@
 {
         int freed = 0;
 
-	if(pgtable_cache_size > high) {
+	if (pgtable_cache_size > high) {
 		do {
 #ifdef CONFIG_SMP
-			if(pgd_quicklist)
+			if (pgd_quicklist)
 				free_pgd_slow(get_pgd_fast()), freed++;
 #endif
-			if(pte_quicklist[0])
+			if (pte_quicklist[0])
 				free_pte_slow(get_pte_fast(0)), freed++;
-			if(pte_quicklist[1])
+			if (pte_quicklist[1])
 				free_pte_slow(get_pte_fast(1)), freed++;
-		} while(pgtable_cache_size > low);
+		} while (pgtable_cache_size > low);
 	}
 #ifndef CONFIG_SMP 
         if (pgd_cache_size > high / 4) {
@@ -163,13 +165,12 @@
 
 int mmu_info(char *buf)
 {
-	/* We'll do the rest later to make it nice... -DaveM */
-#if 0
-	if (this_is_cheetah)
-		sprintf(buf, "MMU Type\t: One bad ass cpu\n");
+	if (tlb_type == cheetah)
+		return sprintf(buf, "MMU Type\t: Cheetah\n");
+	else if (tlb_type == spitfire)
+		return sprintf(buf, "MMU Type\t: Spitfire\n");
 	else
-#endif
-	return sprintf(buf, "MMU Type\t: Spitfire\n");
+		return sprintf(buf, "MMU Type\t: ???\n");
 }
 
 struct linux_prom_translation {
@@ -231,6 +232,8 @@
 			for (vaddr = trans[i].virt;
 			     vaddr < trans[i].virt + trans[i].size;
 			     vaddr += PAGE_SIZE) {
+				unsigned long val;
+
 				pgdp = pgd_offset(&init_mm, vaddr);
 				if (pgd_none(*pgdp)) {
 					pmdp = __alloc_bootmem(PMD_TABLE_SIZE,
@@ -252,7 +255,14 @@
 					pmd_set(pmdp, ptep);
 				}
 				ptep = pte_offset(pmdp, vaddr);
-				set_pte (ptep, __pte(trans[i].data | _PAGE_MODIFIED));
+
+				val = trans[i].data;
+
+				/* Clear diag TTE bits. */
+				if (tlb_type == spitfire)
+					val &= ~0x0003fe0000000000UL;
+
+				set_pte (ptep, __pte(val | _PAGE_MODIFIED));
 				trans[i].data += PAGE_SIZE;
 			}
 		}
@@ -268,26 +278,59 @@
 			     : "r" (0),
 			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
-	phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
+	switch (tlb_type) {
+	default:
+	case spitfire:
+		phys_page = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent());
+		break;
+
+	case cheetah:
+		phys_page = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent());
+		break;
+	};
+
+	phys_page &= _PAGE_PADDR;
 	phys_page += ((unsigned long)&prom_boot_page -
 		      (unsigned long)&empty_zero_page);
 
-	/* Lock this into i/d tlb entry 59 */
-	__asm__ __volatile__(
-		"stxa	%%g0, [%2] %3\n\t"
-		"stxa	%0, [%1] %4\n\t"
-		"membar	#Sync\n\t"
-		"flush	%%g6\n\t"
-		"stxa	%%g0, [%2] %5\n\t"
-		"stxa	%0, [%1] %6\n\t"
-		"membar	#Sync\n\t"
-		"flush	%%g6"
-		: : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
-			 _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
-		    "r" (59 << 3), "r" (TLB_TAG_ACCESS),
-		    "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
-		    "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
-		: "memory");
+	if (tlb_type == spitfire) {
+		/* Lock this into i/d tlb entry 59 */
+		__asm__ __volatile__(
+			"stxa	%%g0, [%2] %3\n\t"
+			"stxa	%0, [%1] %4\n\t"
+			"membar	#Sync\n\t"
+			"flush	%%g6\n\t"
+			"stxa	%%g0, [%2] %5\n\t"
+			"stxa	%0, [%1] %6\n\t"
+			"membar	#Sync\n\t"
+			"flush	%%g6"
+			: : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
+				 _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
+			"r" (59 << 3), "r" (TLB_TAG_ACCESS),
+			"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
+			"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
+			: "memory");
+	} else if (tlb_type == cheetah) {
+		/* Lock this into i/d tlb-0 entry 11 */
+		__asm__ __volatile__(
+			"stxa	%%g0, [%2] %3\n\t"
+			"stxa	%0, [%1] %4\n\t"
+			"membar	#Sync\n\t"
+			"flush	%%g6\n\t"
+			"stxa	%%g0, [%2] %5\n\t"
+			"stxa	%0, [%1] %6\n\t"
+			"membar	#Sync\n\t"
+			"flush	%%g6"
+			: : "r" (phys_page | _PAGE_VALID | _PAGE_SZ8K | _PAGE_CP |
+				 _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W),
+			"r" ((0 << 16) | (11 << 3)), "r" (TLB_TAG_ACCESS),
+			"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
+			"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
+			: "memory");
+	} else {
+		/* Implement me :-) */
+		BUG();
+	}
 
 	tte_vaddr = (unsigned long) &empty_zero_page;
 
@@ -298,7 +341,12 @@
 			     : "r" (0),
 			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
-	kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
+	if (tlb_type == spitfire)
+		tte_data = spitfire_get_dtlb_data(sparc64_highest_locked_tlbent());
+	else
+		tte_data = cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent());
+
+	kern_locked_tte_data = tte_data;
 
 	remap_func = (void *)  ((unsigned long) &prom_remap -
 				(unsigned long) &prom_boot_page);
@@ -311,7 +359,9 @@
 			     : "r" (0),
 			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
-	remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
+	remap_func((tlb_type == spitfire ?
+		    (spitfire_get_dtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR) :
+		    (cheetah_get_ldtlb_data(sparc64_highest_locked_tlbent()) & _PAGE_PADDR)),
 		   (unsigned long) &empty_zero_page,
 		   prom_get_mmu_ihandle());
 
@@ -320,8 +370,8 @@
 	spitfire_flush_itlb_nucleus_page(0x0);
 
 	/* Now lock us back into the TLBs via OBP. */
-	prom_dtlb_load(63, tte_data, tte_vaddr);
-	prom_itlb_load(63, tte_data, tte_vaddr);
+	prom_dtlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
+	prom_itlb_load(sparc64_highest_locked_tlbent(), tte_data, tte_vaddr);
 
 	/* Re-read translations property. */
 	if ((n = prom_getproperty(node, "translations", (char *)trans, tsz)) == -1) {
@@ -372,26 +422,45 @@
 	int i;
 
 	/* Only DTLB must be checked for VPTE entries. */
-	for(i = 0; i < 63; i++) {
-		unsigned long tag;
+	if (tlb_type == spitfire) {
+		for (i = 0; i < 63; i++) {
+			unsigned long tag;
 
-		/* Spitfire Errata #32 workaround */
-		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-				     "flush	%%g6"
-				     : /* No outputs */
-				     : "r" (0),
-				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-		tag = spitfire_get_dtlb_tag(i);
-		if(((tag & ~(PAGE_MASK)) == 0) &&
-		   ((tag &  (PAGE_MASK)) >= prom_reserved_base)) {
-			__asm__ __volatile__("stxa %%g0, [%0] %1"
-					     : /* no outputs */
-					     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-			membar("#Sync");
-			spitfire_put_dtlb_data(i, 0x0UL);
-			membar("#Sync");
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+			tag = spitfire_get_dtlb_tag(i);
+			if (((tag & ~(PAGE_MASK)) == 0) &&
+			    ((tag &  (PAGE_MASK)) >= prom_reserved_base)) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				membar("#Sync");
+				spitfire_put_dtlb_data(i, 0x0UL);
+				membar("#Sync");
+			}
+		}
+	} else if (tlb_type == cheetah) {
+		for (i = 0; i < 511; i++) {
+			unsigned long tag = cheetah_get_dtlb_tag(i);
+
+			if ((tag & ~PAGE_MASK) == 0 &&
+			    (tag & PAGE_MASK) >= prom_reserved_base) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				membar("#Sync");
+				cheetah_put_dtlb_data(i, 0x0UL);
+				membar("#Sync");
+			}
 		}
+	} else {
+		/* Implement me :-) */
+		BUG();
 	}
 }
 
@@ -401,7 +470,7 @@
 	unsigned long	tlb_tag;
 	unsigned long	tlb_data;
 };
-struct prom_tlb_entry prom_itlb[8], prom_dtlb[8];
+struct prom_tlb_entry prom_itlb[16], prom_dtlb[16];
 
 void prom_world(int enter)
 {
@@ -426,41 +495,56 @@
 		__flush_nucleus_vptes();
 
 		/* Install PROM world. */
-		for (i = 0; i < 8; i++) {
+		for (i = 0; i < 16; i++) {
 			if (prom_dtlb[i].tlb_ent != -1) {
 				__asm__ __volatile__("stxa %0, [%1] %2"
 					: : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
 					"i" (ASI_DMMU));
 				membar("#Sync");
-				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
-						       prom_dtlb[i].tlb_data);
+				if (tlb_type == spitfire)
+					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+							       prom_dtlb[i].tlb_data);
+				else if (tlb_type == cheetah)
+					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
+							       prom_dtlb[i].tlb_data);
 				membar("#Sync");
 			}
-
 			if (prom_itlb[i].tlb_ent != -1) {
 				__asm__ __volatile__("stxa %0, [%1] %2"
-					: : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
-					"i" (ASI_IMMU));
+						     : : "r" (prom_itlb[i].tlb_tag),
+						     "r" (TLB_TAG_ACCESS),
+						     "i" (ASI_IMMU));
 				membar("#Sync");
-				spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
-						       prom_itlb[i].tlb_data);
+				if (tlb_type == spitfire)
+					spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+							       prom_itlb[i].tlb_data);
+				else if (tlb_type == cheetah)
+					cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
+							       prom_itlb[i].tlb_data);
 				membar("#Sync");
 			}
 		}
 	} else {
-		for (i = 0; i < 8; i++) {
+		for (i = 0; i < 16; i++) {
 			if (prom_dtlb[i].tlb_ent != -1) {
 				__asm__ __volatile__("stxa %%g0, [%0] %1"
 					: : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
 				membar("#Sync");
-				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
+				if (tlb_type == spitfire)
+					spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
+				else
+					cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, 0x0UL);
 				membar("#Sync");
 			}
 			if (prom_itlb[i].tlb_ent != -1) {
 				__asm__ __volatile__("stxa %%g0, [%0] %1"
-					: : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+						     : : "r" (TLB_TAG_ACCESS),
+						     "i" (ASI_IMMU));
 				membar("#Sync");
-				spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
+				if (tlb_type == spitfire)
+					spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL);
+				else
+					cheetah_put_litlb_data(prom_itlb[i].tlb_ent, 0x0UL);
 				membar("#Sync");
 			}
 		}
@@ -490,25 +574,14 @@
 	 * UNDOCUMENTED!!!!!! Thanks S(t)un!
 	 */
 	if (save_p) {
-		for(i = 0; i < 8; i++) {
-			prom_dtlb[i].tlb_ent = -1;
+		for (i = 0; i < 16; i++) {
 			prom_itlb[i].tlb_ent = -1;
+			prom_dtlb[i].tlb_ent = -1;
 		}
 	}
-	for(i = 0; i < 63; i++) {
-		unsigned long data;
-
-
-		/* Spitfire Errata #32 workaround */
-		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-				     "flush	%%g6"
-				     : /* No outputs */
-				     : "r" (0),
-				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-		data = spitfire_get_dtlb_data(i);
-		if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-			unsigned long tag;
+	if (tlb_type == spitfire) {
+		for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) {
+			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
@@ -517,36 +590,37 @@
 					     : "r" (0),
 					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
-			tag = spitfire_get_dtlb_tag(i);
-			if(save_p) {
-				prom_dtlb[dtlb_seen].tlb_ent = i;
-				prom_dtlb[dtlb_seen].tlb_tag = tag;
-				prom_dtlb[dtlb_seen].tlb_data = data;
-			}
-			__asm__ __volatile__("stxa %%g0, [%0] %1"
-					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-			membar("#Sync");
-			spitfire_put_dtlb_data(i, 0x0UL);
-			membar("#Sync");
+			data = spitfire_get_dtlb_data(i);
+			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
+				unsigned long tag;
+
+				/* Spitfire Errata #32 workaround */
+				__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+						     "flush	%%g6"
+						     : /* No outputs */
+						     : "r" (0),
+						     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+				tag = spitfire_get_dtlb_tag(i);
+				if (save_p) {
+					prom_dtlb[dtlb_seen].tlb_ent = i;
+					prom_dtlb[dtlb_seen].tlb_tag = tag;
+					prom_dtlb[dtlb_seen].tlb_data = data;
+				}
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				membar("#Sync");
+				spitfire_put_dtlb_data(i, 0x0UL);
+				membar("#Sync");
 
-			dtlb_seen++;
-			if(dtlb_seen > 7)
-				break;
+				dtlb_seen++;
+				if (dtlb_seen > 15)
+					break;
+			}
 		}
-	}
-	for(i = 0; i < 63; i++) {
-		unsigned long data;
 
-		/* Spitfire Errata #32 workaround */
-		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-				     "flush	%%g6"
-				     : /* No outputs */
-				     : "r" (0),
-				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-		data = spitfire_get_itlb_data(i);
-		if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-			unsigned long tag;
+		for (i = 0; i < SPITFIRE_HIGHEST_LOCKED_TLBENT; i++) {
+			unsigned long data;
 
 			/* Spitfire Errata #32 workaround */
 			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
@@ -555,22 +629,87 @@
 					     : "r" (0),
 					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
-			tag = spitfire_get_itlb_tag(i);
-			if(save_p) {
-				prom_itlb[itlb_seen].tlb_ent = i;
-				prom_itlb[itlb_seen].tlb_tag = tag;
-				prom_itlb[itlb_seen].tlb_data = data;
+			data = spitfire_get_itlb_data(i);
+			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
+				unsigned long tag;
+
+				/* Spitfire Errata #32 workaround */
+				__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+						     "flush	%%g6"
+						     : /* No outputs */
+						     : "r" (0),
+						     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+				tag = spitfire_get_itlb_tag(i);
+				if (save_p) {
+					prom_itlb[itlb_seen].tlb_ent = i;
+					prom_itlb[itlb_seen].tlb_tag = tag;
+					prom_itlb[itlb_seen].tlb_data = data;
+				}
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+				membar("#Sync");
+				spitfire_put_itlb_data(i, 0x0UL);
+				membar("#Sync");
+
+				itlb_seen++;
+				if (itlb_seen > 15)
+					break;
 			}
-			__asm__ __volatile__("stxa %%g0, [%0] %1"
-					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-			membar("#Sync");
-			spitfire_put_itlb_data(i, 0x0UL);
-			membar("#Sync");
+		}
+	} else if (tlb_type == cheetah) {
+		for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) {
+			unsigned long data;
+
+			data = cheetah_get_ldtlb_data(i);
+			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
+				unsigned long tag;
+
+				tag = cheetah_get_ldtlb_tag(i);
+				if (save_p) {
+					prom_dtlb[dtlb_seen].tlb_ent = i;
+					prom_dtlb[dtlb_seen].tlb_tag = tag;
+					prom_dtlb[dtlb_seen].tlb_data = data;
+				}
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				membar("#Sync");
+				cheetah_put_ldtlb_data(i, 0x0UL);
+				membar("#Sync");
 
-			itlb_seen++;
-			if(itlb_seen > 7)
-				break;
+				dtlb_seen++;
+				if (dtlb_seen > 15)
+					break;
+			}
 		}
+
+		for (i = 0; i < CHEETAH_HIGHEST_LOCKED_TLBENT; i++) {
+			unsigned long data;
+
+			data = cheetah_get_litlb_data(i);
+			if ((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
+				unsigned long tag;
+
+				tag = cheetah_get_litlb_tag(i);
+				if (save_p) {
+					prom_itlb[itlb_seen].tlb_ent = i;
+					prom_itlb[itlb_seen].tlb_tag = tag;
+					prom_itlb[itlb_seen].tlb_data = data;
+				}
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+				membar("#Sync");
+				cheetah_put_litlb_data(i, 0x0UL);
+				membar("#Sync");
+
+				itlb_seen++;
+				if (itlb_seen > 15)
+					break;
+			}
+		}
+	} else {
+		/* Implement me :-) */
+		BUG();
 	}
 	if (save_p)
 		prom_ditlb_set = 1;
@@ -581,24 +720,33 @@
 {
 	int i;
 
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 16; i++) {
 		if (prom_dtlb[i].tlb_ent != -1) {
 			__asm__ __volatile__("stxa %0, [%1] %2"
 				: : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
 				"i" (ASI_DMMU));
 			membar("#Sync");
-			spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
-					       prom_dtlb[i].tlb_data);
+			if (tlb_type == spitfire)
+				spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
+						       prom_dtlb[i].tlb_data);
+			else if (tlb_type == cheetah)
+				cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
+						      prom_dtlb[i].tlb_data);
 			membar("#Sync");
 		}
 
 		if (prom_itlb[i].tlb_ent != -1) {
 			__asm__ __volatile__("stxa %0, [%1] %2"
-				: : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS),
-				"i" (ASI_IMMU));
+					     : : "r" (prom_itlb[i].tlb_tag),
+					     "r" (TLB_TAG_ACCESS),
+					     "i" (ASI_IMMU));
 			membar("#Sync");
-			spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
-					       prom_itlb[i].tlb_data);
+			if (tlb_type == spitfire)
+				spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
+						       prom_itlb[i].tlb_data);
+			else
+				cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
+						       prom_itlb[i].tlb_data);
 			membar("#Sync");
 		}
 	}
@@ -621,7 +769,7 @@
 	unsigned long va;
 
 	flushw_all();
-	for(va =  0; va < (PAGE_SIZE << 1); va += 32)
+	for (va =  0; va < (PAGE_SIZE << 1); va += 32)
 		spitfire_put_icache_tag(va, 0x0);
 }
 
@@ -636,38 +784,43 @@
 			     "wrpr	%0, %1, %%pstate"
 			     : "=r" (pstate)
 			     : "i" (PSTATE_IE));
-	for(i = 0; i < 64; i++) {
-		/* Spitfire Errata #32 workaround */
-		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-				     "flush	%%g6"
-				     : /* No outputs */
-				     : "r" (0),
-				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-		if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
-			__asm__ __volatile__("stxa %%g0, [%0] %1"
-					     : /* no outputs */
-					     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
-			membar("#Sync");
-			spitfire_put_dtlb_data(i, 0x0UL);
-			membar("#Sync");
-		}
+	if (tlb_type == spitfire) {
+		for (i = 0; i < 64; i++) {
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
-		/* Spitfire Errata #32 workaround */
-		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
-				     "flush	%%g6"
-				     : /* No outputs */
-				     : "r" (0),
-				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
-
-		if(!(spitfire_get_itlb_data(i) & _PAGE_L)) {
-			__asm__ __volatile__("stxa %%g0, [%0] %1"
-					     : /* no outputs */
-					     : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
-			membar("#Sync");
-			spitfire_put_itlb_data(i, 0x0UL);
-			membar("#Sync");
+			if (!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
+				membar("#Sync");
+				spitfire_put_dtlb_data(i, 0x0UL);
+				membar("#Sync");
+			}
+
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+			if (!(spitfire_get_itlb_data(i) & _PAGE_L)) {
+				__asm__ __volatile__("stxa %%g0, [%0] %1"
+						     : /* no outputs */
+						     : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
+				membar("#Sync");
+				spitfire_put_itlb_data(i, 0x0UL);
+				membar("#Sync");
+			}
 		}
+	} else if (tlb_type == cheetah) {
+		cheetah_flush_dtlb_all();
+		cheetah_flush_itlb_all();
 	}
 	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
 			     : : "r" (pstate));
@@ -709,7 +862,7 @@
 			mmu_context_bmap[1] = 0;
 			mmu_context_bmap[2] = 0;
 			mmu_context_bmap[3] = 0;
-			for(i = 4; i < CTX_BMAP_SLOTS; i += 4) {
+			for (i = 4; i < CTX_BMAP_SLOTS; i += 4) {
 				mmu_context_bmap[i + 0] = 0;
 				mmu_context_bmap[i + 1] = 0;
 				mmu_context_bmap[i + 2] = 0;
@@ -740,7 +893,7 @@
 	pmd_t *pmd;
 
 	pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-	if(pmd) {
+	if (pmd) {
 		memset(pmd, 0, PAGE_SIZE);
 		pgd_set(pgd, pmd);
 		return pmd + offset;
@@ -798,31 +951,77 @@
 {
         int slot;
 
-        printk ("Contents of itlb: ");
-	for (slot = 0; slot < 14; slot++) printk ("    ");
-	printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
-        for (slot = 1; slot < 64; slot+=3) {
-        	printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
-        		slot, spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
-        		slot+1, spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
-        		slot+2, spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
-        }
+	if (tlb_type == spitfire) {
+		printk ("Contents of itlb: ");
+		for (slot = 0; slot < 14; slot++) printk ("    ");
+		printk ("%2x:%016lx,%016lx\n",
+			0,
+			spitfire_get_itlb_tag(0), spitfire_get_itlb_data(0));
+		for (slot = 1; slot < 64; slot+=3) {
+			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
+				slot,
+				spitfire_get_itlb_tag(slot), spitfire_get_itlb_data(slot),
+				slot+1,
+				spitfire_get_itlb_tag(slot+1), spitfire_get_itlb_data(slot+1),
+				slot+2,
+				spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
+		}
+	} else if (tlb_type == cheetah) {
+		printk ("Contents of itlb0:\n");
+		for (slot = 0; slot < 16; slot+=2) {
+			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+				slot,
+				cheetah_get_litlb_tag(slot), cheetah_get_litlb_data(slot),
+				slot+1,
+				cheetah_get_litlb_tag(slot+1), cheetah_get_litlb_data(slot+1));
+		}
+		printk ("Contents of itlb2:\n");
+		for (slot = 0; slot < 128; slot+=2) {
+			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+				slot,
+				cheetah_get_itlb_tag(slot), cheetah_get_itlb_data(slot),
+				slot+1,
+				cheetah_get_itlb_tag(slot+1), cheetah_get_itlb_data(slot+1));
+		}
+	}
 }
 
 void sparc_ultra_dump_dtlb(void)
 {
         int slot;
 
-        printk ("Contents of dtlb: ");
-	for (slot = 0; slot < 14; slot++) printk ("    ");
-	printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0),
-		spitfire_get_dtlb_data(0));
-        for (slot = 1; slot < 64; slot+=3) {
-        	printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
-        		slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
-        		slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
-        		slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
-        }
+	if (tlb_type == spitfire) {
+		printk ("Contents of dtlb: ");
+		for (slot = 0; slot < 14; slot++) printk ("    ");
+		printk ("%2x:%016lx,%016lx\n", 0,
+			spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+		for (slot = 1; slot < 64; slot+=3) {
+			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
+				slot,
+				spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
+				slot+1,
+				spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
+				slot+2,
+				spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
+		}
+	} else if (tlb_type == cheetah) {
+		printk ("Contents of dtlb0:\n");
+		for (slot = 0; slot < 16; slot+=2) {
+			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+				slot,
+				cheetah_get_ldtlb_tag(slot), cheetah_get_ldtlb_data(slot),
+				slot+1,
+				cheetah_get_ldtlb_tag(slot+1), cheetah_get_ldtlb_data(slot+1));
+		}
+		printk ("Contents of dtlb2:\n");
+		for (slot = 0; slot < 512; slot+=2) {
+			printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
+				slot,
+				cheetah_get_dtlb_tag(slot), cheetah_get_dtlb_data(slot),
+				slot+1,
+				cheetah_get_dtlb_tag(slot+1), cheetah_get_dtlb_data(slot+1));
+		}
+	}
 }
 
 extern unsigned long cmdline_memory_size;
@@ -959,20 +1158,7 @@
 	pt  = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
 	pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
 	__save_and_cli(flags);
-	__asm__ __volatile__("
-	stxa	%1, [%0] %3
-	stxa	%2, [%5] %4
-	membar	#Sync
-	flush	%%g6
-	nop
-	nop
-	nop"
-	: /* No outputs */
-	: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
-	  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
-	: "memory");
-	if (((unsigned long)&_end) >= KERNBASE + 0x340000) {
-		second_alias_page = alias_base + 0x400000;
+	if (tlb_type == spitfire) {
 		__asm__ __volatile__("
 		stxa	%1, [%0] %3
 		stxa	%2, [%5] %4
@@ -982,9 +1168,52 @@
 		nop
 		nop"
 		: /* No outputs */
-		: "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000),
-		  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
+		: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
+		  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
 		: "memory");
+		if (((unsigned long)&_end) >= KERNBASE + 0x340000) {
+			second_alias_page = alias_base + 0x400000;
+			__asm__ __volatile__("
+			stxa	%1, [%0] %3
+			stxa	%2, [%5] %4
+			membar	#Sync
+			flush	%%g6
+			nop
+			nop
+			nop"
+			: /* No outputs */
+			: "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000),
+			  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
+			: "memory");
+		}
+	} else if (tlb_type == cheetah) {
+		__asm__ __volatile__("
+		stxa	%1, [%0] %3
+		stxa	%2, [%5] %4
+		membar	#Sync
+		flush	%%g6
+		nop
+		nop
+		nop"
+		: /* No outputs */
+		: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
+		  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" ((0<<16) | (13<<3))
+		: "memory");
+		if (((unsigned long)&_end) >= KERNBASE + 0x340000) {
+			second_alias_page = alias_base + 0x400000;
+			__asm__ __volatile__("
+			stxa	%1, [%0] %3
+			stxa	%2, [%5] %4
+			membar	#Sync
+			flush	%%g6
+			nop
+			nop
+			nop"
+			: /* No outputs */
+			: "r" (TLB_TAG_ACCESS), "r" (second_alias_page), "r" (pt + 0x400000),
+			  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" ((0<<16) | (12<<3))
+			: "memory");
+		}
 	}
 	__restore_flags(flags);
 	
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.4.2/linux/arch/sparc64/mm/ultra.S	Thu Nov  9 15:57:41 2000
+++ linux/arch/sparc64/mm/ultra.S	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.48 2000/11/06 06:59:04 davem Exp $
+/* $Id: ultra.S,v 1.49 2001/03/02 03:12:00 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -59,6 +59,7 @@
 /*IC5*/	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
+	/* XXX Spitfire dependency... */
 	mov		(62 << 3), %g2
 
 	/* Spitfire Errata #32 workaround. */
@@ -469,6 +470,7 @@
 	stx		%g0, [%g4 + %lo(errata32_hwbug)]
 
 2:	add		%g2, 1, %g2
+	/* XXX Spitfire dependency... */
 	cmp		%g2, 63
 	ble,pt		%icc, 1b
 	 sll		%g2, 3, %g3
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.4.2/linux/arch/sparc64/solaris/misc.c	Fri Dec 29 14:07:21 2000
+++ linux/arch/sparc64/solaris/misc.c	Mon Mar 19 12:35:10 2001
@@ -92,12 +92,12 @@
 	ret_type = flags & _MAP_NEW;
 	flags &= ~_MAP_NEW;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	retval = do_mmap(file,
 			 (unsigned long) addr, (unsigned long) len,
 			 (unsigned long) prot, (unsigned long) flags, off);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if(!ret_type)
 		retval = ((retval < 0xf0000000) ? 0 : retval);
 	                        
diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/char/i2c.c linux/drivers/acorn/char/i2c.c
--- v2.4.2/linux/drivers/acorn/char/i2c.c	Mon Sep 18 15:15:21 2000
+++ linux/drivers/acorn/char/i2c.c	Fri Mar  2 18:38:37 2001
@@ -122,43 +122,62 @@
 #define SCL		0x02
 #define SDA		0x01
 
-static int ioc_control;
+/*
+ * We must preserve all non-i2c output bits in IOC_CONTROL.
+ * Note also that we need to preserve the value of SCL and
+ * SDA outputs as well (which may be different from the
+ * values read back from IOC_CONTROL).
+ */
+static u_int force_ones;
 
 static void ioc_setscl(void *data, int state)
 {
+	u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+	u_int ones = force_ones;
+
 	if (state)
-		ioc_control |= SCL;
+		ones |= SCL;
 	else
-		ioc_control &= ~SCL;
- 	outb(ioc_control, IOC_CONTROL);
+		ones &= ~SCL;
+
+	force_ones = ones;
+
+ 	ioc_writeb(ioc_control | ones, IOC_CONTROL);
 }
 
 static void ioc_setsda(void *data, int state)
 {
+	u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+	u_int ones = force_ones;
+
 	if (state)
-		ioc_control |= SDA;
+		ones |= SDA;
 	else
-		ioc_control &= ~SDA;
- 	outb(ioc_control, IOC_CONTROL);
+		ones &= ~SDA;
+
+	force_ones = ones;
+
+ 	ioc_writeb(ioc_control | ones, IOC_CONTROL);
 }
 
 static int ioc_getscl(void *data)
 {
-	return (inb(IOC_CONTROL) & SCL) != 0;
+	return (ioc_readb(IOC_CONTROL) & SCL) != 0;
 }
 
 static int ioc_getsda(void *data)
 {
-	return (inb(IOC_CONTROL) & SDA) != 0;
+	return (ioc_readb(IOC_CONTROL) & SDA) != 0;
 }
 
 static struct i2c_algo_bit_data ioc_data = {
-	NULL,
-	ioc_setsda,
-	ioc_setscl,
-	ioc_getsda,
-	ioc_getscl,
-	80, 80, 100
+	setsda:		ioc_setsda,
+	setscl:		ioc_setscl,
+	getsda:		ioc_getsda,
+	getscl:		ioc_getscl,
+	udelay:		 80,
+	mdelay:		 80,
+	timeout:	100
 };
 
 static int ioc_client_reg(struct i2c_client *client)
@@ -184,22 +203,16 @@
 }
 
 static struct i2c_adapter ioc_ops = {
-	"IOC/IOMD",
-	I2C_HW_B_IOC,
-	NULL,
-	&ioc_data,
-	NULL,
-	NULL,
-	ioc_client_reg,
-	ioc_client_unreg
+	name:			"IOC/IOMD",
+	id:			I2C_HW_B_IOC,
+	algo_data:		&ioc_data,
+	client_register:	ioc_client_reg,
+	client_unregister:	ioc_client_unreg
 };
 
 static int __init i2c_ioc_init(void)
 {
-	ioc_control = inb(IOC_CONTROL) | FORCE_ONES;
-
-	ioc_setscl(NULL, 1);
-	ioc_setsda(NULL, 1);
+	force_ones = FORCE_ONES | SCL | SDA;
 
 	return i2c_bit_add_bus(&ioc_ops);
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/char/pcf8583.c linux/drivers/acorn/char/pcf8583.c
--- v2.4.2/linux/drivers/acorn/char/pcf8583.c	Wed Feb 21 18:20:16 2001
+++ linux/drivers/acorn/char/pcf8583.c	Fri Mar  2 18:38:37 2001
@@ -20,16 +20,16 @@
 static struct i2c_driver pcf8583_driver;
 
 static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x50, 0x51, I2C_CLIENT_END };
+static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END };
 
 static struct i2c_client_address_data addr_data = {
-	force:			ignore,
+	normal_i2c:		normal_addr,
+	normal_i2c_range:	ignore,
+	probe:			ignore,
+	probe_range:		ignore,
 	ignore:			ignore,
 	ignore_range:		ignore,
-	normal_i2c:		ignore,
-	normal_i2c_range:	normal_addr,
-	probe:			ignore,
-	probe_range:		ignore
+	force:			ignore,
 };
 
 #define DAT(x) ((unsigned int)(x->data))
@@ -86,7 +86,10 @@
 	};
 	int ret = -EIO;
 
-	if (i2c_transfer(client->adapter, msgs, 2) == 2) {
+	memset(buf, 0, sizeof(buf));
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret == 2) {
 		dt->year_off = buf[4] >> 6;
 		dt->wday     = buf[5] >> 5;
 
@@ -126,6 +129,8 @@
 	}
 
 	ret = i2c_master_send(client, (char *)buf, len);
+	if (ret == len)
+		ret = 0;
 
 	buf[1] = DAT(client);
 	i2c_master_send(client, (char *)buf, 2);
@@ -219,12 +224,12 @@
 }
 
 static struct i2c_driver pcf8583_driver = {
-	"PCF8583",
-	I2C_DRIVERID_PCF8583,
-	I2C_DF_NOTIFY,
-	pcf8583_probe,
-	pcf8583_detach,
-	pcf8583_command
+	name:		"PCF8583",
+	id:		I2C_DRIVERID_PCF8583,
+	flags:		I2C_DF_NOTIFY,
+	attach_adapter:	pcf8583_probe,
+	detach_client:	pcf8583_detach,
+	command:	pcf8583_command
 };
 
 static __init int pcf8583_init(void)
diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- v2.4.2/linux/drivers/acorn/scsi/acornscsi.c	Mon Sep 18 15:15:22 2000
+++ linux/drivers/acorn/scsi/acornscsi.c	Fri Mar  2 18:38:37 2001
@@ -1248,7 +1248,7 @@
 
 /*
  * Function: void acornscsi_dma_adjust(AS_Host *host)
- * Purpose : adjust DMA pointers & count for bytes transfered to
+ * Purpose : adjust DMA pointers & count for bytes transferred to
  *	     SBIC but not SCSI bus.
  * Params  : host - host to adjust DMA count for
  */
diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- v2.4.2/linux/drivers/acorn/scsi/cumana_2.c	Wed Feb 21 18:20:16 2001
+++ linux/drivers/acorn/scsi/cumana_2.c	Fri Mar  2 18:38:37 2001
@@ -90,7 +90,7 @@
 /*
  * Use term=0,1,0,0,0 to turn terminators on/off
  */
-int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
 
 #define NR_SG	256
 
diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c
--- v2.4.2/linux/drivers/acorn/scsi/eesox.c	Wed Feb 21 18:20:16 2001
+++ linux/drivers/acorn/scsi/eesox.c	Fri Mar  2 18:38:37 2001
@@ -88,7 +88,7 @@
 /*
  * Use term=0,1,0,0,0 to turn terminators on/off
  */
-int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
 
 #define NR_SG	256
 
diff -u --recursive --new-file v2.4.2/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c
--- v2.4.2/linux/drivers/acorn/scsi/powertec.c	Wed Feb 21 18:20:16 2001
+++ linux/drivers/acorn/scsi/powertec.c	Fri Mar  2 18:38:37 2001
@@ -87,7 +87,7 @@
 /*
  * Use term=0,1,0,0,0 to turn terminators on/off
  */
-int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
 
 #define NR_SG	256
 
diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/Makefile linux/drivers/acpi/Makefile
--- v2.4.2/linux/drivers/acpi/Makefile	Sat Feb  3 19:51:25 2001
+++ linux/drivers/acpi/Makefile	Sat Mar  3 17:46:47 2001
@@ -20,14 +20,6 @@
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
 
-# genksyms only reads $(CFLAGS), it should really read $(EXTRA_CFLAGS) as well.
-# Without EXTRA_CFLAGS the gcc pass for genksyms fails, resulting in an empty
-# include/linux/modules/acpi_ksyms.ver.  Changing genkyms to use EXTRA_CFLAGS
-# will hit everything, too risky in 2.4.0-prerelease.  Bandaid by tweaking
-# CFLAGS only for .ver targets.  Review after 2.4.0 release.  KAO
-
-$(MODINCL)/%.ver: CFLAGS := -I./include $(CFLAGS)
-
 acpi-subdirs := common dispatcher events hardware \
 		interpreter namespace parser resources tables
 
diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/events/evsci.c linux/drivers/acpi/events/evsci.c
--- v2.4.2/linux/drivers/acpi/events/evsci.c	Sat Feb  3 19:51:25 2001
+++ linux/drivers/acpi/events/evsci.c	Tue Mar  6 19:44:36 2001
@@ -177,7 +177,7 @@
  * PARAMETERS:  Event       Event that generated an SCI.
  *
  * RETURN:      Number of SCI's for requested event since last time
- *              Sci_occured() was called for this event.
+ *              Sci_occurred() was called for this event.
  *
  * DESCRIPTION: Checks to see if SCI has been generated from requested source
  *              since the last time this function was called.
diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/include/acconfig.h linux/drivers/acpi/include/acconfig.h
--- v2.4.2/linux/drivers/acpi/include/acconfig.h	Wed Feb 21 18:20:17 2001
+++ linux/drivers/acpi/include/acconfig.h	Tue Mar  6 19:44:36 2001
@@ -89,7 +89,7 @@
 /*
  * Debugger threading model
  * Use single threaded if the entire subsystem is contained in an application
- * Use multiple threaded when the the subsystem is running in the kernel.
+ * Use multiple threaded when the subsystem is running in the kernel.
  *
  * By default the model is single threaded if ACPI_APPLICATION is set,
  * multi-threaded if ACPI_APPLICATION is not set.
diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/interpreter/amstore.c linux/drivers/acpi/interpreter/amstore.c
--- v2.4.2/linux/drivers/acpi/interpreter/amstore.c	Wed Feb 21 18:20:17 2001
+++ linux/drivers/acpi/interpreter/amstore.c	Tue Mar  6 19:44:36 2001
@@ -190,7 +190,7 @@
  * FUNCTION:    Acpi_aml_store_object_to_index
  *
  * PARAMETERS:  *Val_desc           - Value to be stored
- *              *Node           - Named object to recieve the value
+ *              *Node           - Named object to receive the value
  *
  * RETURN:      Status
  *
@@ -390,7 +390,7 @@
  * FUNCTION:    Acpi_aml_store_object_to_node
  *
  * PARAMETERS:  *Source_desc           - Value to be stored
- *              *Node               - Named object to recieve the value
+ *              *Node               - Named object to receive the value
  *
  * RETURN:      Status
  *
diff -u --recursive --new-file v2.4.2/linux/drivers/acpi/namespace/nsinit.c linux/drivers/acpi/namespace/nsinit.c
--- v2.4.2/linux/drivers/acpi/namespace/nsinit.c	Wed Feb 21 18:20:17 2001
+++ linux/drivers/acpi/namespace/nsinit.c	Tue Mar  6 19:44:36 2001
@@ -271,7 +271,7 @@
 	}
 
 	else {
-		/* Count of successfull INIs */
+		/* Count of successful INIs */
 
 		info->num_INI++;
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.4.2/linux/drivers/block/ll_rw_blk.c	Wed Feb 21 18:20:18 2001
+++ linux/drivers/block/ll_rw_blk.c	Fri Mar 23 11:45:28 2001
@@ -954,6 +954,8 @@
  */
 void submit_bh(int rw, struct buffer_head * bh)
 {
+	int count = bh->b_size >> 9;
+
 	if (!test_bit(BH_Lock, &bh->b_state))
 		BUG();
 
@@ -964,16 +966,16 @@
 	 * further remap this.
 	 */
 	bh->b_rdev = bh->b_dev;
-	bh->b_rsector = bh->b_blocknr * (bh->b_size >> 9);
+	bh->b_rsector = bh->b_blocknr * count;
 
 	generic_make_request(rw, bh);
 
 	switch (rw) {
 		case WRITE:
-			kstat.pgpgout++;
+			kstat.pgpgout += count;
 			break;
 		default:
-			kstat.pgpgin++;
+			kstat.pgpgin += count;
 			break;
 	}
 }
@@ -1238,9 +1240,6 @@
 #endif
 #ifdef CONFIG_BLK_DEV_RAM
 	rd_init();
-#endif
-#ifdef CONFIG_BLK_DEV_LOOP
-	loop_init();
 #endif
 #ifdef CONFIG_ISP16_CDI
 	isp16_init();
diff -u --recursive --new-file v2.4.2/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.4.2/linux/drivers/block/loop.c	Wed Feb 21 18:20:18 2001
+++ linux/drivers/block/loop.c	Tue Mar  6 19:35:36 2001
@@ -31,11 +31,14 @@
  * max_loop=<1-255> to the kernel on boot.
  * Erik I. Bolsĝ, <eriki@himolde.no>, Oct 31, 1999
  *
+ * Completely rewrite request handling to be make_request_fn style and
+ * non blocking, pushing work to a helper thread. Lots of fixes from
+ * Al Viro too.
+ * Jens Axboe <axboe@suse.de>, Nov 2000
+ *
  * Still To Fix:
  * - Advisory locking is ignored here. 
  * - Should use an own CAP_* category instead of CAP_SYS_ADMIN 
- * - Should use the underlying filesystems/devices read function if possible
- *   to support read ahead (and for write)
  *
  * WARNING/FIXME:
  * - The block number as IV passing to low level transfer functions is broken:
@@ -48,6 +51,7 @@
  *   number.
  */ 
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -56,9 +60,13 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/major.h>
-
+#include <linux/wait.h>
+#include <linux/blk.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 
@@ -66,40 +74,28 @@
 
 #define MAJOR_NR LOOP_MAJOR
 
-#define DEVICE_NAME "loop"
-#define DEVICE_REQUEST do_lo_request
-#define DEVICE_NR(device) (MINOR(device))
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-#define DEVICE_NO_RANDOM
-#define TIMEOUT_VALUE (6 * HZ)
-#include <linux/blk.h>
-
-#include <linux/slab.h>
 static int max_loop = 8;
 static struct loop_device *loop_dev;
 static int *loop_sizes;
 static int *loop_blksizes;
 static devfs_handle_t devfs_handle;      /*  For the directory */
 
-#define FALSE 0
-#define TRUE (!FALSE)
-
 /*
  * Transfer functions
  */
 static int transfer_none(struct loop_device *lo, int cmd, char *raw_buf,
-		  char *loop_buf, int size, int real_block)
+			 char *loop_buf, int size, int real_block)
 {
 	if (cmd == READ)
 		memcpy(loop_buf, raw_buf, size);
 	else
 		memcpy(raw_buf, loop_buf, size);
+
 	return 0;
 }
 
 static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf,
-		 char *loop_buf, int size, int real_block)
+			char *loop_buf, int size, int real_block)
 {
 	char	*in, *out, *key;
 	int	i, keysize;
@@ -111,17 +107,18 @@
 		in = loop_buf;
 		out = raw_buf;
 	}
+
 	key = lo->lo_encrypt_key;
 	keysize = lo->lo_encrypt_key_size;
-	for (i=0; i < size; i++)
+	for (i = 0; i < size; i++)
 		*out++ = *in++ ^ key[(i & 511) % keysize];
 	return 0;
 }
 
 static int none_status(struct loop_device *lo, struct loop_info *info)
 {
-	return 0; 
-} 
+	return 0;
+}
 
 static int xor_status(struct loop_device *lo, struct loop_info *info)
 {
@@ -133,7 +130,7 @@
 struct loop_func_table none_funcs = { 
 	number: LO_CRYPT_NONE,
 	transfer: transfer_none,
-	init: none_status
+	init: none_status,
 }; 	
 
 struct loop_func_table xor_funcs = { 
@@ -150,39 +147,41 @@
 
 #define MAX_DISK_SIZE 1024*1024*1024
 
-static void figure_loop_size(struct loop_device *lo)
+static int compute_loop_size(struct loop_device *lo, struct dentry * lo_dentry, kdev_t lodev)
 {
-	int	size;
-
-	if (S_ISREG(lo->lo_dentry->d_inode->i_mode))
-		size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
-	else {
-		kdev_t lodev = lo->lo_device;
-		if (blk_size[MAJOR(lodev)])
-			size = blk_size[MAJOR(lodev)][MINOR(lodev)] -
+	if (S_ISREG(lo_dentry->d_inode->i_mode))
+		return (lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
+	if (blk_size[MAJOR(lodev)])
+		return blk_size[MAJOR(lodev)][MINOR(lodev)] -
                                 (lo->lo_offset >> BLOCK_SIZE_BITS);
-		else
-			size = MAX_DISK_SIZE;
-	}
+	return MAX_DISK_SIZE;
+}
 
-	loop_sizes[lo->lo_number] = size;
+static void figure_loop_size(struct loop_device *lo)
+{
+	loop_sizes[lo->lo_number] = compute_loop_size(lo,
+					lo->lo_backing_file->f_dentry,
+					lo->lo_device);
 }
 
-static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
-	int blksize)
+static int lo_send(struct loop_device *lo, struct buffer_head *bh, int bsize,
+		   loff_t pos)
 {
 	struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
-	struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping;
+	struct address_space *mapping = file->f_dentry->d_inode->i_mapping;
 	struct address_space_operations *aops = mapping->a_ops;
 	struct page *page;
-	char *kaddr;
+	char *kaddr, *data;
 	unsigned long index;
 	unsigned size, offset;
+	int len;
 
 	index = pos >> PAGE_CACHE_SHIFT;
 	offset = pos & (PAGE_CACHE_SIZE - 1);
+	len = bh->b_size;
+	data = bh->b_data;
 	while (len > 0) {
-		int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize;
+		int IV = index * (PAGE_CACHE_SIZE/bsize) + offset/bsize;
 		size = PAGE_CACHE_SIZE - offset;
 		if (size > len)
 			size = len;
@@ -193,7 +192,8 @@
 		if (aops->prepare_write(file, page, offset, offset+size))
 			goto unlock;
 		kaddr = page_address(page);
-		if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
+		flush_dcache_page(page);
+		if (lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV))
 			goto write_fail;
 		if (aops->commit_write(file, page, offset, offset+size))
 			goto unlock;
@@ -203,6 +203,7 @@
 		index++;
 		pos += size;
 		UnlockPage(page);
+		deactivate_page(page);
 		page_cache_release(page);
 	}
 	return 0;
@@ -213,6 +214,7 @@
 	kunmap(page);
 unlock:
 	UnlockPage(page);
+	deactivate_page(page);
 	page_cache_release(page);
 fail:
 	return -1;
@@ -221,7 +223,7 @@
 struct lo_read_data {
 	struct loop_device *lo;
 	char *data;
-	int blksize;
+	int bsize;
 };
 
 static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
@@ -230,16 +232,15 @@
 	unsigned long count = desc->count;
 	struct lo_read_data *p = (struct lo_read_data*)desc->buf;
 	struct loop_device *lo = p->lo;
-	int IV = page->index * (PAGE_CACHE_SIZE/p->blksize) + offset/p->blksize;
+	int IV = page->index * (PAGE_CACHE_SIZE/p->bsize) + offset/p->bsize;
 
 	if (size > count)
 		size = count;
 
 	kaddr = kmap(page);
-	if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
+	if (lo_do_transfer(lo, READ, kaddr + offset, p->data, size, IV)) {
 		size = 0;
-		printk(KERN_ERR "loop: transfer error block %ld\n",
-		       page->index);
+		printk(KERN_ERR "loop: transfer error block %ld\n",page->index);
 		desc->error = -EINVAL;
 	}
 	kunmap(page);
@@ -250,160 +251,345 @@
 	return size;
 }
 
-static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos,
-	int blksize)
+static int lo_receive(struct loop_device *lo, struct buffer_head *bh, int bsize,
+		      loff_t pos)
 {
-	struct file *file = lo->lo_backing_file;
 	struct lo_read_data cookie;
 	read_descriptor_t desc;
+	struct file *file;
 
 	cookie.lo = lo;
-	cookie.data = data;
-	cookie.blksize = blksize;
+	cookie.data = bh->b_data;
+	cookie.bsize = bsize;
 	desc.written = 0;
-	desc.count = len;
+	desc.count = bh->b_size;
 	desc.buf = (char*)&cookie;
 	desc.error = 0;
+	spin_lock_irq(&lo->lo_lock);
+	file = lo->lo_backing_file;
+	spin_unlock_irq(&lo->lo_lock);
 	do_generic_file_read(file, &pos, &desc, lo_read_actor);
 	return desc.error;
 }
 
-static void do_lo_request(request_queue_t * q)
+static inline int loop_get_bs(struct loop_device *lo)
+{
+	int bs = 0;
+
+	if (blksize_size[MAJOR(lo->lo_device)])
+		bs = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)];
+	if (!bs)
+		bs = BLOCK_SIZE;	
+
+	return bs;
+}
+
+static inline unsigned long loop_get_iv(struct loop_device *lo,
+					unsigned long sector)
+{
+	int bs = loop_get_bs(lo);
+	unsigned long offset, IV;
+
+	IV = sector / (bs >> 9) + lo->lo_offset / bs;
+	offset = ((sector % (bs >> 9)) << 9) + lo->lo_offset % bs;
+	if (offset >= bs)
+		IV++;
+
+	return IV;
+}
+
+static int do_bh_filebacked(struct loop_device *lo, struct buffer_head *bh, int rw)
 {
-	int	block, offset, len, blksize, size;
-	char	*dest_addr;
-	struct loop_device *lo;
-	struct buffer_head *bh;
-	struct request *current_request;
 	loff_t pos;
+	int ret;
+
+	pos = ((loff_t) bh->b_rsector << 9) + lo->lo_offset;
+
+	if (rw == WRITE)
+		ret = lo_send(lo, bh, loop_get_bs(lo), pos);
+	else
+		ret = lo_receive(lo, bh, loop_get_bs(lo), pos);
+
+	return ret;
+}
+
+static void loop_put_buffer(struct buffer_head *bh)
+{
+	if (bh) {
+		kunmap(bh->b_page);
+		__free_page(bh->b_page);
+		kmem_cache_free(bh_cachep, bh);
+	}
+}
+
+/*
+ * Add buffer_head to back of pending list
+ */
+static void loop_add_bh(struct loop_device *lo, struct buffer_head *bh)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&lo->lo_lock, flags);
+	if (lo->lo_bhtail) {
+		lo->lo_bhtail->b_reqnext = bh;
+		lo->lo_bhtail = bh;
+	} else
+		lo->lo_bh = lo->lo_bhtail = bh;
+	spin_unlock_irqrestore(&lo->lo_lock, flags);
+
+	up(&lo->lo_bh_mutex);
+}
+
+/*
+ * Grab first pending buffer
+ */
+static struct buffer_head *loop_get_bh(struct loop_device *lo)
+{
+	struct buffer_head *bh;
+
+	spin_lock_irq(&lo->lo_lock);
+	if ((bh = lo->lo_bh)) {
+		if (bh == lo->lo_bhtail)
+			lo->lo_bhtail = NULL;
+		lo->lo_bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+	}
+	spin_unlock_irq(&lo->lo_lock);
+
+	return bh;
+}
+
+/*
+ * when buffer i/o has completed. if BH_Dirty is set, this was a WRITE
+ * and lo->transfer stuff has already been done. if not, it was a READ
+ * so queue it for the loop thread and let it do the transfer out of
+ * b_end_io context (we don't want to do decrypt of a page with irqs
+ * disabled)
+ */
+static void loop_end_io_transfer(struct buffer_head *bh, int uptodate)
+{
+	struct loop_device *lo = &loop_dev[MINOR(bh->b_dev)];
+
+	if (!uptodate || test_bit(BH_Dirty, &bh->b_state)) {
+		struct buffer_head *rbh = bh->b_private;
+
+		rbh->b_end_io(rbh, uptodate);
+		if (atomic_dec_and_test(&lo->lo_pending))
+			up(&lo->lo_bh_mutex);
+		loop_put_buffer(bh);
+	} else
+		loop_add_bh(lo, bh);
+}
+
+static struct buffer_head *loop_get_buffer(struct loop_device *lo,
+					   struct buffer_head *rbh)
+{
+	struct buffer_head *bh;
+
+	do {
+		bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER);
+		if (bh)
+			break;
+
+		run_task_queue(&tq_disk);
+		schedule_timeout(HZ);
+	} while (1);
+	memset(bh, 0, sizeof(*bh));
+
+	bh->b_size = rbh->b_size;
+	bh->b_dev = rbh->b_rdev;
+	spin_lock_irq(&lo->lo_lock);
+	bh->b_rdev = lo->lo_device;
+	spin_unlock_irq(&lo->lo_lock);
+	bh->b_state = (1 << BH_Req) | (1 << BH_Mapped) | (1 << BH_Lock);
+
+	/*
+	 * easy way out, although it does waste some memory for < PAGE_SIZE
+	 * blocks... if highmem bounce buffering can get away with it,
+	 * so can we :-)
+	 */
+	bh->b_page = alloc_page(GFP_BUFFER);
+	bh->b_data = kmap(bh->b_page);
+
+	bh->b_end_io = loop_end_io_transfer;
+	bh->b_rsector = rbh->b_rsector + (lo->lo_offset >> 9);
+	init_waitqueue_head(&bh->b_wait);
+
+	return bh;
+}
+
+static int loop_make_request(request_queue_t *q, int rw, struct buffer_head *rbh)
+{
+	struct buffer_head *bh = NULL;
+	struct loop_device *lo;
+	unsigned long IV;
+
+	if (!buffer_locked(rbh))
+		BUG();
+
+	if (MINOR(rbh->b_rdev) >= max_loop)
+		goto out;
 
-repeat:
-	INIT_REQUEST;
-	current_request=CURRENT;
-	blkdev_dequeue_request(current_request);
-	if (MINOR(current_request->rq_dev) >= max_loop)
-		goto error_out;
-	lo = &loop_dev[MINOR(current_request->rq_dev)];
-	if (!lo->lo_dentry || !lo->transfer)
-		goto error_out;
-	if (current_request->cmd == WRITE) {
+	lo = &loop_dev[MINOR(rbh->b_rdev)];
+	spin_lock_irq(&lo->lo_lock);
+	if (lo->lo_state != Lo_bound)
+		goto inactive;
+	atomic_inc(&lo->lo_pending);
+	spin_unlock_irq(&lo->lo_lock);
+
+	if (rw == WRITE) {
 		if (lo->lo_flags & LO_FLAGS_READ_ONLY)
-			goto error_out;
-	} else if (current_request->cmd != READ) {
-		printk(KERN_ERR "unknown loop device command (%d)?!?",
-		       current_request->cmd);
-		goto error_out;
+			goto err;
+	} else if (rw == READA) {
+		rw = READ;
+	} else if (rw != READ) {
+		printk(KERN_ERR "loop: unknown command (%d)\n", rw);
+		goto err;
 	}
 
-	dest_addr = current_request->buffer;
-	len = current_request->current_nr_sectors << 9;
+#if CONFIG_HIGHMEM
+	rbh = create_bounce(rw, rbh);
+#endif
 
-	blksize = BLOCK_SIZE;
-	if (blksize_size[MAJOR(lo->lo_device)]) {
-	    blksize = blksize_size[MAJOR(lo->lo_device)][MINOR(lo->lo_device)];
-	    if (!blksize)
-	      blksize = BLOCK_SIZE;
+	/*
+	 * file backed, queue for loop_thread to handle
+	 */
+	if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
+		if (rw == WRITE)
+			set_bit(BH_Dirty, &rbh->b_state);
+		loop_add_bh(lo, rbh);
+		return 0;
 	}
 
-	if (lo->lo_flags & LO_FLAGS_DO_BMAP)
-		goto file_backed;
+	/*
+	 * piggy old buffer on original, and submit for I/O
+	 */
+	bh = loop_get_buffer(lo, rbh);
+	bh->b_private = rbh;
+	IV = loop_get_iv(lo, bh->b_rsector);
+	if (rw == WRITE) {
+		set_bit(BH_Dirty, &bh->b_state);
+		if (lo_do_transfer(lo, WRITE, bh->b_data, rbh->b_data, bh->b_size, IV))
+			goto err;
+	}
 
-	if (blksize < 512) {
-		block = current_request->sector * (512/blksize);
-		offset = 0;
+	generic_make_request(rw, bh);
+	return 0;
+
+err:
+	if (atomic_dec_and_test(&lo->lo_pending))
+		up(&lo->lo_bh_mutex);
+	loop_put_buffer(bh);
+out:
+	buffer_IO_error(rbh);
+	return 0;
+inactive:
+	spin_unlock_irq(&lo->lo_lock);
+	goto out;
+}
+
+static inline void loop_handle_bh(struct loop_device *lo,struct buffer_head *bh)
+{
+	int ret;
+
+	/*
+	 * For block backed loop, we know this is a READ
+	 */
+	if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
+		int rw = !!test_and_clear_bit(BH_Dirty, &bh->b_state);
+
+		ret = do_bh_filebacked(lo, bh, rw);
+		bh->b_end_io(bh, !ret);
 	} else {
-		block = current_request->sector / (blksize >> 9);
-		offset = (current_request->sector % (blksize >> 9)) << 9;
-	}
-	block += lo->lo_offset / blksize;
-	offset += lo->lo_offset % blksize;
-	if (offset >= blksize) {
-		block++;
-		offset -= blksize;
+		struct buffer_head *rbh = bh->b_private;
+		unsigned long IV = loop_get_iv(lo, rbh->b_rsector);
+
+		ret = lo_do_transfer(lo, READ, bh->b_data, rbh->b_data,
+				     bh->b_size, IV);
+
+		rbh->b_end_io(rbh, !ret);
+		loop_put_buffer(bh);
 	}
-	spin_unlock_irq(&io_request_lock);
+}
 
-	while (len > 0) {
+/*
+ * worker thread that handles reads/writes to file backed loop devices,
+ * to avoid blocking in our make_request_fn. it also does loop decrypting
+ * on reads for block backed loop, as that is too heavy to do from
+ * b_end_io context where irqs may be disabled.
+ */
+static int loop_thread(void *data)
+{
+	struct loop_device *lo = data;
+	struct buffer_head *bh;
 
-		size = blksize - offset;
-		if (size > len)
-			size = len;
+	daemonize();
+	exit_files(current);
 
-		bh = getblk(lo->lo_device, block, blksize);
-		if (!bh) {
-			printk(KERN_ERR "loop: device %s: getblk(-, %d, %d) returned NULL",
-				kdevname(lo->lo_device),
-				block, blksize);
-			goto error_out_lock;
-		}
-		if (!buffer_uptodate(bh) && ((current_request->cmd == READ) ||
-					(offset || (len < blksize)))) {
-			ll_rw_block(READ, 1, &bh);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh)) {
-				brelse(bh);
-				goto error_out_lock;
-			}
-		}
+	sprintf(current->comm, "loop%d", lo->lo_number);
 
-		if ((lo->transfer)(lo, current_request->cmd,
-				   bh->b_data + offset,
-				   dest_addr, size, block)) {
-			printk(KERN_ERR "loop: transfer error block %d\n",
-			       block);
-			brelse(bh);
-			goto error_out_lock;
-		}
+	spin_lock_irq(&current->sigmask_lock);
+	sigfillset(&current->blocked);
+	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);
+	spin_unlock_irq(&lo->lo_lock);
+
+	/*
+	 * up sem, we are running
+	 */
+	up(&lo->lo_sem);
 
-		if (current_request->cmd == WRITE) {
-			mark_buffer_uptodate(bh, 1);
-			mark_buffer_dirty(bh);
+	for (;;) {
+		down_interruptible(&lo->lo_bh_mutex);
+		/*
+		 * could be upped because of tear-down, not because of
+		 * pending work
+		 */
+		if (!atomic_read(&lo->lo_pending))
+			break;
+
+		bh = loop_get_bh(lo);
+		if (!bh) {
+			printk("loop: missing bh\n");
+			continue;
 		}
-		brelse(bh);
-		dest_addr += size;
-		len -= size;
-		offset = 0;
-		block++;
-	}
-	goto done;
+		loop_handle_bh(lo, bh);
 
-file_backed:
-	pos = ((loff_t)current_request->sector << 9) + lo->lo_offset;
-	spin_unlock_irq(&io_request_lock);
-	if (current_request->cmd == WRITE) {
-		if (lo_send(lo, dest_addr, len, pos, blksize))
-			goto error_out_lock;
-	} else {
-		if (lo_receive(lo, dest_addr, len, pos, blksize))
-			goto error_out_lock;
+		/*
+		 * upped both for pending work and tear-down, lo_pending
+		 * will hit zero then
+		 */
+		if (atomic_dec_and_test(&lo->lo_pending))
+			break;
 	}
-done:
-	spin_lock_irq(&io_request_lock);
-	current_request->sector += current_request->current_nr_sectors;
-	current_request->nr_sectors -= current_request->current_nr_sectors;
-	list_add(&current_request->queue, &q->queue_head);
-	end_request(1);
-	goto repeat;
-error_out_lock:
-	spin_lock_irq(&io_request_lock);
-error_out:
-	list_add(&current_request->queue, &q->queue_head);
-	end_request(0);
-	goto repeat;
+
+	up(&lo->lo_sem);
+	return 0;
 }
 
-static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
+static int loop_set_fd(struct loop_device *lo, struct file *lo_file, kdev_t dev,
+		       unsigned int arg)
 {
 	struct file	*file;
 	struct inode	*inode;
-	int error;
+	kdev_t		lo_device;
+	int		lo_flags = 0;
+	int		error;
+	int		bs;
 
 	MOD_INC_USE_COUNT;
 
 	error = -EBUSY;
-	if (lo->lo_dentry)
+	if (lo->lo_state != Lo_unbound)
 		goto out;
-
+	 
 	error = -EBADF;
 	file = fget(arg);
 	if (!file)
@@ -412,24 +598,13 @@
 	error = -EINVAL;
 	inode = file->f_dentry->d_inode;
 
-	if (S_ISBLK(inode->i_mode)) {
-		/* dentry will be wired, so... */
-		error = blkdev_get(inode->i_bdev, file->f_mode,
-				   file->f_flags, BDEV_FILE);
-
-		lo->lo_device = inode->i_rdev;
-		lo->lo_flags = 0;
-
-		/* Backed by a block device - don't need to hold onto
-		   a file structure */
-		lo->lo_backing_file = NULL;
+	if (!(file->f_mode & FMODE_WRITE))
+		lo_flags |= LO_FLAGS_READ_ONLY;
 
-		if (error)
-			goto out_putf;
+	if (S_ISBLK(inode->i_mode)) {
+		lo_device = inode->i_rdev;
 	} else if (S_ISREG(inode->i_mode)) {
-		struct address_space_operations *aops;
-
-		aops = inode->i_mapping->a_ops;
+		struct address_space_operations *aops = inode->i_mapping->a_ops;
 		/*
 		 * If we can't read - sorry. If we only can't write - well,
 		 * it's going to be read-only.
@@ -439,57 +614,50 @@
 			goto out_putf;
 
 		if (!aops->prepare_write || !aops->commit_write)
-			lo->lo_flags |= LO_FLAGS_READ_ONLY;
-
-		error = get_write_access(inode);
-		if (error)
-			goto out_putf;
-
-		/* Backed by a regular file - we need to hold onto a file
-		   structure for this file.  Friggin' NFS can't live without
-		   it on write and for reading we use do_generic_file_read(),
-		   so...  We create a new file structure based on the one
-		   passed to us via 'arg'.  This is to avoid changing the file
-		   structure that the caller is using */
-
-		lo->lo_device = inode->i_dev;
-		lo->lo_flags |= LO_FLAGS_DO_BMAP;
-
-		error = -ENFILE;
-		lo->lo_backing_file = get_empty_filp();
-		if (lo->lo_backing_file == NULL) {
-			put_write_access(inode);
-			goto out_putf;
-		}
-
-		lo->lo_backing_file->f_mode = file->f_mode;
-		lo->lo_backing_file->f_pos = file->f_pos;
-		lo->lo_backing_file->f_flags = file->f_flags;
-		lo->lo_backing_file->f_owner = file->f_owner;
-		lo->lo_backing_file->f_dentry = file->f_dentry;
-		lo->lo_backing_file->f_vfsmnt = mntget(file->f_vfsmnt);
-		lo->lo_backing_file->f_op = fops_get(file->f_op);
-		lo->lo_backing_file->private_data = file->private_data;
-		file_moveto(lo->lo_backing_file, file);
+			lo_flags |= LO_FLAGS_READ_ONLY;
 
+		lo_device = inode->i_dev;
+		lo_flags |= LO_FLAGS_DO_BMAP;
 		error = 0;
-	}
+	} else
+		goto out_putf;
+
+	get_file(file);
 
-	if (IS_RDONLY (inode) || is_read_only(lo->lo_device))
-		lo->lo_flags |= LO_FLAGS_READ_ONLY;
+	if (IS_RDONLY (inode) || is_read_only(lo_device)
+	    || !(lo_file->f_mode & FMODE_WRITE))
+		lo_flags |= LO_FLAGS_READ_ONLY;
 
-	set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0);
+	set_device_ro(dev, (lo_flags & LO_FLAGS_READ_ONLY) != 0);
 
-	lo->lo_dentry = dget(file->f_dentry);
+	lo->lo_device = lo_device;
+	lo->lo_flags = lo_flags;
+	lo->lo_backing_file = file;
 	lo->transfer = NULL;
 	lo->ioctl = NULL;
 	figure_loop_size(lo);
+	lo->old_gfp_mask = inode->i_mapping->gfp_mask;
+	inode->i_mapping->gfp_mask = GFP_BUFFER;
+
+	bs = 0;
+	if (blksize_size[MAJOR(inode->i_rdev)])
+		bs = blksize_size[MAJOR(inode->i_rdev)][MINOR(inode->i_rdev)];
+	if (!bs)
+		bs = BLOCK_SIZE;
+
+	set_blocksize(dev, bs);
+
+	lo->lo_bh = lo->lo_bhtail = NULL;
+	kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	down(&lo->lo_sem);
+
+	fput(file);
+	return 0;
 
  out_putf:
 	fput(file);
  out:
-	if (error)
-		MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 	return error;
 }
 
@@ -525,27 +693,25 @@
 
 static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
 {
-	struct dentry *dentry = lo->lo_dentry;
+	struct file *filp = lo->lo_backing_file;
+	int gfp = lo->old_gfp_mask;
 
-	if (!dentry)
+	if (lo->lo_state != Lo_bound)
 		return -ENXIO;
 	if (lo->lo_refcnt > 1)	/* we needed one fd for the ioctl */
 		return -EBUSY;
+	if (filp==NULL)
+		return -EINVAL;
 
-	if (S_ISBLK(dentry->d_inode->i_mode))
-		blkdev_put(dentry->d_inode->i_bdev, BDEV_FILE);
+	spin_lock_irq(&lo->lo_lock);
+	lo->lo_state = Lo_rundown;
+	if (atomic_dec_and_test(&lo->lo_pending))
+		up(&lo->lo_bh_mutex);
+	spin_unlock_irq(&lo->lo_lock);
 
-	lo->lo_dentry = NULL;
+	down(&lo->lo_sem);
 
-	if (lo->lo_backing_file != NULL) {
-		struct file *filp = lo->lo_backing_file;
-		if ((filp->f_mode & FMODE_WRITE) == 0)
-			put_write_access(filp->f_dentry->d_inode);
-		fput(filp);
-		lo->lo_backing_file = NULL;
-	} else {
-		dput(dentry);
-	}
+	lo->lo_backing_file = NULL;
 
 	loop_release_xfer(lo);
 	lo->transfer = NULL;
@@ -554,10 +720,14 @@
 	lo->lo_encrypt_type = 0;
 	lo->lo_offset = 0;
 	lo->lo_encrypt_key_size = 0;
+	lo->lo_flags = 0;
 	memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
 	memset(lo->lo_name, 0, LO_NAME_SIZE);
 	loop_sizes[lo->lo_number] = 0;
 	invalidate_buffers(dev);
+	filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp;
+	lo->lo_state = Lo_unbound;
+	fput(filp);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -571,7 +741,7 @@
 	if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && 
 	    !capable(CAP_SYS_ADMIN))
 		return -EPERM;
-	if (!lo->lo_dentry)
+	if (lo->lo_state != Lo_bound)
 		return -ENXIO;
 	if (copy_from_user(&info, arg, sizeof (struct loop_info)))
 		return -EFAULT; 
@@ -608,15 +778,16 @@
 static int loop_get_status(struct loop_device *lo, struct loop_info *arg)
 {
 	struct loop_info	info;
+	struct file *file = lo->lo_backing_file;
 
-	if (!lo->lo_dentry)
+	if (lo->lo_state != Lo_bound)
 		return -ENXIO;
 	if (!arg)
 		return -EINVAL;
 	memset(&info, 0, sizeof(info));
 	info.lo_number = lo->lo_number;
-	info.lo_device = kdev_t_to_nr(lo->lo_dentry->d_inode->i_dev);
-	info.lo_inode = lo->lo_dentry->d_inode->i_ino;
+	info.lo_device = kdev_t_to_nr(file->f_dentry->d_inode->i_dev);
+	info.lo_inode = file->f_dentry->d_inode->i_ino;
 	info.lo_rdevice = kdev_t_to_nr(lo->lo_device);
 	info.lo_offset = lo->lo_offset;
 	info.lo_flags = lo->lo_flags;
@@ -634,7 +805,7 @@
 	unsigned int cmd, unsigned long arg)
 {
 	struct loop_device *lo;
-	int dev;
+	int dev, err;
 
 	if (!inode)
 		return -EINVAL;
@@ -647,25 +818,36 @@
 	if (dev >= max_loop)
 		return -ENODEV;
 	lo = &loop_dev[dev];
+	down(&lo->lo_ctl_mutex);
 	switch (cmd) {
 	case LOOP_SET_FD:
-		return loop_set_fd(lo, inode->i_rdev, arg);
+		err = loop_set_fd(lo, file, inode->i_rdev, arg);
+		break;
 	case LOOP_CLR_FD:
-		return loop_clr_fd(lo, inode->i_rdev);
+		err = loop_clr_fd(lo, inode->i_rdev);
+		break;
 	case LOOP_SET_STATUS:
-		return loop_set_status(lo, (struct loop_info *) arg);
+		err = loop_set_status(lo, (struct loop_info *) arg);
+		break;
 	case LOOP_GET_STATUS:
-		return loop_get_status(lo, (struct loop_info *) arg);
-	case BLKGETSIZE:   /* Return device size */
-		if (!lo->lo_dentry)
-			return -ENXIO;
-		if (!arg)
-			return -EINVAL;
-		return put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
+		err = loop_get_status(lo, (struct loop_info *) arg);
+		break;
+	case BLKGETSIZE:
+		if (lo->lo_state != Lo_bound) {
+			err = -ENXIO;
+			break;
+		}
+		if (!arg) {
+			err = -EINVAL;
+			break;
+		}
+		err = put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
+		break;
 	default:
-		return lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
+		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
 	}
-	return 0;
+	up(&lo->lo_ctl_mutex);
+	return err;
 }
 
 static int lo_open(struct inode *inode, struct file *file)
@@ -673,7 +855,6 @@
 	struct loop_device *lo;
 	int	dev, type;
 
-
 	if (!inode)
 		return -EINVAL;
 	if (MAJOR(inode->i_rdev) != MAJOR_NR) {
@@ -681,23 +862,25 @@
 		return -ENODEV;
 	}
 	dev = MINOR(inode->i_rdev);
-	if (dev >= max_loop) {
+	if (dev >= max_loop)
 		return -ENODEV;
-	}
+
 	lo = &loop_dev[dev];
+	MOD_INC_USE_COUNT;
+	down(&lo->lo_ctl_mutex);
 
 	type = lo->lo_encrypt_type; 
 	if (type && xfer_funcs[type] && xfer_funcs[type]->lock)
 		xfer_funcs[type]->lock(lo);
 	lo->lo_refcnt++;
-	MOD_INC_USE_COUNT;
+	up(&lo->lo_ctl_mutex);
 	return 0;
 }
 
 static int lo_release(struct inode *inode, struct file *file)
 {
 	struct loop_device *lo;
-	int	dev;
+	int	dev, type;
 
 	if (!inode)
 		return 0;
@@ -709,17 +892,16 @@
 	dev = MINOR(inode->i_rdev);
 	if (dev >= max_loop)
 		return 0;
+
 	lo = &loop_dev[dev];
-	if (lo->lo_refcnt <= 0)
-		printk(KERN_ERR "lo_release: refcount(%d) <= 0\n",
-		       lo->lo_refcnt);
-	else  {
-		int type  = lo->lo_encrypt_type;
-		--lo->lo_refcnt;
-		if (xfer_funcs[type] && xfer_funcs[type]->unlock)
-			xfer_funcs[type]->unlock(lo);
-		MOD_DEC_USE_COUNT;
-	}
+	down(&lo->lo_ctl_mutex);
+	type = lo->lo_encrypt_type;
+	--lo->lo_refcnt;
+	if (xfer_funcs[type] && xfer_funcs[type]->unlock)
+		xfer_funcs[type]->unlock(lo);
+
+	up(&lo->lo_ctl_mutex);
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -732,11 +914,8 @@
 /*
  * And now the modules code and kernel interface.
  */
-#ifdef MODULE
-#define loop_init init_module
 MODULE_PARM(max_loop, "i");
 MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
-#endif
 
 int loop_register_transfer(struct loop_func_table *funcs)
 {
@@ -767,88 +946,88 @@
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-static void no_plug_device(request_queue_t *q, kdev_t device)
-{
-}
-
 int __init loop_init(void) 
 {
 	int	i;
 
-	if (devfs_register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
-		printk(KERN_WARNING "Unable to get major number %d for loop device\n",
-		       MAJOR_NR);
-		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);
-
 	if ((max_loop < 1) || (max_loop > 255)) {
-		printk (KERN_WARNING "loop: invalid max_loop (must be between 1 and 255), using default (8)\n");
+		printk(KERN_WARNING "loop: invalid max_loop (must be between"
+				    " 1 and 255), using default (8)\n");
 		max_loop = 8;
 	}
 
-	printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop);
-
-	loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL);
-	if (!loop_dev) {
-		printk (KERN_ERR "loop: Unable to create loop_dev\n");
-		return -ENOMEM;
+	if (devfs_register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
+		printk(KERN_WARNING "Unable to get major number %d for loop"
+				    " device\n", MAJOR_NR);
+		return -EIO;
 	}
 
-	loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
-	if (!loop_sizes) {
-		printk (KERN_ERR "loop: Unable to create loop_sizes\n");
-		kfree (loop_dev);
-		return -ENOMEM;
-	}
+	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_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL);
-	if (!loop_blksizes) {
-		printk (KERN_ERR "loop: Unable to create loop_blksizes\n");
-		kfree (loop_dev);
-		kfree (loop_sizes);
+	loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
+	if (!loop_dev)
 		return -ENOMEM;
-	}		
 
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
-	blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), no_plug_device);
-	blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR), 0);
-	for (i=0; i < max_loop; i++) {
-		memset(&loop_dev[i], 0, sizeof(struct loop_device));
-		loop_dev[i].lo_number = i;
+	loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
+	if (!loop_sizes)
+		goto out_sizes;
+
+	loop_blksizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
+	if (!loop_blksizes)
+		goto out_blksizes;
+
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request);
+
+	for (i = 0; i < max_loop; i++) {
+		struct loop_device *lo = &loop_dev[i];
+		memset(lo, 0, sizeof(struct loop_device));
+		init_MUTEX(&lo->lo_ctl_mutex);
+		init_MUTEX_LOCKED(&lo->lo_sem);
+		init_MUTEX_LOCKED(&lo->lo_bh_mutex);
+		lo->lo_number = i;
+		spin_lock_init(&lo->lo_lock);
 	}
+
 	memset(loop_sizes, 0, max_loop * sizeof(int));
 	memset(loop_blksizes, 0, max_loop * sizeof(int));
 	blk_size[MAJOR_NR] = loop_sizes;
 	blksize_size[MAJOR_NR] = loop_blksizes;
-	for (i=0; i < max_loop; i++)
-		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &lo_fops, 0);
+	for (i = 0; i < max_loop; i++)
+		register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
 
+	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
+
+out_sizes:
+	kfree(loop_dev);
+out_blksizes:
+	kfree(loop_sizes);
+	printk(KERN_ERR "loop: ran out of memory\n");
+	return -ENOMEM;
 }
 
-#ifdef MODULE
-void cleanup_module(void) 
+void loop_exit(void) 
 {
-	devfs_unregister (devfs_handle);
-	if (devfs_unregister_blkdev(MAJOR_NR, "loop") != 0)
+	devfs_unregister(devfs_handle);
+	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 
-	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-	kfree (loop_dev);
-	kfree (loop_sizes);
-	kfree (loop_blksizes);
+	kfree(loop_dev);
+	kfree(loop_sizes);
+	kfree(loop_blksizes);
 }
-#endif
+
+module_init(loop_init);
+module_exit(loop_exit);
 
 #ifndef MODULE
 static int __init max_loop_setup(char *str)
 {
-	max_loop = simple_strtol(str,NULL,0);
+	max_loop = simple_strtol(str, NULL, 0);
 	return 1;
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.4.2/linux/drivers/block/nbd.c	Mon Oct 30 14:30:33 2000
+++ linux/drivers/block/nbd.c	Tue Mar  6 19:19:21 2001
@@ -18,6 +18,8 @@
  * 97-9-13 Cosmetic changes
  * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines
  * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines <ankry@mif.pg.gda.pl>
+ * 01-2-27 Fix to store proper blockcount for kernel (calculated using
+ *   BLOCK_SIZE_BITS, not device blocksize) <aga@permonline.ru>
  *
  * 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 
@@ -413,16 +415,16 @@
 			nbd_blksize_bits[dev]++;
 			temp >>= 1;
 		}
-		nbd_sizes[dev] = nbd_bytesizes[dev] >> nbd_blksize_bits[dev];
-		nbd_bytesizes[dev] = nbd_sizes[dev] << nbd_blksize_bits[dev];
+		nbd_bytesizes[dev] &= ~(nbd_blksizes[dev]-1); 
+		nbd_sizes[dev] = nbd_bytesizes[dev] >> BLOCK_SIZE_BITS;
 		return 0;
 	case NBD_SET_SIZE:
-		nbd_sizes[dev] = arg >> nbd_blksize_bits[dev];
-		nbd_bytesizes[dev] = nbd_sizes[dev] << nbd_blksize_bits[dev];
+		nbd_bytesizes[dev] = arg & ~(nbd_blksizes[dev]-1); 
+		nbd_sizes[dev] = nbd_bytesizes[dev] >> BLOCK_SIZE_BITS;
 		return 0;
 	case NBD_SET_SIZE_BLOCKS:
-		nbd_sizes[dev] = arg;
-		nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev];
+		nbd_bytesizes[dev] = ((u64) arg) << nbd_blksize_bits[dev]; 
+		nbd_sizes[dev] = nbd_bytesizes[dev] >> BLOCK_SIZE_BITS;
 		return 0;
 	case NBD_DO_IT:
 		if (!lo->file)
@@ -513,7 +515,7 @@
 		nbd_blksizes[i] = 1024;
 		nbd_blksize_bits[i] = 10;
 		nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
-		nbd_sizes[i] = nbd_bytesizes[i] >> nbd_blksize_bits[i];
+		nbd_sizes[i] = nbd_bytesizes[i] >> BLOCK_SIZE_BITS;
 		register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &nbd_fops,
 				nbd_bytesizes[i]>>9);
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.4.2/linux/drivers/cdrom/cdrom.c	Wed Feb 21 18:20:18 2001
+++ linux/drivers/cdrom/cdrom.c	Fri Mar 23 11:45:28 2001
@@ -1171,42 +1171,50 @@
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-	int ret, i;
-	u_char buf[4 + 4 * 20], *base;
+	unsigned char buf[20], *base;
 	struct dvd_layer *layer;
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
+	int ret, layer_num = s->physical.layer_num;
+
+	if (layer_num >= DVD_LAYERS)
+		return -EINVAL;
 
 	init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-	cgc.cmd[6] = s->physical.layer_num;
+	cgc.cmd[6] = layer_num;
 	cgc.cmd[7] = s->type;
 	cgc.cmd[9] = cgc.buflen & 0xff;
 
+	/*
+	 * refrain from reporting errors on non-existing layers (mainly)
+	 */
+	cgc.quiet = 1;
+
 	if ((ret = cdo->generic_packet(cdi, &cgc)))
 		return ret;
 
 	base = &buf[4];
-	layer = &s->physical.layer[0];
+	layer = &s->physical.layer[layer_num];
 
-	/* place the data... really ugly, but at least we won't have to
-	   worry about endianess in userspace or here. */
-	for (i = 0; i < 4; ++i, base += 20, ++layer) {
-		memset(layer, 0, sizeof(*layer));
-		layer->book_version = base[0] & 0xf;
-		layer->book_type = base[0] >> 4;
-		layer->min_rate = base[1] & 0xf;
-		layer->disc_size = base[1] >> 4;
-		layer->layer_type = base[2] & 0xf;
-		layer->track_path = (base[2] >> 4) & 1;
-		layer->nlayers = (base[2] >> 5) & 3;
-		layer->track_density = base[3] & 0xf;
-		layer->linear_density = base[3] >> 4;
-		layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
-		layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
-		layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
-		layer->bca = base[16] >> 7;
-	}
+	/*
+	 * place the data... really ugly, but at least we won't have to
+	 * worry about endianess in userspace.
+	 */
+	memset(layer, 0, sizeof(*layer));
+	layer->book_version = base[0] & 0xf;
+	layer->book_type = base[0] >> 4;
+	layer->min_rate = base[1] & 0xf;
+	layer->disc_size = base[1] >> 4;
+	layer->layer_type = base[2] & 0xf;
+	layer->track_path = (base[2] >> 4) & 1;
+	layer->nlayers = (base[2] >> 5) & 3;
+	layer->track_density = base[3] & 0xf;
+	layer->linear_density = base[3] >> 4;
+	layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
+	layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
+	layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
+	layer->bca = base[16] >> 7;
 
 	return 0;
 }
@@ -1985,7 +1993,7 @@
 		}
 	case CDROMREADAUDIO: {
 		struct cdrom_read_audio ra;
-		int lba;
+		int lba, nr;
 
 		IOCTL_IN(arg, struct cdrom_read_audio, ra);
 
@@ -2002,7 +2010,19 @@
 		if (lba < 0 || ra.nframes <= 0)
 			return -EINVAL;
 
-		if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW, GFP_KERNEL)) == NULL)
+		/*
+		 * start with will ra.nframes size, back down if alloc fails
+		 */
+		nr = ra.nframes;
+		do {
+			cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL);
+			if (cgc.buffer)
+				break;
+
+			nr >>= 1;
+		} while (nr);
+
+		if (!nr)
 			return -ENOMEM;
 
 		if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) {
@@ -2011,12 +2031,16 @@
 		}
 		cgc.data_direction = CGC_DATA_READ;
 		while (ra.nframes > 0) {
-			ret = cdrom_read_block(cdi, &cgc, lba, 1, 1, CD_FRAMESIZE_RAW);
-			if (ret) break;
+			if (nr > ra.nframes)
+				nr = ra.nframes;
+
+			ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW);
+			if (ret)
+				break;
 			__copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW);
-			ra.buf += CD_FRAMESIZE_RAW;
-			ra.nframes--;
-			lba++;
+			ra.buf += CD_FRAMESIZE_RAW * nr;
+			ra.nframes -= nr;
+			lba += nr;
 		}
 		kfree(cgc.buffer);
 		return ret;
diff -u --recursive --new-file v2.4.2/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.4.2/linux/drivers/char/Config.in	Wed Feb 21 18:20:18 2001
+++ linux/drivers/char/Config.in	Tue Mar  6 19:44:34 2001
@@ -133,6 +133,7 @@
    fi
    tristate '  Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
    tristate '  Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+   tristate '  Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
    tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
    tristate '  Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
@@ -142,6 +143,7 @@
          tristate '  NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG
       fi
    fi
+   tristate '  ZF MachZ Watchdog' CONFIG_MACHZ_WDT
 fi
 endmenu
 
@@ -176,7 +178,7 @@
 fi
 endmenu
 
-tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
+dep_tristate '/dev/agpgart (AGP Support)' CONFIG_AGP $CONFIG_DRM_AGP
 if [ "$CONFIG_AGP" != "n" ]; then
    bool '  Intel 440LX/BX/GX and I815/I840/I850 support' CONFIG_AGP_INTEL
    bool '  Intel I810/I815 (on-board) support' CONFIG_AGP_I810
diff -u --recursive --new-file v2.4.2/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.4.2/linux/drivers/char/Makefile	Thu Jan  4 13:00:55 2001
+++ linux/drivers/char/Makefile	Tue Mar  6 19:44:34 2001
@@ -177,6 +177,7 @@
 
 obj-$(CONFIG_PCWATCHDOG) += pcwd.o
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
 obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
 obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
 obj-$(CONFIG_WDT) += wdt.o
@@ -184,6 +185,7 @@
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
 obj-$(CONFIG_I810_TCO) += i810-tco.o
+obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c
--- v2.4.2/linux/drivers/char/advantechwdt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/advantechwdt.c	Tue Mar  6 19:44:34 2001
@@ -0,0 +1,241 @@
+/*
+ *	Advantech Single Board Computer WDT driver for Linux 2.4.x
+ *
+ *	(c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *	Based on acquirewdt.c which is based on wdt.c.
+ *	Original copyright messages:
+ *
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.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.
+ *	
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
+ *
+ */
+
+#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/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+static int advwdt_is_open;
+static spinlock_t advwdt_lock;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ *
+ *	To enable or restart, write the timeout value in seconds (1 to 63)
+ *	to I/O port WDT_START.  To disable, read I/O port WDT_STOP.
+ *	Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
+ *	check your manual (at least the PCA-6159 seems to be different -
+ *	the manual says WDT_STOP is 0x43, not 0x443).
+ *	(0x43 is also a write-only control register for the 8254 timer!)
+ *
+ *	TODO: module parameters to set the I/O port addresses and NOWAYOUT
+ *	option at load time.
+ */
+ 
+#define WDT_STOP 0x443
+#define WDT_START 0x443
+
+#define WD_TIMO 60		/* 1 minute */
+
+/*
+ *	Kernel methods.
+ */
+ 
+static void
+advwdt_ping(void)
+{
+	/* Write a watchdog value */
+	outb_p(WD_TIMO, WDT_START);
+}
+
+static ssize_t
+advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count) {
+		advwdt_ping();
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t
+advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static int
+advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		WDIOF_KEEPALIVEPING, 1, "Advantech WDT"
+	};
+	
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+	  if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
+	    return -EFAULT;
+	  break;
+	  
+	case WDIOC_GETSTATUS:
+	  if (copy_to_user((int *)arg, &advwdt_is_open,  sizeof(int)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_KEEPALIVE:
+	  advwdt_ping();
+	  break;
+
+	default:
+	  return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int
+advwdt_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+		case WATCHDOG_MINOR:
+			spin_lock(&advwdt_lock);
+			if (advwdt_is_open) {
+				spin_unlock(&advwdt_lock);
+				return -EBUSY;
+			}
+			/*
+			 *	Activate 
+			 */
+	 
+			advwdt_is_open = 1;
+			advwdt_ping();
+			spin_unlock(&advwdt_lock);
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+static int
+advwdt_close(struct inode *inode, struct file *file)
+{
+	lock_kernel();
+	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+		spin_lock(&advwdt_lock);
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		inb_p(WDT_STOP);
+#endif		
+		advwdt_is_open = 0;
+		spin_unlock(&advwdt_lock);
+	}
+	unlock_kernel();
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int
+advwdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the WDT off */
+		inb_p(WDT_STOP);
+	}
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	Kernel Interfaces
+ */
+ 
+static struct file_operations advwdt_fops = {
+	owner:		THIS_MODULE,
+	read:		advwdt_read,
+	write:		advwdt_write,
+	ioctl:		advwdt_ioctl,
+	open:		advwdt_open,
+	release:	advwdt_close,
+};
+
+static struct miscdevice advwdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&advwdt_fops
+};
+
+/*
+ *	The WDT needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block advwdt_notifier = {
+	advwdt_notify_sys,
+	NULL,
+	0
+};
+
+static int __init
+advwdt_init(void)
+{
+	printk("WDT driver for Advantech single board computer initialising.\n");
+
+	spin_lock_init(&advwdt_lock);
+	misc_register(&advwdt_miscdev);
+#if WDT_START != WDT_STOP
+	request_region(WDT_STOP, 1, "Advantech WDT");
+#endif
+	request_region(WDT_START, 1, "Advantech WDT");
+	register_reboot_notifier(&advwdt_notifier);
+	return 0;
+}
+
+static void __exit
+advwdt_exit(void)
+{
+	misc_deregister(&advwdt_miscdev);
+	unregister_reboot_notifier(&advwdt_notifier);
+#if WDT_START != WDT_STOP
+	release_region(WDT_STOP,1);
+#endif
+	release_region(WDT_START,1);
+}
+
+module_init(advwdt_init);
+module_exit(advwdt_exit);
+
+/* end of advantechwdt.c */
diff -u --recursive --new-file v2.4.2/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.4.2/linux/drivers/char/agp/agpgart_fe.c	Wed Feb 21 18:20:19 2001
+++ linux/drivers/char/agp/agpgart_fe.c	Tue Mar  6 19:28:32 2001
@@ -1105,7 +1105,8 @@
 	return 0;
 }
 
-static void __exit agp_frontend_cleanup(void)
+void __exit agp_frontend_cleanup(void)
 {
 	misc_deregister(&agp_miscdev);
 }
+
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c
--- v2.4.2/linux/drivers/char/drm/bufs.c	Tue Aug 29 14:09:15 2000
+++ linux/drivers/char/drm/bufs.c	Mon Mar 19 12:35:08 2001
@@ -485,10 +485,10 @@
 		return -EFAULT;
 
 	if (request.count >= dma->buf_count) {
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 		virtual = do_mmap(filp, 0, dma->byte_count,
 				  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
-		up(&current->mm->mmap_sem);
+		up_write(&current->mm->mmap_sem);
 		if (virtual > -1024UL) {
 				/* Real error */
 			retcode = (signed long)virtual;
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h
--- v2.4.2/linux/drivers/char/drm/drmP.h	Thu Jan  4 14:50:49 2001
+++ linux/drivers/char/drm/drmP.h	Fri Mar 23 18:23:49 2001
@@ -43,6 +43,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
+#include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c
--- v2.4.2/linux/drivers/char/drm/i810_dma.c	Mon Dec 11 12:39:44 2000
+++ linux/drivers/char/drm/i810_dma.c	Mon Mar 19 12:35:08 2001
@@ -192,7 +192,7 @@
 	if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
 
 	if(VM_DONTCOPY != 0) {
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 		old_fops = filp->f_op;
 		filp->f_op = &i810_buffer_fops;
 		dev_priv->mmap_buffer = buf;
@@ -208,7 +208,7 @@
 			retcode = (signed int)buf_priv->virtual;
 			buf_priv->virtual = 0;
 		}
-   		up(&current->mm->mmap_sem);
+   		up_write(&current->mm->mmap_sem);
 	} else {
 		buf_priv->virtual = buf_priv->kernel_virtual;
    		buf_priv->currently_mapped = I810_BUF_MAPPED;
@@ -224,7 +224,7 @@
 	if(VM_DONTCOPY != 0) {
 		if(buf_priv->currently_mapped != I810_BUF_MAPPED) 
 			return -EINVAL;
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 #if LINUX_VERSION_CODE < 0x020399
         	retcode = do_munmap((unsigned long)buf_priv->virtual, 
 				    (size_t) buf->total);
@@ -233,7 +233,7 @@
 				    (unsigned long)buf_priv->virtual, 
 				    (size_t) buf->total);
 #endif
-   		up(&current->mm->mmap_sem);
+   		up_write(&current->mm->mmap_sem);
 	}
    	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
    	buf_priv->virtual = 0;
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/mga_bufs.c linux/drivers/char/drm/mga_bufs.c
--- v2.4.2/linux/drivers/char/drm/mga_bufs.c	Sun Oct  1 20:00:00 2000
+++ linux/drivers/char/drm/mga_bufs.c	Mon Mar 19 12:35:08 2001
@@ -549,17 +549,17 @@
 			DRM_DEBUG("map->flags : %x\n", map->flags);
 			DRM_DEBUG("map->handle : %p\n", map->handle);
 			DRM_DEBUG("map->mtrr : %d\n", map->mtrr);
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			virtual = do_mmap(filp, 0, map->size, 
 					  PROT_READ|PROT_WRITE,
 					  MAP_SHARED, 
 					  (unsigned long)map->offset);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 		} else {
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			virtual = do_mmap(filp, 0, dma->byte_count,
 					  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 		}
 		if (virtual > -1024UL) {
 			/* Real error */
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/r128_bufs.c linux/drivers/char/drm/r128_bufs.c
--- v2.4.2/linux/drivers/char/drm/r128_bufs.c	Thu Jan  4 13:03:20 2001
+++ linux/drivers/char/drm/r128_bufs.c	Mon Mar 19 12:35:08 2001
@@ -249,17 +249,17 @@
 				goto done;
 			}
 
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			virtual = do_mmap(filp, 0, map->size,
 					  PROT_READ|PROT_WRITE,
 					  MAP_SHARED,
 					  (unsigned long)map->offset);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 		} else {
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			virtual = do_mmap(filp, 0, dma->byte_count,
 					  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 		}
 		if (virtual > -1024UL) {
 			/* Real error */
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/r128_drv.h linux/drivers/char/drm/r128_drv.h
--- v2.4.2/linux/drivers/char/drm/r128_drv.h	Thu Jan  4 13:03:20 2001
+++ linux/drivers/char/drm/r128_drv.h	Fri Mar  2 18:38:37 2001
@@ -447,6 +447,11 @@
 		DRM_INFO( "ADVANCE_RING() tail=0x%06x wr=0x%06x\n",	\
 			  write, dev_priv->ring.tail );			\
 	}								\
+	if ( write < 32 ) {						\
+		memcpy( dev_priv->ring.end,				\
+			dev_priv->ring.start,				\
+			write * sizeof(u32) );				\
+	}								\
 	r128_flush_write_combine();					\
 	dev_priv->ring.tail = write;					\
 	R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write );			\
diff -u --recursive --new-file v2.4.2/linux/drivers/char/drm/radeon_bufs.c linux/drivers/char/drm/radeon_bufs.c
--- v2.4.2/linux/drivers/char/drm/radeon_bufs.c	Sat Feb  3 19:51:27 2001
+++ linux/drivers/char/drm/radeon_bufs.c	Mon Mar 19 12:35:08 2001
@@ -240,17 +240,17 @@
 				goto done;
 			}
 
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			virtual = do_mmap(filp, 0, map->size,
 					  PROT_READ|PROT_WRITE,
 					  MAP_SHARED,
 					  (unsigned long)map->offset);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 		} else {
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			virtual = do_mmap(filp, 0, dma->byte_count,
 					  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 		}
 		if (virtual > -1024UL) {
 			/* Real error */
diff -u --recursive --new-file v2.4.2/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.4.2/linux/drivers/char/dsp56k.c	Wed Feb 21 18:20:19 2001
+++ linux/drivers/char/dsp56k.c	Fri Mar  2 18:38:37 2001
@@ -265,7 +265,7 @@
 	}
 
 	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 		return -ENXIO;
 	}
 }
@@ -327,7 +327,7 @@
 		return -EFAULT;
 	}
 	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 		return -ENXIO;
 	}
 }
@@ -416,7 +416,7 @@
 		return 0;
 
 	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 		return -ENXIO;
 	}
 }
@@ -469,7 +469,7 @@
 		break;
 
 	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 		return -ENXIO;
 	}
 
@@ -490,7 +490,7 @@
 
 		break;
 	default:
-		printk("DSP56k driver: Unknown minor device: %d\n", dev);
+		printk(KERN_ERR "DSP56k driver: Unknown minor device: %d\n", dev);
 		return -ENXIO;
 	}
 
@@ -511,7 +511,9 @@
 
 static devfs_handle_t devfs_handle;
 
-int __init dsp56k_init(void)
+static const char banner[] __initdata = KERN_INFO "DSP56k driver installed\n";
+
+static int __init dsp56k_init_driver(void)
 {
 	if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
 		printk("DSP56k driver: Hardware not present\n");
@@ -522,27 +524,19 @@
 		printk("DSP56k driver: Unable to register driver\n");
 		return -ENODEV;
 	}
-	devfs_handle = devfs_register (NULL, "dsp56k", DEVFS_FL_DEFAULT,
-				       DSP56K_MAJOR, 0,
-				       S_IFCHR | S_IRUSR | S_IWUSR,
-				       &dsp56k_fops, NULL);
-
-	dsp56k.in_use = 0;
-
-	printk("DSP56k driver installed\n");
+	devfs_handle = devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT,
+				      DSP56K_MAJOR, 0,
+				      S_IFCHR | S_IRUSR | S_IWUSR,
+				      &dsp56k_fops, NULL);
 
+	printk(banner);
 	return 0;
 }
+module_init(dsp56k_init_driver);
 
-#ifdef MODULE
-int init_module(void)
-{
-	return dsp56k_init();
-}
-
-void cleanup_module(void)
+static void __exit dsp56k_cleanup_driver(void)
 {
 	devfs_unregister_chrdev(DSP56K_MAJOR, "dsp56k");
-	devfs_unregister (devfs_handle);
+	devfs_unregister(devfs_handle);
 }
-#endif /* MODULE */
+module_exit(dsp56k_cleanup_driver);
diff -u --recursive --new-file v2.4.2/linux/drivers/char/dz.c linux/drivers/char/dz.c
--- v2.4.2/linux/drivers/char/dz.c	Wed Feb 21 18:20:19 2001
+++ linux/drivers/char/dz.c	Fri Mar  2 18:38:37 2001
@@ -847,10 +847,12 @@
   if (!new_info)
     return -EFAULT;
 
-  copy_from_user (&new_serial, new_info, sizeof(new_serial));
+  if(copy_from_user (&new_serial, new_info, sizeof(new_serial)))
+    return -EFAULT;
+    
   old_info = *info;
 
-  if (!suser())
+  if (!capable(CAP_SYS_ADMIN))
     return -EPERM;
 
   if (info->count > 1)
diff -u --recursive --new-file v2.4.2/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c
--- v2.4.2/linux/drivers/char/i810_rng.c	Wed Feb 21 18:20:19 2001
+++ linux/drivers/char/i810_rng.c	Sat Mar  3 10:53:47 2001
@@ -1,8 +1,8 @@
 /*
 
 	Hardware driver for Intel i810 Random Number Generator (RNG)
-	Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2000 Philipp Rumpf <prumpf@tux.org>
+	Copyright 2000,2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
 
 	Driver Web site:  http://sourceforge.net/projects/gkernel/
 
@@ -114,15 +114,13 @@
 	Minimum interval is 1 jiffy, maximum interval is 24 hours.
 
 	* In order to unload the i810_rng module, you must first
-	disable the hardware via sysctl i810_hw_enabled, as shown above,
+	disable the hardware via sysctl i810_rng_timer, as shown above,
 	and make sure all users of the character device have closed
 
 	* The timer and the character device may be used simultaneously,
 	if desired.
 
-	* FIXME: support poll()
-
-	* FIXME: should we be crazy and support mmap()?
+	* FIXME: support poll(2)
 
 	* FIXME: It is possible for the timer function to read,
 	and shove into the kernel entropy pool, 2499 bytes of data
@@ -135,11 +133,24 @@
 	* FIXME: module unload is racy.  To fix this, struct ctl_table
 	needs an owner member a la struct file_operations.
 
+	* FIXME: Timer interval should not be in jiffies, but in a more
+	user-understandable value like milliseconds.
+
 	* Since the RNG is accessed from a timer as well as normal
 	kernel code, but not from interrupts, we use spin_lock_bh
 	in regular code, and spin_lock in the timer function, to
 	serialize access to the RNG hardware area.
 
+	NOTE: request_mem_region was removed, for two reasons:
+	1) Only one RNG is supported by this driver, 2) The location
+	used by the RNG is a fixed location in MMIO-addressable memory,
+	3) users with properly working BIOS e820 handling will always
+	have the region in which the RNG is located reserved, so
+	request_mem_region calls always fail for proper setups.
+	However, for people who use mem=XX, BIOS e820 information is
+	-not- in /proc/iomem, and request_mem_region(RNG_ADDR) can
+	succeed.
+
 	----------------------------------------------------------
 
 	Change history:
@@ -179,6 +190,19 @@
 	Version 0.9.2:
 	* Simplify open blocking logic
 
+	Version 0.9.3:
+	* Clean up rng_read a bit.
+	* Update i810_rng driver Web site URL.
+	* Increase default timer interval to 4 samples per second.
+	* Abort if mem region is not available.
+	* BSS zero-initialization cleanup.
+	* Call misc_register() from rng_init_one.
+	* Fix O_NONBLOCK to occur before we schedule.
+
+	Version 0.9.4:
+	* Fix: Remove request_mem_region
+	* Fix: Horrible bugs in FIPS calculation and test execution
+
  */
 
 
@@ -202,7 +226,7 @@
 /*
  * core module and version information
  */
-#define RNG_VERSION "0.9.2"
+#define RNG_VERSION "0.9.4"
 #define RNG_MODULE_NAME "i810_rng"
 #define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
 #define PFX RNG_MODULE_NAME ": "
@@ -211,7 +235,7 @@
 /*
  * debugging macros
  */
-#undef RNG_DEBUG /* define to 1 to enable copious debugging info */
+#undef RNG_DEBUG /* define to enable copious debugging info */
 
 #ifdef RNG_DEBUG
 /* note: prints function name for you */
@@ -220,8 +244,8 @@
 #define DPRINTK(fmt, args...)
 #endif
 
-#define RNG_NDEBUG 0        /* define to 1 to disable lightweight runtime checks */
-#if RNG_NDEBUG
+#undef RNG_NDEBUG        /* define to disable lightweight runtime checks */
+#ifdef RNG_NDEBUG
 #define assert(expr)
 #else
 #define assert(expr) \
@@ -249,6 +273,9 @@
 #define		RNG_DATA_PRESENT	0x01
 #define RNG_DATA			2
 
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
 #define RNG_ADDR			0xFFBC015F
 #define RNG_ADDR_LEN			3
 
@@ -259,9 +286,9 @@
 
 /*
  * Frequency that data is added to kernel entropy pool
- * HZ>>1 == every half-second
+ * HZ>>1 == every quarter-second
  */
-#define RNG_DEF_TIMER_LEN		(HZ >> 1)
+#define RNG_DEF_TIMER_LEN		(HZ >> 2)
 
 
 /*
@@ -283,7 +310,6 @@
 static unsigned int rng_entropy = 8;	/* number of entropy bits we submit to /dev/random */
 static unsigned int rng_entropy_sysctl;	/* sysctl for changing entropy bits */
 static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */
-static int rng_have_mem_region;		/* did we grab RNG region via request_mem_region? */
 static unsigned int rng_fips_counter;	/* size of internal FIPS test data pool */
 static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */
 static void *rng_mem;			/* token to our ioremap'd RNG register area */
@@ -356,8 +382,11 @@
 
 		/* fitness testing via FIPS, if we have enough data */
 		rng_fips_test_store (rng_data);
-		if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD)
+		rng_fips_counter++;
+		if (rng_fips_counter == RNG_FIPS_TEST_THRESHOLD) {
 			rng_run_fips_test ();
+			rng_fips_counter = 0;
+		}
 	} else {
 		spin_unlock (&rng_lock);
 	}
@@ -622,12 +651,10 @@
 
 static int rng_dev_open (struct inode *inode, struct file *filp)
 {
-	int rc = -EINVAL;
-
 	if ((filp->f_mode & FMODE_READ) == 0)
-		return rc;
+		return -EINVAL;
 	if (filp->f_mode & FMODE_WRITE)
-		return rc;
+		return -EINVAL;
 
 	/* wait for device to become free */
 	if (filp->f_flags & O_NONBLOCK) {
@@ -639,15 +666,11 @@
 	}
 
 	if (rng_enable (1)) {
-		rc = -EIO;
-		goto err_out;
+		up (&rng_open_sem);
+		return -EIO;
 	}
 
 	return 0;
-
-err_out:
-	up (&rng_open_sem);
-	return rc;
 }
 
 
@@ -686,20 +709,35 @@
 			ret++;
 		}
 
+		if (filp->f_flags & O_NONBLOCK)
+			return ret ? : -EAGAIN;
+
 		if (current->need_resched)
 			schedule ();
 
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
-
-		if (filp->f_flags & O_NONBLOCK)
-			return ret ? : -EAGAIN;
 	}
 
 	return ret;
 }
 
 
+static struct file_operations rng_chrdev_ops = {
+	owner:		THIS_MODULE,
+	open:		rng_dev_open,
+	release:	rng_dev_release,
+	read:		rng_dev_read,
+};
+
+
+static struct miscdevice rng_miscdev = {
+	RNG_MISCDEV_MINOR,
+	RNG_MODULE_NAME,
+	&rng_chrdev_ops,
+};
+
+
 /*
  * rng_init_one - look for and attempt to init a single RNG
  */
@@ -713,16 +751,19 @@
 	if (pci_enable_device (dev))
 		return -EIO;
 
-	/* XXX currently fails, investigate who has our mem region */
-	if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME))
-		rng_have_mem_region = 1;
+	rc = misc_register (&rng_miscdev);
+	if (rc) {
+		printk (KERN_ERR PFX "cannot register misc device\n");
+		DPRINTK ("EXIT, returning %d\n", rc);
+		goto err_out;
+	}
 
 	rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
 	if (rng_mem == NULL) {
 		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
 		DPRINTK ("EXIT, returning -EBUSY\n");
 		rc = -EBUSY;
-		goto err_out_free_res;
+		goto err_out_free_miscdev;
 	}
 
 	/* Check for Intel 82802 */
@@ -756,9 +797,9 @@
 
 err_out_free_map:
 	iounmap (rng_mem);
-err_out_free_res:
-	if (rng_have_mem_region)
-		release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+err_out_free_miscdev:
+	misc_deregister (&rng_miscdev);
+err_out:
 	return rc;
 }
 
@@ -786,21 +827,6 @@
 MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)");
 
 
-static struct file_operations rng_chrdev_ops = {
-	owner:		THIS_MODULE,
-	open:		rng_dev_open,
-	release:	rng_dev_release,
-	read:		rng_dev_read,
-};
-
-
-static struct miscdevice rng_miscdev = {
-	RNG_MISCDEV_MINOR,
-	RNG_MODULE_NAME,
-	&rng_chrdev_ops,
-};
-
-
 /*
  * rng_init - initialize RNG module
  */
@@ -826,15 +852,6 @@
 	if (rc)
 		return rc;
 
-	rc = misc_register (&rng_miscdev);
-	if (rc) {
-		iounmap (rng_mem);
-		if (rng_have_mem_region)
-			release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
-		DPRINTK ("EXIT, returning %d\n", rc);
-		return rc;
-	}
-
 	printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
 
 	rng_pdev = pdev;
@@ -859,8 +876,8 @@
 	rng_sysctl (0);
 
 	iounmap (rng_mem);
-	if (rng_have_mem_region)
-		release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+
+	rng_pdev = NULL;
 
 	DPRINTK ("EXIT\n");
 }
@@ -892,8 +909,8 @@
 *  random as random :)
 */
 
-static int poker[16] = { 0, }, runs[12] = { 0, };
-static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0;
+static int poker[16], runs[12];
+static int ones, rlength = -1, current_bit, rng_test;
 
 
 /*
@@ -927,7 +944,7 @@
 
 			/* Check if we just failed longrun test */
 			if (rlength >= 33)
-				rng_test &= 8;
+				rng_test |= 8;
 			rlength = 0;
 			/* flip the current run type */
 			last_bit = current_bit;
@@ -955,16 +972,16 @@
 	else {
 		runs[5 + (6 * current_bit)]++;
 		if (rlength >= 33)
-			rng_test &= 8;
+			rng_test |= 8;
 	}
 	/* Ones test */
 	if ((ones >= 10346) || (ones <= 9654))
-		rng_test &= 1;
+		rng_test |= 1;
 	/* Poker calcs */
 	for (i = 0, j = 0; i < 16; i++)
 		j += poker[i] * poker[i];
 	if ((j >= 1580457) || (j <= 1562821))
-		rng_test &= 2;
+		rng_test |= 2;
 	if ((runs[0] < 2267) || (runs[0] > 2733) ||
 	    (runs[1] < 1079) || (runs[1] > 1421) ||
 	    (runs[2] < 502) || (runs[2] > 748) ||
@@ -977,7 +994,7 @@
 	    (runs[9] < 223) || (runs[9] > 402) ||
 	    (runs[10] < 90) || (runs[10] > 223) ||
 	    (runs[11] < 90) || (runs[11] > 223)) {
-		rng_test &= 4;
+		rng_test |= 4;
 	}
 
 	rng_test = !rng_test;
diff -u --recursive --new-file v2.4.2/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.4.2/linux/drivers/char/istallion.c	Wed Feb 21 18:20:19 2001
+++ linux/drivers/char/istallion.c	Fri Mar  2 11:12:07 2001
@@ -213,12 +213,8 @@
  *	at 9600 baud, 8 data bits, no parity, 1 stop bit.
  */
 static struct termios		stli_deftermios = {
-	0,
-	0,
-	(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
-	0,
-	0,
-	INIT_C_CC
+	c_cflag:	(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+	c_cc:		INIT_C_CC,
 };
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.4.2/linux/drivers/char/lp.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/lp.c	Fri Mar  2 18:43:11 2001
@@ -500,7 +500,7 @@
 			if (copy_to_user((int *) arg, &LP_STAT(minor),
 					sizeof(struct lp_stats)))
 				return -EFAULT;
-			if (suser())
+			if (capable(CAP_SYS_ADMIN))
 				memset(&LP_STAT(minor), 0,
 						sizeof(struct lp_stats));
 			break;
diff -u --recursive --new-file v2.4.2/linux/drivers/char/machzwd.c linux/drivers/char/machzwd.c
--- v2.4.2/linux/drivers/char/machzwd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/machzwd.c	Tue Mar  6 19:44:34 2001
@@ -0,0 +1,545 @@
+/*
+ *  MachZ ZF-Logic Watchdog Timer driver for Linux
+ *  
+ * 
+ *  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 does NOT admit liability nor provide warranty for
+ *  any of this software. This material is provided "AS-IS" in
+ *  the hope that it may be useful for others.
+ *
+ *  Author: Fernando Fuganti <fuganti@conectiva.com.br>
+ *
+ *  Based on sbc60xxwdt.c by Jakob Oestergaard
+ * 
+ *
+ *  We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the 
+ *  following periods:
+ *      wd#1 - 2 seconds;
+ *      wd#2 - 7.2 ms;
+ *  After the expiration of wd#1, it can generate a NMI, SCI, SMI, or 
+ *  a system RESET and it starts wd#2 that unconditionaly will RESET 
+ *  the system when the counter reaches zero.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+
+/* ports */
+#define ZF_IOBASE	0x218
+#define INDEX		0x218
+#define DATA_B		0x219
+#define DATA_W		0x21A
+#define DATA_D		0x21A
+
+/* indexes */			/* size */
+#define ZFL_VERSION	0x02	/* 16   */
+#define CONTROL 	0x10	/* 16   */	
+#define STATUS		0x12	/* 8    */
+#define COUNTER_1	0x0C	/* 16   */
+#define COUNTER_2	0x0E	/* 8    */
+#define PULSE_LEN	0x0F	/* 8    */
+
+/* controls */
+#define ENABLE_WD1	0x0001
+#define ENABLE_WD2	0x0002
+#define RESET_WD1	0x0010
+#define RESET_WD2	0x0020
+#define GEN_SCI		0x0100
+#define GEN_NMI		0x0200
+#define GEN_SMI		0x0400
+#define GEN_RESET	0x0800
+
+
+/* utilities */
+
+#define WD1	0
+#define WD2	1
+
+#define zf_writew(port, data)  { outb(port, INDEX); outw(data, DATA_W); }
+#define zf_writeb(port, data)  { outb(port, INDEX); outb(data, DATA_B); }
+#define zf_get_ZFL_version()   zf_readw(ZFL_VERSION)
+
+
+static unsigned short zf_readw(unsigned char port)
+{
+	outb(port, INDEX);
+	return inw(DATA_W);
+}
+
+static unsigned short zf_readb(unsigned char port)
+{
+	outb(port, INDEX);
+	return inb(DATA_B);
+}
+
+
+MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
+MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
+MODULE_PARM(action, "i");
+MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
+
+#define PFX "machzwd"
+
+static struct watchdog_info zf_info = {
+	options:		WDIOF_KEEPALIVEPING, 
+	firmware_version:	1, 
+	identity:		"ZF-Logic watchdog"
+};
+
+
+/*
+ * action refers to action taken when watchdog resets
+ * 0 = GEN_RESET
+ * 1 = GEN_SMI
+ * 2 = GEN_NMI
+ * 3 = GEN_SCI
+ * defaults to GEN_RESET (0)
+ */
+static int action = 0;
+static int zf_action = GEN_RESET;
+static int zf_is_open = 0;
+static int zf_expect_close = 0;
+static spinlock_t zf_lock;
+static struct timer_list zf_timer;
+static unsigned long next_heartbeat = 0;
+
+
+/* timeout for user land heart beat (10 seconds) */
+#define ZF_USER_TIMEO (HZ*10)
+
+/* timeout for hardware watchdog (~500ms) */
+#define ZF_HW_TIMEO (HZ/2)
+
+/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */
+#define ZF_CTIMEOUT 0xffff
+
+#ifndef ZF_DEBUG
+#	define dprintk(format, args...)
+#else
+#	define dprintk(format, args...) printk(KERN_DEBUG PFX ":" __FUNCTION__ ":%d: " format, __LINE__ , ## args)
+#endif
+
+
+/* STATUS register functions */
+
+static inline unsigned char zf_get_status(void)
+{
+	return zf_readb(STATUS);
+}
+
+static inline void zf_set_status(unsigned char new)
+{
+	zf_writeb(STATUS, new);
+}
+
+
+/* CONTROL register functions */
+
+static inline unsigned short zf_get_control(void)
+{
+	return zf_readw(CONTROL);
+}
+
+static inline void zf_set_control(unsigned short new)
+{
+	zf_writew(CONTROL, new);
+}
+
+
+/* WD#? counter functions */
+/*
+ *	Just get current counter value
+ */
+
+inline unsigned short zf_get_timer(unsigned char n)
+{
+	switch(n){
+		case WD1:
+			return zf_readw(COUNTER_1);
+		case WD2:
+			return zf_readb(COUNTER_2);
+		default:
+			return 0;
+	}
+}
+
+/*
+ *	Just set counter value
+ */
+
+static inline void zf_set_timer(unsigned short new, unsigned char n)
+{
+	switch(n){
+		case WD1:
+			zf_writew(COUNTER_1, new);
+		case WD2:
+			zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
+		default:
+			return;
+	}
+}
+
+/*
+ * stop hardware timer
+ */
+static void zf_timer_off(void)
+{
+	unsigned int ctrl_reg = 0;
+
+	/* stop internal ping */
+	del_timer(&zf_timer);
+
+	/* stop watchdog timer */	
+	ctrl_reg = zf_get_control();
+	ctrl_reg |= (ENABLE_WD1|ENABLE_WD2);	/* disable wd1 and wd2 */
+	ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2);
+	zf_set_control(ctrl_reg);
+
+	printk(PFX ": Watchdog timer is now disabled\n");
+}
+
+
+/*
+ * start hardware timer 
+ */
+static void zf_timer_on(void)
+{
+	unsigned int ctrl_reg = 0;
+
+	zf_writeb(PULSE_LEN, 0xff);
+
+	zf_set_timer(ZF_CTIMEOUT, WD1);
+
+	/* user land ping */
+	next_heartbeat = jiffies + ZF_USER_TIMEO;
+
+	/* start the timer for internal ping */
+	zf_timer.expires = jiffies + ZF_HW_TIMEO;
+
+	add_timer(&zf_timer);
+
+	/* start watchdog timer */
+	ctrl_reg = zf_get_control();
+	ctrl_reg |= (ENABLE_WD1|zf_action);
+	zf_set_control(ctrl_reg);
+
+	printk(PFX ": Watchdog timer is now enabled\n");
+}
+
+
+static void zf_ping(unsigned long data)
+{
+	unsigned int ctrl_reg = 0;
+
+	zf_writeb(COUNTER_2, 0xff);
+
+	if(time_before(jiffies, next_heartbeat)){
+
+		dprintk("time_before: %ld\n", next_heartbeat - jiffies);
+		
+		/* 
+		 * reset event is activated by transition from 0 to 1 on
+		 * RESET_WD1 bit and we assume that it is already zero...
+		 */
+		ctrl_reg = zf_get_control();    
+		ctrl_reg |= RESET_WD1;		
+		zf_set_control(ctrl_reg);	
+		
+		/* ...and nothing changes until here */
+		ctrl_reg &= ~(RESET_WD1);
+		zf_set_control(ctrl_reg);		
+
+		zf_timer.expires = jiffies + ZF_HW_TIMEO;
+		add_timer(&zf_timer);
+	}else{
+		printk(PFX ": I will reset your machine\n");
+	}
+}
+
+static ssize_t zf_write(struct file *file, const char *buf, size_t count, 
+								loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* See if we got the magic character */
+	if(count){
+
+/*
+ * no need to check for close confirmation
+ * no way to disable watchdog ;)
+ */
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+		size_t ofs;
+
+		/* 
+		 * note: just in case someone wrote the magic character
+		 * five months ago...
+		 */
+		zf_expect_close = 0;
+
+		/* now scan */
+		for(ofs = 0; ofs != count; ofs++){
+			if(buf[ofs] == 'V'){
+				zf_expect_close = 1;
+				dprintk("zf_expect_close 1\n");
+			}
+		}
+#endif
+		/*
+		 * Well, anyhow someone wrote to us,
+		 * we should return that favour
+		 */
+		next_heartbeat = jiffies + ZF_USER_TIMEO;
+		dprintk("user ping at %ld\n", jiffies);
+		
+		return 1;
+	}
+
+	return 0;
+}
+
+static ssize_t zf_read(struct file *file, char *buf, size_t count, 
+							loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+
+
+static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	int ret;
+		
+	switch(cmd){
+		case WDIOC_GETSUPPORT:
+			ret = copy_to_user((struct watchdog_info *)arg, 
+						&zf_info, sizeof(zf_info));
+			if(ret)
+				return -EFAULT;
+			break;
+	  
+		case WDIOC_GETSTATUS:
+			ret = copy_to_user((int *)arg, &zf_is_open,
+								sizeof(int));
+			if(ret)
+				return -EFAULT;
+			break;
+
+		case WDIOC_KEEPALIVE:
+			zf_ping(0);
+			break;
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+
+	return 0;
+}
+
+static int zf_open(struct inode *inode, struct file *file)
+{
+	switch(MINOR(inode->i_rdev)){
+		case WATCHDOG_MINOR:
+			spin_lock(&zf_lock);
+			if(zf_is_open){
+				spin_unlock(&zf_lock);
+				return -EBUSY;
+			}
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+			MOD_INC_USE_COUNT;
+#endif
+			zf_is_open = 1;
+
+			spin_unlock(&zf_lock);
+
+			zf_timer_on();
+
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+static int zf_close(struct inode *inode, struct file *file)
+{
+	if(MINOR(inode->i_rdev) == WATCHDOG_MINOR){
+
+		if(zf_expect_close){
+			zf_timer_off();
+		} else {
+			del_timer(&zf_timer);
+			printk(PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
+		}
+		
+		spin_lock(&zf_lock);
+		zf_is_open = 0;
+		spin_unlock(&zf_lock);
+
+		zf_expect_close = 0;
+	}
+	
+	return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int zf_notify_sys(struct notifier_block *this, unsigned long code,
+								void *unused)
+{
+	if(code == SYS_DOWN || code == SYS_HALT){
+		zf_timer_off();		
+	}
+	
+	return NOTIFY_DONE;
+}
+
+
+
+
+static struct file_operations zf_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,34)
+	owner:          THIS_MODULE,
+#endif
+	read:           zf_read,
+	write:          zf_write,
+	ioctl:          zf_ioctl,
+	open:           zf_open,
+	release:        zf_close,
+};
+
+static struct miscdevice zf_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&zf_fops
+};
+                                                                        
+
+/*
+ * The device needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+static struct notifier_block zf_notifier = {
+	zf_notify_sys,
+	NULL,
+	0
+};
+
+static void __init zf_show_action(int act)
+{
+	char *str[] = { "RESET", "SMI", "NMI", "SCI" };
+	
+	printk(PFX ": Watchdog using action = %s\n", str[act]);
+}
+
+int __init zf_init(void)
+{
+	int ret;
+	
+	printk(PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
+
+	ret = zf_get_ZFL_version();
+	printk("%#x\n", ret);
+	if((!ret) || (ret != 0xffff)){
+		printk(PFX ": no ZF-Logic found\n");
+		return -ENODEV;
+	}
+
+	if((action <= 3) && (action >= 0)){
+		zf_action = zf_action>>action;
+	} else
+		action = 0;
+	
+	zf_show_action(action);
+
+	spin_lock_init(&zf_lock);
+	
+	ret = misc_register(&zf_miscdev);
+	if (ret){
+		printk(KERN_ERR "can't misc_register on minor=%d\n",
+							WATCHDOG_MINOR);
+		goto out;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3)
+	if(check_region(ZF_IOBASE, 3)){
+#else
+	if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
+#endif
+
+		printk(KERN_ERR "cannot reserve I/O ports at %d\n",
+							ZF_IOBASE);
+		ret = -EBUSY;
+		goto no_region;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,3)
+	request_region(ZF_IOBASE, 3, "MachZ ZFL WDT");
+#define __exit
+#endif
+
+	ret = register_reboot_notifier(&zf_notifier);
+	if(ret){
+		printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
+									ret);
+		goto no_reboot;
+	}
+	
+	zf_set_status(0);
+	zf_set_control(0);
+
+	/* this is the timer that will do the hard work */
+	init_timer(&zf_timer);
+	zf_timer.function = zf_ping;
+	zf_timer.data = 0;
+	
+	return 0;
+
+no_reboot:
+	release_region(ZF_IOBASE, 3);
+no_region:
+	misc_deregister(&zf_miscdev);
+out:
+	return ret;
+}
+
+	
+void __exit zf_exit(void)
+{
+	zf_timer_off();
+	
+	misc_deregister(&zf_miscdev);
+	unregister_reboot_notifier(&zf_notifier);
+	release_region(ZF_IOBASE, 3);
+}
+
+module_init(zf_init);
+module_exit(zf_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.4.2/linux/drivers/char/mem.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/mem.c	Mon Mar 19 12:35:08 2001
@@ -353,7 +353,7 @@
 
 	mm = current->mm;
 	/* Oops, this was forgotten before. -ben */
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 
 	/* For private mappings, just map in zero pages. */
 	for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
@@ -367,10 +367,8 @@
 		if (count > size)
 			count = size;
 
-		flush_cache_range(mm, addr, addr + count);
 		zap_page_range(mm, addr, count);
         	zeromap_page_range(addr, count, PAGE_COPY);
-        	flush_tlb_range(mm, addr, addr + count);
 
 		size -= count;
 		buf += count;
@@ -379,7 +377,7 @@
 			goto out_up;
 	}
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	
 	/* The shared case is hard. Let's do the conventional zeroing. */ 
 	do {
@@ -394,7 +392,7 @@
 
 	return size;
 out_up:
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return size;
 }
 
@@ -641,6 +639,9 @@
 #endif
 #ifdef CONFIG_FTAPE
 	ftape_init();
+#endif
+#if defined(CONFIG_S390_TAPE) && defined(CONFIG_S390_TAPE_CHAR)
+	tapechar_init();
 #endif
 #if defined(CONFIG_ADB)
 	adbdev_init();
diff -u --recursive --new-file v2.4.2/linux/drivers/char/mxser.c linux/drivers/char/mxser.c
--- v2.4.2/linux/drivers/char/mxser.c	Wed Dec  6 12:06:18 2000
+++ linux/drivers/char/mxser.c	Fri Mar  2 11:12:07 2001
@@ -120,7 +120,7 @@
 #define CI104J_ASIC_ID  5
 
 enum {
-	MXSER_BOARD_C168_ISA = 0,
+	MXSER_BOARD_C168_ISA = 1,
 	MXSER_BOARD_C104_ISA,
 	MXSER_BOARD_CI104J,
 	MXSER_BOARD_C168_PCI,
@@ -617,16 +617,18 @@
 			pdev = pci_find_device(mxser_pcibrds[b].vendor_id,
 					       mxser_pcibrds[b].device_id, pdev);
 			if (!pdev)
-				break;
+			{
+				b++;
+				continue;
+			}
 			if (pci_enable_device(pdev))
 				continue;
-			b++;
 			hwconf.pdev = pdev;
 			printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
 				mxser_brdname[mxser_pcibrds[b].board_type - 1],
 				pdev->bus->number, PCI_SLOT(pdev->devfn >> 3));
 			if (m >= MXSER_BOARDS) {
-				printk("Too many Smartio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
+				printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
 			} else {
 				retval = mxser_get_PCI_conf(pdev,
 				   mxser_pcibrds[b].board_type, &hwconf);
@@ -1457,7 +1459,9 @@
 
 	if (info->xmit_cnt < WAKEUP_CHARS) {
 		set_bit(MXSER_EVENT_TXLOW, &info->event);
-		schedule_task(&info->tqueue);
+		MOD_INC_USE_COUNT;
+		if (schedule_task(&info->tqueue) == 0)
+		    MOD_DEC_USE_COUNT;
 	}
 	if (info->xmit_cnt <= 0) {
 		info->IER &= ~UART_IER_THRI;
@@ -1486,8 +1490,9 @@
 		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
 			   (info->flags & ASYNC_CALLOUT_NOHUP)))
 			set_bit(MXSER_EVENT_HANGUP, &info->event);
-		schedule_task(&info->tqueue);
-
+		MOD_INC_USE_COUNT;
+		if (schedule_task(&info->tqueue) == 0)
+		    MOD_DEC_USE_COUNT;
 	}
 	if (info->flags & ASYNC_CTS_FLOW) {
 		if (info->tty->hw_stopped) {
@@ -1671,7 +1676,7 @@
 	 */
 	if (inb(info->base + UART_LSR) == 0xff) {
 		restore_flags(flags);
-		if (suser()) {
+		if (capable(CAP_SYS_ADMIN)) {
 			if (info->tty)
 				set_bit(TTY_IO_ERROR, &info->tty->flags);
 			return (0);
@@ -2188,8 +2193,7 @@
 	status = inb(info->base + UART_LSR);
 	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	put_user(result, value);
-	return (0);
+	return put_user(result, value);
 }
 
 /*
@@ -2229,8 +2233,7 @@
 	    ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
 	    ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
 	    ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	put_user(result, value);
-	return (0);
+	return put_user(result, value);
 }
 
 static int mxser_set_modem_info(struct mxser_struct *info, unsigned int cmd,
diff -u --recursive --new-file v2.4.2/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.4.2/linux/drivers/char/pc_keyb.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/pc_keyb.c	Fri Mar  2 18:38:37 2001
@@ -908,6 +908,8 @@
 							   controller. */
 	aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
 	kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
+	
+	mdelay(2);			/* Ensure we follow the kbc access delay rules.. */
 
 	send_data(KBD_CMD_ENABLE);	/* try to workaround toshiba4030cdt problem */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/char/pcmcia/Config.in linux/drivers/char/pcmcia/Config.in
--- v2.4.2/linux/drivers/char/pcmcia/Config.in	Tue Jul 11 19:02:37 2000
+++ linux/drivers/char/pcmcia/Config.in	Tue Mar  6 19:28:35 2001
@@ -2,29 +2,13 @@
 # PCMCIA character device configuration
 #
 
-if [ "$CONFIG_SERIAL" = "n" ]; then
-   define_tristate CONFIG_PCMCIA_SERIAL n
-else
-   if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then
-      define_tristate CONFIG_PCMCIA_SERIAL m
-   else
-      define_tristate CONFIG_PCMCIA_SERIAL y
-   fi
-fi
-
-if [ "$CONFIG_PCMCIA_SERIAL" != "n" ]; then
-   mainmenu_option next_comment
-   comment 'PCMCIA character device support'
+mainmenu_option next_comment
+comment 'PCMCIA character devices'
 
-   dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL
-   if [ "$CONFIG_CARDBUS" = "y" ]; then
-      dep_tristate 'CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL
-   fi
+dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_SERIAL
+if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" ]; then
+   define_bool CONFIG_PCMCIA_CHRDEV y
+fi
 
-   if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \
-        "$CONFIG_PCMCIA_SERIAL_CB" = "y" ]; then
-      define_bool CONFIG_PCMCIA_CHRDEV y
-   fi
+endmenu
 
-   endmenu
-fi
diff -u --recursive --new-file v2.4.2/linux/drivers/char/pcmcia/Makefile linux/drivers/char/pcmcia/Makefile
--- v2.4.2/linux/drivers/char/pcmcia/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/drivers/char/pcmcia/Makefile	Tue Mar  6 19:28:35 2001
@@ -16,6 +16,5 @@
 obj-		:=
 
 obj-$(CONFIG_PCMCIA_SERIAL_CS)	+= serial_cs.o
-obj-$(CONFIG_PCMCIA_SERIAL_CB)	+= serial_cb.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.2/linux/drivers/char/pcmcia/serial_cb.c linux/drivers/char/pcmcia/serial_cb.c
--- v2.4.2/linux/drivers/char/pcmcia/serial_cb.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/pcmcia/serial_cb.c	Wed Dec 31 16:00:00 1969
@@ -1,163 +0,0 @@
-/*======================================================================
-
-    A driver for CardBus serial devices
-
-    serial_cb.c 1.20 2000/08/07 19:02:03
-
-    Copyright 1998, 1999 by Donald Becker and David Hinds
-    
-    This software may be used and distributed according to the terms
-    of the GNU General Public License, incorporated herein by reference.
-    All other rights reserved.
-    
-    This driver is an activator for CardBus serial cards, as
-    found on multifunction (e.g. Ethernet and Modem) CardBus cards.
-    
-    Donald Becker may be reached as becker@CESDIS.edu, or C/O
-    USRA Center of Excellence in Space Data and Information Sciences
-    Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
-    David Hinds may be reached at dahinds@users.sourceforge.net
-    
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/tty.h>
-#include <linux/serial.h>
-#include <linux/major.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include <pcmcia/driver_ops.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 =
-"serial_cb.c 1.20 2000/08/07 19:02:03 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*======================================================================
-
-    Card-specific configuration hacks
-
-======================================================================*/
-
-static void device_setup(struct pci_dev *pdev, u_int ioaddr)
-{
-    u_short a, b;
-
-    a = pdev->subsystem_vendor;
-    b = pdev->subsystem_device;
-    if (((a == 0x13a2) && (b == 0x8007)) ||
-	((a == 0x1420) && (b == 0x8003))) {
-	/* Ositech, Psion 83c175-based cards */
-	DEBUG(0, "  83c175 NVCTL_m = 0x%4.4x.\n", inl(ioaddr+0x80));
-	outl(0x4C00, ioaddr + 0x80);
-	outl(0x4C80, ioaddr + 0x80);
-    }
-    DEBUG(0, "  modem registers are %2.2x %2.2x %2.2x "
-	  "%2.2x %2.2x %2.2x %2.2x %2.2x  %2.2x.\n",
-	  inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
-	  inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
-	  inb(ioaddr + 6), inb(ioaddr + 7), inb(ioaddr + 8));
-}
-
-/*======================================================================
-
-    serial_attach() creates a serial device "instance" and registers
-    it with the kernel serial driver, and serial_detach() unregisters
-    an instance.
-
-======================================================================*/
-
-static dev_node_t *serial_attach(dev_locator_t *loc)
-{
-    u_int io;
-    u_char irq;
-    int line;
-    struct serial_struct serial;
-    struct pci_dev *pdev;
-    dev_node_t *node;
-    
-    MOD_INC_USE_COUNT;
-
-    if (loc->bus != LOC_PCI) goto err_out;
-    pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
-    if (!pdev) goto err_out;
-    if (pci_enable_device(pdev)) goto err_out;
-
-    printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn);
-    io = pci_resource_start (pdev, 0);
-    irq = pdev->irq;
-    if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
-	printk(KERN_NOTICE "serial_cb: PCI base address 0 is not IO\n");
-	goto err_out;
-    }
-    device_setup(pdev, io);
-    memset(&serial, 0, sizeof(serial));
-    serial.port = io; serial.irq = irq;
-    serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
-
-    /* Some devices seem to need extra time */
-    __set_current_state(TASK_UNINTERRUPTIBLE);
-    schedule_timeout(HZ/50);
-
-    line = register_serial(&serial);
-    if (line < 0) {
-	printk(KERN_NOTICE "serial_cb: register_serial() at 0x%04x, "
-	       "irq %d failed\n", serial.port, serial.irq);
-    	goto err_out;
-    }
-
-    node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-    if (!node)
-	    goto err_out_unregister;
-    sprintf(node->dev_name, "ttyS%d", line);
-    node->major = TTY_MAJOR; node->minor = 0x40 + line;
-    node->next = NULL;
-    return node;
-
-err_out_unregister:
-    unregister_serial(line);
-err_out:
-    MOD_DEC_USE_COUNT;
-    return NULL;
-}
-
-static void serial_detach(dev_node_t *node)
-{
-    DEBUG(0, "serial_detach(ttyS%02d)\n", node->minor - 0x40);
-    unregister_serial(node->minor - 0x40);
-    kfree(node);
-    MOD_DEC_USE_COUNT;
-}
-
-/*====================================================================*/
-
-struct driver_operations serial_ops = {
-    "serial_cb", serial_attach, NULL, NULL, serial_detach
-};
-
-static int __init init_serial_cb(void)
-{
-    DEBUG(0, "%s\n", version);
-    register_driver(&serial_ops);
-    return 0;
-}
-
-static void __exit exit_serial_cb(void)
-{
-    DEBUG(0, "serial_cb: unloading\n");
-    unregister_driver(&serial_ops);
-}
-
-module_init(init_serial_cb);
-module_exit(exit_serial_cb);
diff -u --recursive --new-file v2.4.2/linux/drivers/char/rocket.c linux/drivers/char/rocket.c
--- v2.4.2/linux/drivers/char/rocket.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/rocket.c	Tue Mar  6 19:44:34 2001
@@ -47,19 +47,6 @@
 #endif
 
 #define NEW_MODULES
-#ifdef LOCAL_ROCKET_H		/* We're building standalone */
-#define MODULE
-#endif
-
-#if defined(NEW_MODULES) && defined(LOCAL_ROCKET_H)
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#else /* !NEW_MODULES */
-#ifdef MODVERSIONS
-#define MODULE
-#endif
-#endif /* NEW_MODULES */
 
 #include <linux/module.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.4.2/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.4.2/linux/drivers/char/serial.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/serial.c	Tue Mar  6 20:13:51 2001
@@ -54,16 +54,13 @@
  *  7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
  *	  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  *
- * 10/00: add in optional hardware flow control for serial console.
- *	  Kanoj Sarcar <kanoj@sgi.com>
+ * 10/00: add in optional software flow control for serial console.
+ *	  Kanoj Sarcar <kanoj@sgi.com>  (Modified by Theodore Ts'o)
  *
- * This module exports the following rs232 io functions:
- *
- *	int rs_init(void);
  */
 
-static char *serial_version = "5.02";
-static char *serial_revdate = "2000-08-09";
+static char *serial_version = "5.05";
+static char *serial_revdate = "2000-12-13";
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -191,7 +188,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #if (LINUX_VERSION_CODE >= 131343)
 #include <linux/init.h>
 #endif
@@ -325,7 +322,6 @@
 #define NR_PCI_BOARDS	8
 
 static struct pci_board_inst	serial_pci_board[NR_PCI_BOARDS];
-static int serial_pci_board_idx;
 
 #ifndef IS_PCI_REGION_IOPORT
 #define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
@@ -564,8 +560,8 @@
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch;
-	int ignored = 0;
 	struct	async_icount *icount;
+	int	max_count = 256;
 
 	icount = &info->state->icount;
 	do {
@@ -612,15 +608,8 @@
 				icount->overrun++;
 
 			/*
-			 * Now check to see if character should be
-			 * ignored, and mask off conditions which
-			 * should be ignored.
+			 * Mask off conditions which should be ignored.
 			 */
-			if (*status & info->ignore_status_mask) {
-				if (++ignored > 100)
-					break;
-				goto ignore_char;
-			}
 			*status &= info->read_status_mask;
 
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -639,19 +628,6 @@
 				*tty->flip.flag_buf_ptr = TTY_PARITY;
 			else if (*status & UART_LSR_FE)
 				*tty->flip.flag_buf_ptr = TTY_FRAME;
-			if (*status & UART_LSR_OE) {
-				/*
-				 * Overrun is special, since it's
-				 * reported immediately, and doesn't
-				 * affect the current character
-				 */
-				tty->flip.count++;
-				tty->flip.flag_buf_ptr++;
-				tty->flip.char_buf_ptr++;
-				*tty->flip.flag_buf_ptr = TTY_OVERRUN;
-				if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-					goto ignore_char;
-			}
 		}
 #if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 		if (break_pressed && info->line == sercons.index) {
@@ -664,16 +640,30 @@
 			break_pressed = 0;
 		}
 #endif
-		tty->flip.flag_buf_ptr++;
-		tty->flip.char_buf_ptr++;
-		tty->flip.count++;
+		if ((*status & info->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((*status & UART_LSR_OE) &&
+		    (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+			tty->flip.count++;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+		}
 	ignore_char:
 		*status = serial_inp(info, UART_LSR);
-	} while (*status & UART_LSR_DR);
+	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
 #if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
 	tty_flip_buffer_push(tty);
 #else
-	queue_task(&tty->flip.tqueue, &tq_timer);
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
 #endif	
 }
 
@@ -827,6 +817,9 @@
 				end_mark = info;
 			goto next;
 		}
+#ifdef SERIAL_DEBUG_INTR
+		printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
 		end_mark = 0;
 
 		info->last_active = jiffies;
@@ -910,6 +903,9 @@
 #endif
 			break;
 		}
+#ifdef SERIAL_DEBUG_INTR
+		printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
 	} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
 	info->last_active = jiffies;
 #ifdef CONFIG_SERIAL_MULTIPORT	
@@ -1310,7 +1306,7 @@
 	 */
 	if (!(info->flags & ASYNC_BUGGY_UART) &&
 	    (serial_inp(info, UART_LSR) == 0xff)) {
-		printk("LSR safety check engaged!\n");
+		printk("ttyS%d: LSR safety check engaged!\n", state->line);
 		if (capable(CAP_SYS_ADMIN)) {
 			if (info->tty)
 				set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1554,7 +1550,10 @@
 		/* Arrange to enter sleep mode */
 		serial_outp(info, UART_LCR, 0xBF);
 		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_LCR, 0);
 		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, 0);
 		serial_outp(info, UART_LCR, 0);
 	}
 	if (info->state->type == PORT_16750) {
@@ -2906,7 +2905,6 @@
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
-	set_current_state(TASK_RUNNING);
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
 #endif
@@ -3254,6 +3252,10 @@
 		info->magic = SERIAL_MAGIC;
 		info->port = state->port;
 		info->flags = state->flags;
+		info->hub6 = state->hub6;
+		info->io_type = state->io_type;
+		info->iomem_base = state->iomem_base;
+		info->iomem_reg_shift = state->iomem_reg_shift;
 		info->quot = 0;
 		info->tty = 0;
 	}
@@ -3809,7 +3811,7 @@
 
 #if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) 
 
-static void __init printk_pnp_dev_id(unsigned short vendor,
+static void __devinit printk_pnp_dev_id(unsigned short vendor,
 				     unsigned short device)
 {
 	printk("%c%c%c%x%x%x%x",
@@ -3901,7 +3903,7 @@
 /*
  * Common enabler code shared by both PCI and ISAPNP probes
  */
-static void __init start_pci_pnp_board(struct pci_dev *dev,
+static void __devinit start_pci_pnp_board(struct pci_dev *dev,
 				       struct pci_board *board)
 {
 	int k, line;
@@ -3933,19 +3935,19 @@
 	if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
 		return;
 
-#ifdef MODULE
 	/*
 	 * Register the serial board in the array if we need to
-	 * shutdown the board on a module unload.
+	 * shutdown the board on a module unload or card removal
 	 */
 	if (DEACTIVATE_FUNC(dev) || board->init_fn) {
-		if (serial_pci_board_idx >= NR_PCI_BOARDS)
+		for (k=0; k < NR_PCI_BOARDS; k++)
+			if (serial_pci_board[k].dev == 0)
+				break;
+		if (k >= NR_PCI_BOARDS)
 			return;
-		serial_pci_board[serial_pci_board_idx].board = *board;
-		serial_pci_board[serial_pci_board_idx].dev = dev;
-		serial_pci_board_idx++;
+		serial_pci_board[k].board = *board;
+		serial_pci_board[k].dev = dev;
 	}
-#endif
 
 	base_baud = board->base_baud;
 	if (!base_baud)
@@ -3965,6 +3967,7 @@
 		if (line < 0)
 			break;
 		rs_table[line].baud_base = base_baud;
+		rs_table[line].dev = dev;
 	}
 }
 #endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
@@ -3978,7 +3981,7 @@
  */
 static int
 #ifndef MODULE
-__init
+__devinit
 #endif
 pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
@@ -4045,7 +4048,7 @@
 
 static int
 #ifndef MODULE
-__init
+__devinit
 #endif
 pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
@@ -4077,7 +4080,7 @@
 
 static int
 #ifndef MODULE
-__init
+__devinit
 #endif
 pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
@@ -4101,7 +4104,7 @@
 /* Added for EKF Intel i960 serial boards */
 static int
 #ifndef MODULE
-__init
+__devinit
 #endif
 pci_inteli960ni_fn(struct pci_dev *dev,
 		   struct pci_board *board,
@@ -4162,7 +4165,7 @@
 
 static int
 #ifndef MODULE
-__init
+__devinit
 #endif
 pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
 {
@@ -4577,6 +4580,12 @@
 		SPCI_FL_BASE0, 1, 520833,
 		64, 3, NULL, 0x300 },
 #endif
+#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */
+	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE3, 8, 115200,
+		8 },
+#endif
 	/* Generic serial board */
 	{	0, 0,
 		0, 0,
@@ -4626,6 +4635,90 @@
 	return 1;
 }
 
+static int __devinit serial_init_one(struct pci_dev *dev,
+				     const struct pci_device_id *ent)
+{
+	struct pci_board *board, tmp;
+
+	for (board = pci_boards; board->vendor; board++) {
+		if (board->vendor != (unsigned short) PCI_ANY_ID &&
+		    dev->vendor != board->vendor)
+			continue;
+		if (board->device != (unsigned short) PCI_ANY_ID &&
+		    dev->device != board->device)
+			continue;
+		if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+		    pci_get_subvendor(dev) != board->subvendor)
+			continue;
+		if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+		    pci_get_subdevice(dev) != board->subdevice)
+			continue;
+		break;
+	}
+
+	if (board->vendor == 0 && serial_pci_guess_board(dev, board))
+		return -ENODEV;
+	else if (serial_pci_guess_board(dev, &tmp) == 0) {
+		printk(KERN_INFO "Redundant entry in serial pci_table.  "
+		       "Please send the output of\n"
+		       "lspci -vv, this message (%d,%d,%d,%d)\n"
+		       "and the manufacturer and name of "
+		       "serial board or modem board\n"
+		       "to serial-pci-info@lists.sourceforge.net.\n",
+		       dev->vendor, dev->device,
+		       pci_get_subvendor(dev), pci_get_subdevice(dev));
+	}
+		       
+	start_pci_pnp_board(dev, board);
+
+	return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+	int	i;
+
+	/*
+	 * Iterate through all of the ports finding those that belong
+	 * to this PCI device.
+	 */
+	for(i = 0; i < NR_PORTS; i++) {
+		if (rs_table[i].dev != dev)
+			continue;
+		unregister_serial(i);
+		rs_table[i].dev = 0;
+	}
+	/*
+	 * Now execute any board-specific shutdown procedure
+	 */
+	for (i=0; i < NR_PCI_BOARDS; i++) {
+		struct pci_board_inst *brd = &serial_pci_board[i];
+
+		if (serial_pci_board[i].dev != dev)
+			continue;
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
+		serial_pci_board[i].dev = 0;
+	}
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+       name:           "serial",
+       probe:          serial_init_one,
+       remove:	       serial_remove_one,
+       id_table:       serial_pci_tbl,
+};
 
 
 /*
@@ -4635,38 +4728,19 @@
  * Accept a maximum of eight boards
  *
  */
-static void __init probe_serial_pci(void) 
+static void __devinit probe_serial_pci(void) 
 {
-	struct pci_dev *dev = NULL;
-	struct pci_board *board;
-
 #ifdef SERIAL_DEBUG_PCI
 	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
 #endif
-  
-	pci_for_each_dev(dev) {
-		for (board = pci_boards; board->vendor; board++) {
-			if (board->vendor != (unsigned short) PCI_ANY_ID &&
-			    dev->vendor != board->vendor)
-				continue;
-			if (board->device != (unsigned short) PCI_ANY_ID &&
-			    dev->device != board->device)
-				continue;
-			if (board->subvendor != (unsigned short) PCI_ANY_ID &&
-			    pci_get_subvendor(dev) != board->subvendor)
-				continue;
-			if (board->subdevice != (unsigned short) PCI_ANY_ID &&
-			    pci_get_subdevice(dev) != board->subdevice)
-				continue;
-			break;
-		}
-	
-		if (board->vendor == 0 && serial_pci_guess_board(dev, board))
-			continue;
-		
-		start_pci_pnp_board(dev, board);
-	}
-	
+
+	/* Register call PCI serial devices.  Null out
+	 * the driver name upon failure, as a signal
+	 * not to attempt to unregister the driver later
+	 */
+	if (pci_module_init (&serial_pci_driver) != 0)
+		serial_pci_driver.name[0] = 0;
+
 #ifdef SERIAL_DEBUG_PCI
 	printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
 #endif
@@ -4682,7 +4756,7 @@
 	unsigned short device;
 };
 
-static struct pnp_board pnp_devices[] __initdata = {
+static struct pnp_board pnp_devices[] __devinitdata = {
 	/* Archtek America Corp. */
 	/* Archtek SmartLink Modem 3334BT Plug & Play */
 	{	ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
@@ -4972,14 +5046,14 @@
 			irq->map = map;
 }
 
-static char *modem_names[] __initdata = {
+static char *modem_names[] __devinitdata = {
        "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
        "56K", "56k", "K56", "33.6", "28.8", "14.4",
        "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
        "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
 };
 
-static int __init check_name(char *name)
+static int __devinit check_name(char *name)
 {
        char **tmp = modem_names;
 
@@ -5041,7 +5115,7 @@
        return 1;
 }
 
-static void __init probe_serial_pnp(void)
+static void __devinit probe_serial_pnp(void)
 {
        struct pci_dev *dev = NULL;
        struct pnp_board *pnp_board;
@@ -5252,7 +5326,7 @@
 }
 
 /*
- * This is for use by architectures that know their serial port
+ * This is for use by architectures that know their serial console 
  * attributes only at run time. Not to be invoked after rs_init().
  */
 int __init early_serial_setup(struct serial_struct *req)
@@ -5318,6 +5392,14 @@
 		    (rs_table[i].iomem_base == req->iomem_base))
 			break;
 	}
+#ifdef __i386__
+	if (i == NR_PORTS) {
+		for (i = 4; i < NR_PORTS; i++)
+			if ((rs_table[i].type == PORT_UNKNOWN) &&
+			    (rs_table[i].count == 0))
+				break;
+	}
+#endif
 	if (i == NR_PORTS) {
 		for (i = 0; i < NR_PORTS; i++)
 			if ((rs_table[i].type == PORT_UNKNOWN) &&
@@ -5441,12 +5523,13 @@
 #endif
 	}
 #if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
-	for (i=0; i < serial_pci_board_idx; i++) {
+	for (i=0; i < NR_PCI_BOARDS; i++) {
 		struct pci_board_inst *brd = &serial_pci_board[i];
-		
+
+		if (serial_pci_board[i].dev == 0)
+			continue;
 		if (brd->board.init_fn)
 			(brd->board.init_fn)(brd->dev, &brd->board, 0);
-
 		if (DEACTIVATE_FUNC(brd->dev))
 			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
 	}
@@ -5456,6 +5539,11 @@
 		tmp_buf = NULL;
 		free_page(pg);
 	}
+	
+#ifdef ENABLE_SERIAL_PCI
+	if (serial_pci_driver.name[0])
+		pci_unregister_driver (&serial_pci_driver);
+#endif
 }
 
 module_init(rs_init);
@@ -5491,10 +5579,13 @@
 		if (--tmout == 0)
 			break;
 	} while((status & BOTH_EMPTY) != BOTH_EMPTY);
-	if (info->flags & ASYNC_NO_FLOW)
-		return;
-	tmout = 1000000;
-	while (--tmout && ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+
+	/* Wait for flow control if necessary */
+	if (info->flags & ASYNC_CONS_FLOW) {
+		tmout = 1000000;
+		while (--tmout &&
+		       ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+	}	
 }
 
 
@@ -5577,7 +5668,7 @@
 }
 
 /*
- *	Setup initial baud/bits/parity/flow. We do two things here:
+ *	Setup initial baud/bits/parity/flow control. We do two things here:
  *	- construct a cflag setting for the first rs_open()
  *	- initialize the serial port
  *	Return non-zero if we didn't find a serial port.
@@ -5602,8 +5693,7 @@
 			s++;
 		if (*s) parity = *s++;
 		if (*s) bits   = *s++ - '0';
-		if ((*s) && (!strcmp(s, "rtscts")))
-			doflow = 1;
+		if (*s) doflow = (*s++ == 'r');
 	}
 
 	/*
@@ -5659,8 +5749,8 @@
 	 *	Divisor, bytesize and parity
 	 */
 	state = rs_table + co->index;
-	if (doflow == 0)
-		state->flags |= ASYNC_NO_FLOW;
+	if (doflow)
+		state->flags |= ASYNC_CONS_FLOW;
 	info = &async_sercons;
 	info->magic = SERIAL_MAGIC;
 	info->state = state;
diff -u --recursive --new-file v2.4.2/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.4.2/linux/drivers/char/stallion.c	Wed Feb 21 18:20:20 2001
+++ linux/drivers/char/stallion.c	Fri Mar  2 11:12:07 2001
@@ -165,12 +165,8 @@
  *	at 9600, 8 data bits, 1 stop bit.
  */
 static struct termios		stl_deftermios = {
-	0,
-	0,
-	(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
-	0,
-	0,
-	INIT_C_CC
+	c_cflag:	(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+	c_cc:		INIT_C_CC,
 };
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/char/sx.c linux/drivers/char/sx.c
--- v2.4.2/linux/drivers/char/sx.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/char/sx.c	Tue Mar  6 19:44:34 2001
@@ -1647,7 +1647,7 @@
 #if 0 
 	/* Removed superuser check: Sysops can use the permissions on the device
 	   file to restrict access. Recommendation: Root only. (root.root 600) */
-	if (!suser ()) {
+	if (!capable(CAP_SYS_ADMIN)) {
 		return -EPERM;
 	}
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.4.2/linux/drivers/char/synclink.c	Wed Feb 21 18:20:21 2001
+++ linux/drivers/char/synclink.c	Tue Mar  6 19:44:34 2001
@@ -54,7 +54,11 @@
  */
 
 #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
-#define BREAKPOINT() asm("   int $3");
+#if defined(__i386__)
+#  define BREAKPOINT() asm("   int $3");
+#else
+#  define BREAKPOINT() { }
+#endif
 
 #define MAX_ISA_DEVICES 10
 #define MAX_PCI_DEVICES 10
@@ -103,7 +107,7 @@
 #endif
 
 #ifdef CONFIG_SYNCLINK_SYNCPPP
-#include "../net/wan/syncppp.h"
+#include <net/syncppp.h>
 #endif
 
 #include <asm/segment.h>
@@ -6994,7 +6998,7 @@
 		status = info->rx_buffer_list[0].status;
 
 		if ( status & (BIT8 + BIT3 + BIT1) ) {
-			/* receive error has occured */
+			/* receive error has occurred */
 			rc = FALSE;
 		} else {
 			if ( memcmp( info->tx_buffer_list[0].virt_addr ,
diff -u --recursive --new-file v2.4.2/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.4.2/linux/drivers/char/tpqic02.c	Wed Feb 21 18:20:21 2001
+++ linux/drivers/char/tpqic02.c	Fri Mar  2 18:38:37 2001
@@ -30,6 +30,8 @@
  *
  * You are not allowed to change this line nor the text above.
  *
+ * 2001/02/26	Minor s/suser/capable/
+ *
  * 1996/10/10   Emerald changes
  *
  * 1996/05/21	Misc changes+merges+cleanups + I/O reservations
@@ -208,7 +210,7 @@
  * must ensure that a large enough buffer is passed to the kernel, in order
  * to reduce tape repositioning wear and tear.
  */
-static unsigned long buffaddr;	/* physical address of buffer */
+static void *buffaddr;	/* virtual address of buffer */
 
 /* This translates minor numbers to the corresponding recording format: */
 static const char *format_names[] = {
@@ -1376,7 +1378,7 @@
 	flags=claim_dma_lock();
 	clear_dma_ff(QIC02_TAPE_DMA);
 	set_dma_mode(QIC02_TAPE_DMA, dma_mode);
-	set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done);	/* full address */
+	set_dma_addr(QIC02_TAPE_DMA, virt_to_bus(buffaddr) + dma_bytes_done);
 	set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE);
 
 	/* start tape DMA controller */
@@ -1921,7 +1923,7 @@
 	    /* copy buffer to user-space in one go */
 	    if (bytes_done>0)
 	    {
-		err = copy_to_user( (void *) buf, (void *) bus_to_virt(buffaddr), bytes_done);
+		err = copy_to_user(buf, buffaddr, bytes_done);
 		if (err)
 		{
 		    return -EFAULT;
@@ -2074,7 +2076,7 @@
 	/* copy from user to DMA buffer and initiate transfer. */
 	if (bytes_todo>0)
 	{
-	    err = copy_from_user( (void *) bus_to_virt(buffaddr), (const void *) buf, bytes_todo);
+	    err = copy_from_user(buffaddr, buf, bytes_todo);
 	    if (err)
 	    {
 		return -EFAULT;
@@ -2198,7 +2200,7 @@
 
     if (MINOR(dev)==255)	/* special case for resetting */
     {
-	if (suser())
+	if (capable(CAP_SYS_ADMIN))
 	{
 	    return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO;
 	}
@@ -2607,7 +2609,7 @@
 	
 	CHECK_IOC_SIZE(mtconfiginfo);
 	
-	if (!suser())
+	if (!capable(CAP_SYS_ADMIN))
 	{
 	    return -EPERM;
 	}
@@ -2780,7 +2782,7 @@
     release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
     if (buffaddr)
     {
-	free_pages(buffaddr, get_order(TPQBUF_SIZE));
+	free_pages((unsigned long)buffaddr, get_order(TPQBUF_SIZE));
     }
     buffaddr = 0; /* Better to cause a panic than overwite someone else */
     status_zombie = YES;
@@ -2830,9 +2832,7 @@
     request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, TPQIC02_NAME);
     
     /* Setup the page-address for the dma transfer. */
-
-    /*** TODO: does _get_dma_pages() really return the physical address?? ****/
-    buffaddr = __get_dma_pages(GFP_KERNEL,get_order(TPQBUF_SIZE));
+    buffaddr = (void *)__get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
     
     if (!buffaddr)
     {
@@ -2840,7 +2840,7 @@
 	return -EBUSY; /* Not ideal, EAGAIN perhaps? */
     }
     
-    memset( (void*) buffaddr, 0, TPQBUF_SIZE );
+    memset(buffaddr, 0, TPQBUF_SIZE);
     
     printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
 	   QIC02_TAPE_IRQ, QIC02_TAPE_DMA,
diff -u --recursive --new-file v2.4.2/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.4.2/linux/drivers/char/tty_io.c	Wed Feb 21 18:20:21 2001
+++ linux/drivers/char/tty_io.c	Thu Mar 22 09:20:45 2001
@@ -60,6 +60,9 @@
  *
  * Reduced memory usage for older ARM systems
  *      -- Russell King <rmk@arm.linux.org.uk>
+ *
+ * Move do_SAK() into process context.  Less stack use in devfs functions.
+ * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
  */
 
 #include <linux/config.h>
@@ -159,26 +162,19 @@
 #define MAX(a,b)	((a) < (b) ? (b) : (a))
 #endif
 
-static inline struct tty_struct *alloc_tty_struct(void)
+static struct tty_struct *alloc_tty_struct(void)
 {
 	struct tty_struct *tty;
 
-	if (PAGE_SIZE > 8192) {
-		tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
-		if (tty)
-			memset(tty, 0, sizeof(struct tty_struct));
-	} else
-		tty = (struct tty_struct *)get_zeroed_page(GFP_KERNEL);
-
+	tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
+	if (tty)
+		memset(tty, 0, sizeof(struct tty_struct));
 	return tty;
 }
 
 static inline void free_tty_struct(struct tty_struct *tty)
 {
-	if (PAGE_SIZE > 8192)
-		kfree(tty);
-	else
-		free_page((unsigned long) tty);
+	kfree(tty);
 }
 
 /*
@@ -1814,12 +1810,16 @@
  * Now, if it would be correct ;-/ The current code has a nasty hole -
  * it doesn't catch files in flight. We may send the descriptor to ourselves
  * via AF_UNIX socket, close it and later fetch from socket. FIXME.
+ *
+ * Nasty bug: do_SAK is being called in interrupt context.  This can
+ * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
  */
-void do_SAK( struct tty_struct *tty)
+static void __do_SAK(void *arg)
 {
 #ifdef TTY_SOFT_SAK
 	tty_hangup(tty);
 #else
+	struct tty_struct *tty = arg;
 	struct task_struct *p;
 	int session;
 	int		i;
@@ -1842,7 +1842,6 @@
 		task_lock(p);
 		if (p->files) {
 			read_lock(&p->files->file_lock);
-			/* FIXME: p->files could change */
 			for (i=0; i < p->files->max_fds; i++) {
 				filp = fcheck_files(p->files, i);
 				if (filp && (filp->f_op == &tty_fops) &&
@@ -1860,6 +1859,19 @@
 }
 
 /*
+ * The tq handling here is a little racy - tty->SAK_tq may already be queued.
+ * But there's no mechanism to fix that without futzing with tqueue_lock.
+ * Fortunately we don't need to worry, because if ->SAK_tq is already queued,
+ * the values which we write to it will be identical to the values which it
+ * already has. --akpm
+ */
+void do_SAK(struct tty_struct *tty)
+{
+	PREPARE_TQUEUE(&tty->SAK_tq, __do_SAK, tty);
+	schedule_task(&tty->SAK_tq);
+}
+
+/*
  * This routine is called out of the software interrupt to flush data
  * from the flip buffer to the line discipline.
  */
@@ -1973,6 +1985,7 @@
 	sema_init(&tty->atomic_write, 1);
 	spin_lock_init(&tty->read_lock);
 	INIT_LIST_HEAD(&tty->tty_files);
+	INIT_TQUEUE(&tty->SAK_tq, 0, 0);
 }
 
 /*
@@ -1986,17 +1999,15 @@
 /*
  * Register a tty device described by <driver>, with minor number <minor>.
  */
-void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
-			 unsigned int minor)
+void tty_register_devfs (struct tty_driver *driver, unsigned int flags, unsigned minor)
 {
 #ifdef CONFIG_DEVFS_FS
 	umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
-	struct tty_struct tty;
+	kdev_t device = MKDEV (driver->major, minor);
+	int idx = minor - driver->minor_start;
 	char buf[32];
 
-	tty.driver = *driver;
-	tty.device = MKDEV (driver->major, minor);
-	switch (tty.device) {
+	switch (device) {
 		case TTY_DEV:
 		case PTMX_DEV:
 			mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
@@ -2017,7 +2028,8 @@
 	     (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) )
 		flags |= DEVFS_FL_CURRENT_OWNER;
 #  endif
-	devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT,
+	sprintf(buf, driver->name, idx + driver->name_base);
+	devfs_register (NULL, buf, flags | DEVFS_FL_DEFAULT,
 			driver->major, minor, mode, &tty_fops, NULL);
 #endif /* CONFIG_DEVFS_FS */
 }
@@ -2026,14 +2038,11 @@
 {
 #ifdef CONFIG_DEVFS_FS
 	void * handle;
-	struct tty_struct tty;
+	int idx = minor - driver->minor_start;
 	char buf[32];
 
-	tty.driver = *driver;
-	tty.device = MKDEV(driver->major, minor);
-	
-	handle = devfs_find_handle (NULL, tty_name (&tty, buf),
-				    driver->major, minor,
+	sprintf(buf, driver->name, idx + driver->name_base);
+	handle = devfs_find_handle (NULL, buf, driver->major, minor,
 				    DEVFS_SPECIAL_CHR, 0);
 	devfs_unregister (handle);
 #endif /* CONFIG_DEVFS_FS */
@@ -2218,9 +2227,6 @@
  */
 void __init tty_init(void)
 {
-	if (sizeof(struct tty_struct) > PAGE_SIZE)
-		panic("size of tty structure > PAGE_SIZE!");
-
 	/*
 	 * dev_tty_driver and dev_console_driver are actually magic
 	 * devices which get redirected at open time.  Nevertheless,
diff -u --recursive --new-file v2.4.2/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c
--- v2.4.2/linux/drivers/i2c/i2c-algo-bit.c	Wed Feb 21 18:20:21 2001
+++ linux/drivers/i2c/i2c-algo-bit.c	Tue Mar  6 19:44:34 2001
@@ -169,7 +169,7 @@
 /* returns:
  * 1 if the device acknowledged
  * 0 if the device did not ack
- * -ETIMEDOUT if an error occured (while raising the scl line)
+ * -ETIMEDOUT if an error occurred (while raising the scl line)
  */
 static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
 {
@@ -421,7 +421,7 @@
  * reads, writes as well as 10bit-addresses.
  * returns:
  *  0 everything went okay, the chip ack'ed
- * -x an error occured (like: -EREMOTEIO if the device did not answer, or
+ * -x an error occurred (like: -EREMOTEIO if the device did not answer, or
  *	-ETIMEDOUT, for example if the lines are stuck...) 
  */
 static inline int bit_doAddress(struct i2c_adapter *i2c_adap,
@@ -445,7 +445,7 @@
 		/* the remaining 8 bit address */
 		ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
 		if (ret != 1) {
-			/* the chip did not ack / xmission error occured */
+			/* the chip did not ack / xmission error occurred */
 			printk("died at 2nd address code.\n");
 			return -EREMOTEIO;
 		}
diff -u --recursive --new-file v2.4.2/linux/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- v2.4.2/linux/drivers/ide/ide-probe.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ide/ide-probe.c	Sun Mar 18 09:25:02 2001
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/ide-probe.c	Version 1.06	June 9, 2000
+ *  linux/drivers/ide/ide-probe.c	Version 1.07	March 18, 2001
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -25,6 +25,8 @@
  *			allowed for secondary flash card to be detectable
  *			 with new flag : drive->ata_flash : 1;
  * Version 1.06		stream line request queue and prep for cascade project.
+ * Version 1.07		max_sect <= 255; slower disks would get behind and
+ * 			then fall over when they get to 256.	Paul G.
  */
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
@@ -614,9 +616,14 @@
 {
 	unsigned long flags;
 	unsigned int index;
-	ide_hwgroup_t *hwgroup;
+	ide_hwgroup_t *hwgroup, *new_hwgroup;
 	ide_hwif_t *match = NULL;
 
+	
+	/* Allocate the buffer and potentially sleep first */
+	
+	new_hwgroup = kmalloc(sizeof(ide_hwgroup_t),GFP_KERNEL);
+	
 	save_flags(flags);	/* all CPUs */
 	cli();			/* all CPUs */
 
@@ -650,10 +657,14 @@
 	 */
 	if (match) {
 		hwgroup = match->hwgroup;
+		if(new_hwgroup)
+			kfree(new_hwgroup);
 	} else {
-		hwgroup = kmalloc(sizeof(ide_hwgroup_t), GFP_KERNEL);
-		if (!hwgroup)
+		hwgroup = new_hwgroup;
+		if (!hwgroup) {
+			restore_flags(flags);	/* all CPUs */
 			return 1;
+		}
 		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
 		hwgroup->hwif     = hwif->next = hwif;
 		hwgroup->rq       = NULL;
@@ -763,10 +774,10 @@
 	for (unit = 0; unit < minors; ++unit) {
 		*bs++ = BLOCK_SIZE;
 #ifdef CONFIG_BLK_DEV_PDC4030
-		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 256);
+		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 255);
 #else
 		/* IDE can do up to 128K per request. */
-		*max_sect++ = 256;
+		*max_sect++ = 255;
 #endif
 		*max_ra++ = MAX_READAHEAD;
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.4.2/linux/drivers/ide/ide.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ide/ide.c	Tue Mar  6 19:44:34 2001
@@ -1400,7 +1400,7 @@
 
 	if ((handler = hwgroup->handler) == NULL) {
 		/*
-		 * Either a marginal timeout occured
+		 * 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.
@@ -2467,8 +2467,7 @@
 void ide_delay_50ms (void)
 {
 #ifndef CONFIG_BLK_DEV_IDECS
-	unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
-	while (0 < (signed long)(timeout - jiffies));
+	mdelay(50);
 #else
 	__set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ/20);
diff -u --recursive --new-file v2.4.2/linux/drivers/ide/pdc4030.c linux/drivers/ide/pdc4030.c
--- v2.4.2/linux/drivers/ide/pdc4030.c	Thu Apr 13 22:54:26 2000
+++ linux/drivers/ide/pdc4030.c	Tue Mar  6 19:44:34 2001
@@ -445,9 +445,9 @@
 
 /*
  * 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 transfered
+ * 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 transfered. There is no interrupt generated
+ * 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)
diff -u --recursive --new-file v2.4.2/linux/drivers/ide/piix.c linux/drivers/ide/piix.c
--- v2.4.2/linux/drivers/ide/piix.c	Tue Jan  2 16:58:45 2001
+++ linux/drivers/ide/piix.c	Tue Mar  6 19:44:34 2001
@@ -226,7 +226,7 @@
 
 /*
  *  Based on settings done by AMI BIOS
- *  (might be usefull if drive is not registered in CMOS for any reason).
+ *  (might be useful if drive is not registered in CMOS for any reason).
  */
 static void piix_tune_drive (ide_drive_t *drive, byte pio)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/ide/slc90e66.c linux/drivers/ide/slc90e66.c
--- v2.4.2/linux/drivers/ide/slc90e66.c	Mon Oct 16 12:21:40 2000
+++ linux/drivers/ide/slc90e66.c	Tue Mar  6 19:44:34 2001
@@ -181,7 +181,7 @@
 
 /*
  *  Based on settings done by AMI BIOS
- *  (might be usefull if drive is not registered in CMOS for any reason).
+ *  (might be useful if drive is not registered in CMOS for any reason).
  */
 static void slc90e66_tune_drive (ide_drive_t *drive, byte pio)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/aic5800.c linux/drivers/ieee1394/aic5800.c
--- v2.4.2/linux/drivers/ieee1394/aic5800.c	Wed Oct 11 16:49:47 2000
+++ linux/drivers/ieee1394/aic5800.c	Fri Mar  2 18:38:38 2001
@@ -657,7 +657,7 @@
 	};
     }
     if ( interruptEvent & INT_BusReset ) {
-	PRINT(KERN_INFO, aic->id, "bus reset occured");
+	PRINT(KERN_INFO, aic->id, "bus reset occurred");
 	if (!host->in_bus_reset) {
 	    hpsb_bus_reset(host);
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/csr.c linux/drivers/ieee1394/csr.c
--- v2.4.2/linux/drivers/ieee1394/csr.c	Tue Jan  2 16:45:38 2001
+++ linux/drivers/ieee1394/csr.c	Thu Mar  1 16:57:11 2001
@@ -403,31 +403,30 @@
 }
 
 
-struct hpsb_highlevel_ops csr_ops = {
+static struct hpsb_highlevel_ops csr_ops = {
         add_host: add_host,
         host_reset: host_reset,
 };
 
 
-struct hpsb_address_ops map_ops = {
+static struct hpsb_address_ops map_ops = {
         read: read_maps,
 };
 
-struct hpsb_address_ops fcp_ops = {
+static struct hpsb_address_ops fcp_ops = {
         write: write_fcp,
 };
 
-struct hpsb_address_ops reg_ops = {
+static struct hpsb_address_ops reg_ops = {
         read: read_regs,
         write: write_regs,
         lock: lock_regs,
 };
 
+static struct hpsb_highlevel *hl;
 
 void init_csr(void)
 {
-        struct hpsb_highlevel *hl;
-
         hl = hpsb_register_highlevel("standard registers", &csr_ops);
         if (hl == NULL) {
                 HPSB_ERR("out of memory during ieee1394 initialization");
@@ -448,4 +447,9 @@
         hpsb_register_addrspace(hl, &map_ops,
                                 CSR_REGISTER_BASE + CSR_SPEED_MAP,
                                 CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
+}
+
+void cleanup_csr(void)
+{
+        hpsb_unregister_highlevel(hl);
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/csr.h linux/drivers/ieee1394/csr.h
--- v2.4.2/linux/drivers/ieee1394/csr.h	Wed Mar 22 00:02:48 2000
+++ linux/drivers/ieee1394/csr.h	Thu Mar  1 16:57:11 2001
@@ -50,5 +50,6 @@
 
 
 void init_csr(void);
+void cleanup_csr(void);
 
 #endif /* _IEEE1394_CSR_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/guid.c linux/drivers/ieee1394/guid.c
--- v2.4.2/linux/drivers/ieee1394/guid.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ieee1394/guid.c	Thu Mar  1 16:57:11 2001
@@ -219,11 +219,19 @@
         host_reset:  host_reset,
 };
 
+static struct hpsb_highlevel *hl;
+
 void init_ieee1394_guid(void)
 {
         atomic_set(&outstanding_requests, 0);
 
-        if (!hpsb_register_highlevel("GUID manager", &guid_ops)) {
+        hl = hpsb_register_highlevel("GUID manager", &guid_ops);
+        if (!hl) {
                 HPSB_ERR("out of memory during ieee1394 initialization");
         }
+}
+
+void cleanup_ieee1394_guid(void)
+{
+        hpsb_unregister_highlevel(hl);
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/guid.h linux/drivers/ieee1394/guid.h
--- v2.4.2/linux/drivers/ieee1394/guid.h	Mon Jun 19 17:59:40 2000
+++ linux/drivers/ieee1394/guid.h	Thu Mar  1 16:57:11 2001
@@ -49,6 +49,6 @@
 
 
 void init_ieee1394_guid(void);
-
+void cleanup_ieee1394_guid(void);
 
 #endif /* _IEEE1394_GUID_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- v2.4.2/linux/drivers/ieee1394/ieee1394_core.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Thu Mar  1 16:57:11 2001
@@ -269,7 +269,7 @@
         }
 
         /* set self mapping */
-        for (i = nodecount - 1; i; i--) {
+        for (i = 0; i < nodecount; i++) {
                 map[64*i + i] = speedcap[i];
         }
 
@@ -802,6 +802,12 @@
         init_ieee1394_guid();
 
         return 0;
+}
+
+void cleanup_module(void)
+{
+        cleanup_ieee1394_guid();
+        cleanup_csr();
 }
 
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.4.2/linux/drivers/ieee1394/ohci1394.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ieee1394/ohci1394.c	Fri Mar  2 18:38:38 2001
@@ -1129,7 +1129,7 @@
 		/*
 		 * Problem: How can I ensure that the AT bottom half will be
 		 * executed before the AR bottom half (both events may have
-		 * occured within a single irq event)
+		 * occurred within a single irq event)
 		 * Quick hack: just launch it within the IRQ handler
 		 */
 		if (event & OHCI1394_reqTxComplete) { 
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h
--- v2.4.2/linux/drivers/ieee1394/ohci1394.h	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ieee1394/ohci1394.h	Tue Mar  6 19:28:32 2001
@@ -75,10 +75,6 @@
 #define PCI_DEVICE_ID_NEC_UPD72871      0x00ce
 #endif
 
-#ifndef PCI_DEVICE_ID_APPLE_UNI_N_FW
-#define PCI_DEVICE_ID_APPLE_UNI_N_FW	0x0018
-#endif
-
 #ifndef PCI_DEVICE_ID_ALI_OHCI1394_M5251
 #define PCI_DEVICE_ID_ALI_OHCI1394_M5251 0x5251
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- v2.4.2/linux/drivers/ieee1394/pcilynx.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/ieee1394/pcilynx.c	Tue Mar 20 15:42:18 2001
@@ -470,8 +470,6 @@
         lynx->phy_reg0 = -1;
 
         lynx->async.queue = NULL;
-        spin_lock_init(&lynx->async.queue_lock);
-        spin_lock_init(&lynx->phy_reg_lock);
         
         pcl.next = pcl_bus(lynx, lynx->rcv_pcl);
         put_pcl(lynx, lynx->rcv_pcl_start, &pcl);
@@ -1127,7 +1125,7 @@
 
         if (intmask & PCI_INT_1394) {
                 if (linkint & LINK_INT_PHY_TIMEOUT) {
-                        PRINT(KERN_INFO, lynx->id, "PHY timeout occured");
+                        PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");
                 }
                 if (linkint & LINK_INT_PHY_BUSRESET) {
                         PRINT(KERN_INFO, lynx->id, "bus reset interrupt");
@@ -1357,7 +1355,10 @@
         lynx->id = num_of_cards-1;
         lynx->dev = dev;
 
-        if (!pci_dma_supported(dev, 0xffffffff)) {
+	lynx->lock = SPIN_LOCK_UNLOCKED;
+	lynx->phy_reg_lock = SPIN_LOCK_UNLOCKED;
+
+        if (pci_set_dma_mask(dev, 0xffffffff)) {
                 FAIL("DMA address limits not supported for PCILynx hardware %d",
                      lynx->id);
         }
@@ -1456,8 +1457,6 @@
         lynx->iso_rcv.pcl_start = alloc_pcl(lynx);
 
         /* all allocations successful - simple init stuff follows */
-
-        lynx->lock = SPIN_LOCK_UNLOCKED;
 
         reg_write(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- v2.4.2/linux/drivers/isdn/Config.in	Tue Jan  2 16:45:37 2001
+++ linux/drivers/isdn/Config.in	Fri Mar  2 11:12:10 2001
@@ -9,7 +9,7 @@
    if [ "$CONFIG_ISDN_PPP" != "n" ]; then
       bool         '    Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
       bool         '    Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
-      dep_tristate '    Support BSD compression (module only)' CONFIG_ISDN_PPP_BSDCOMP m
+      dep_tristate '    Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN
    fi
 fi
 bool '  Support audio via ISDN' CONFIG_ISDN_AUDIO
@@ -23,7 +23,7 @@
 mainmenu_option next_comment
 comment 'ISDN feature submodules'
    dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-   dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN m
+   dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
 endmenu
 
 comment 'low-level hardware drivers'
@@ -77,6 +77,9 @@
       fi
    fi
 fi
+
+dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
+
 endmenu
 
 ### Active ISDN cards
@@ -92,7 +95,7 @@
 bool               'Eicon active card support' CONFIG_ISDN_DRV_EICON
 if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
    if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
-      dep_tristate '  Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN
+      dep_tristate '  Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN $CONFIG_PCI
    fi
    if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
       dep_tristate '  Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile
--- v2.4.2/linux/drivers/isdn/Makefile	Fri Dec 29 14:40:54 2000
+++ linux/drivers/isdn/Makefile	Fri Mar  2 11:12:10 2001
@@ -11,8 +11,7 @@
 # Multipart objects.
 
 list-multi	:= isdn.o
-isdn-objs	:= isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o \
-		   isdn_common.o
+isdn-objs	:= isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
 
 # Optional parts of multipart objects.
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/act2000.h linux/drivers/isdn/act2000/act2000.h
--- v2.4.2/linux/drivers/isdn/act2000/act2000.h	Wed Feb 21 18:20:22 2001
+++ linux/drivers/isdn/act2000/act2000.h	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: act2000.h,v 1.8 2000/11/12 16:32:06 kai Exp $
+/* $Id: act2000.h,v 1.8.6.2 2001/02/16 16:43:23 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/capi.c linux/drivers/isdn/act2000/capi.c
--- v2.4.2/linux/drivers/isdn/act2000/capi.c	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/act2000/capi.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.9 2000/11/12 16:32:06 kai Exp $
+/* $Id: capi.c,v 1.9.6.1 2001/02/16 16:43:23 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *        CAPI encoder/decoder
@@ -124,7 +124,7 @@
 	        m->hdr.cmd.cmd = c; \
 	        m->hdr.cmd.subcmd = s; \
 	        m->hdr.msgnum = actcapi_nextsmsg(card); \
-	} \
+	} else m = NULL;\
 }
 
 #define ACTCAPI_CHKSKB if (!skb) { \
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/capi.h linux/drivers/isdn/act2000/capi.h
--- v2.4.2/linux/drivers/isdn/act2000/capi.h	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/act2000/capi.h	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: capi.h,v 1.6 2000/11/12 16:32:06 kai Exp $
+/* $Id: capi.h,v 1.6.6.1 2001/02/16 16:43:23 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
@@ -44,7 +44,7 @@
 	char *description;
 } actcapi_msgdsc;
 
-/* CAPI Adress */
+/* CAPI Address */
 typedef struct actcapi_addr {
 	__u8 len;                            /* Length of element            */
 	__u8 tnp;                            /* Type/Numbering Plan          */
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/act2000/module.c linux/drivers/isdn/act2000/module.c
--- v2.4.2/linux/drivers/isdn/act2000/module.c	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/act2000/module.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: module.c,v 1.14 2000/11/12 16:32:06 kai Exp $
+/* $Id: module.c,v 1.14.6.2 2000/12/18 22:14:10 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
@@ -24,6 +24,7 @@
 #include "act2000.h"
 #include "act2000_isa.h"
 #include "capi.h"
+#include <linux/init.h>
 
 static unsigned short act2000_isa_ports[] =
 {
@@ -820,12 +821,7 @@
 
 #define DRIVERNAME "IBM Active 2000 ISDN driver"
 
-#ifdef MODULE
-#define act2000_init init_module
-#endif
-
-int
-act2000_init(void)
+static int __init act2000_init(void)
 {
         printk(KERN_INFO "%s\n", DRIVERNAME);
         if (!cards)
@@ -837,9 +833,7 @@
         return 0;
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void __exit act2000_exit(void)
 {
         act2000_card *card = cards;
         act2000_card *last;
@@ -858,34 +852,5 @@
         printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
 }
 
-#else
-void
-act2000_setup(char *str, int *ints)
-{
-        int i, j, argc, port, irq, bus;
-	
-        argc = ints[0];
-        i = 1;
-        if (argc)
-                while (argc) {
-                        port = irq = -1;
-			bus = 0;
-                        if (argc) {
-                                bus = ints[i];
-                                i++;
-                                argc--;
-                        }
-                        if (argc) {
-                                port = ints[i];
-                                i++;
-                                argc--;
-                        }
-                        if (argc) {
-                                irq = ints[i];
-                                i++;
-                                argc--;
-                        }
-			act2000_addcard(bus, port, irq, act_id);
-		}
-}
-#endif
+module_init(act2000_init);
+module_exit(act2000_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/avm_cs.c linux/drivers/isdn/avmb1/avm_cs.c
--- v2.4.2/linux/drivers/isdn/avmb1/avm_cs.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/isdn/avmb1/avm_cs.c	Fri Mar  2 11:12:07 2001
@@ -138,6 +138,8 @@
     
     /* Initialize the dev_link_t structure */
     link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    if (!link)
+	return NULL;
     memset(link, 0, sizeof(struct dev_link_t));
     link->release.function = &avmcs_release;
     link->release.data = (u_long)link;
@@ -169,6 +171,8 @@
 
     /* Allocate space for private device-specific data */
     local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    if (!local)
+	return NULL;
     memset(local, 0, sizeof(local_info_t));
     link->priv = local;
     
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c
--- v2.4.2/linux/drivers/isdn/avmb1/b1.c	Tue Nov 28 21:43:13 2000
+++ linux/drivers/isdn/avmb1/b1.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: b1.c,v 1.20 2000/11/23 20:45:14 kai Exp $
+ * $Id: b1.c,v 1.20.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Common module for AVM B1 cards.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1.c,v $
+ * Revision 1.20.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.20  2000/11/23 20:45:14  kai
  * fixed module_init/exit stuff
  * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
@@ -117,7 +120,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.20 $";
+static char *revision = "$Revision: 1.20.6.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c
--- v2.4.2/linux/drivers/isdn/avmb1/b1dma.c	Tue Nov 28 21:43:13 2000
+++ linux/drivers/isdn/avmb1/b1dma.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: b1dma.c,v 1.11 2000/11/19 17:02:47 kai Exp $
+ * $Id: b1dma.c,v 1.11.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1dma.c,v $
+ * Revision 1.11.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.11  2000/11/19 17:02:47  kai
  * compatibility cleanup - part 3
  *
@@ -62,7 +65,7 @@
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.11 $";
+static char *revision = "$Revision: 1.11.6.1 $";
 
 /* ------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1isa.c linux/drivers/isdn/avmb1/b1isa.c
--- v2.4.2/linux/drivers/isdn/avmb1/b1isa.c	Tue Nov 28 21:43:13 2000
+++ linux/drivers/isdn/avmb1/b1isa.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: b1isa.c,v 1.10 2000/11/23 20:45:14 kai Exp $
+ * $Id: b1isa.c,v 1.10.6.2 2001/02/16 16:43:23 kai Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1isa.c,v $
+ * Revision 1.10.6.2  2001/02/16 16:43:23  kai
+ * Changes from -ac16, little bug fixes, typos and the like
+ *
+ * Revision 1.10.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.10  2000/11/23 20:45:14  kai
  * fixed module_init/exit stuff
  * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
@@ -24,7 +30,7 @@
  * - fixed problem with memory mapping if address is not aligned
  *
  * Revision 1.6  2000/01/25 14:37:39  calle
- * new message after successfull detection including card revision and
+ * new message after successful detection including card revision and
  * used resources.
  *
  * Revision 1.5  1999/11/05 16:38:01  calle
@@ -83,7 +89,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.10.6.2 $";
 
 /* ------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/b1pcmcia.c linux/drivers/isdn/avmb1/b1pcmcia.c
--- v2.4.2/linux/drivers/isdn/avmb1/b1pcmcia.c	Tue Nov 28 21:43:13 2000
+++ linux/drivers/isdn/avmb1/b1pcmcia.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: b1pcmcia.c,v 1.12 2000/11/23 20:45:14 kai Exp $
+ * $Id: b1pcmcia.c,v 1.12.6.2 2001/02/16 16:43:23 kai Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pcmcia.c,v $
+ * Revision 1.12.6.2  2001/02/16 16:43:23  kai
+ * Changes from -ac16, little bug fixes, typos and the like
+ *
+ * Revision 1.12.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.12  2000/11/23 20:45:14  kai
  * fixed module_init/exit stuff
  * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
@@ -33,7 +39,7 @@
  * - fixed problem with memory mapping if address is not aligned
  *
  * Revision 1.6  2000/01/25 14:37:39  calle
- * new message after successfull detection including card revision and
+ * new message after successful detection including card revision and
  * used resources.
  *
  * Revision 1.5  1999/11/05 16:38:01  calle
@@ -93,7 +99,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.12.6.2 $";
 
 /* ------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- v2.4.2/linux/drivers/isdn/avmb1/c4.c	Tue Nov 28 21:44:41 2000
+++ linux/drivers/isdn/avmb1/c4.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: c4.c,v 1.20.6.1 2000/11/28 12:02:45 kai Exp $
+ * $Id: c4.c,v 1.20.6.3 2001/02/16 16:43:23 kai Exp $
  * 
  * Module for AVM C4 card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: c4.c,v $
+ * Revision 1.20.6.3  2001/02/16 16:43:23  kai
+ * Changes from -ac16, little bug fixes, typos and the like
+ *
+ * Revision 1.20.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.20.6.1  2000/11/28 12:02:45  kai
  * MODULE_DEVICE_TABLE for 2.4
  *
@@ -75,7 +81,7 @@
  * - fixed problem with memory mapping if address is not aligned
  *
  * Revision 1.3  2000/01/25 14:37:39  calle
- * new message after successfull detection including card revision and
+ * new message after successful detection including card revision and
  * used resources.
  *
  * Revision 1.2  2000/01/21 20:52:58  keil
@@ -106,7 +112,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.1 $";
+static char *revision = "$Revision: 1.20.6.3 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
@@ -1330,7 +1336,6 @@
 
     add_card: 0, /* no add_card function */
 };
-
 
 static int ncards = 0;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- v2.4.2/linux/drivers/isdn/avmb1/capi.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/isdn/avmb1/capi.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: capi.c,v 1.44.6.3 2000/12/17 22:45:08 kai Exp $
+ * $Id: capi.c,v 1.44.6.5 2001/02/13 11:43:29 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.44.6.5  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.44.6.4  2001/02/10 14:41:20  kai
+ * Changes from kernel tree
+ *
  * Revision 1.44.6.3  2000/12/17 22:45:08  kai
  * That's hopefully it for test13-4
  *
@@ -253,7 +259,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.44.6.3 $";
+static char *revision = "$Revision: 1.44.6.5 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
@@ -1317,7 +1323,6 @@
 #ifdef _DEBUG_REFCOUNT
 	printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE));
 #endif
-
 	mp->datahandle = 0;
 	mp->file = file;
 	file->private_data = (void *)mp;
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c
--- v2.4.2/linux/drivers/isdn/avmb1/capidrv.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/isdn/avmb1/capidrv.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: capidrv.c,v 1.39 2000/11/23 20:45:14 kai Exp $
+ * $Id: capidrv.c,v 1.39.6.2 2001/02/13 11:43:29 kai Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.39.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.39.6.1  2001/02/10 14:41:20  kai
+ * Changes from kernel tree
+ *
  * Revision 1.39  2000/11/23 20:45:14  kai
  * fixed module_init/exit stuff
  * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
@@ -219,7 +225,7 @@
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.39 $";
+static char *revision = "$Revision: 1.39.6.2 $";
 static int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
@@ -488,7 +494,7 @@
 }
 
 
-/* -------- controller managment ------------------------------------- */
+/* -------- controller management ------------------------------------- */
 
 static inline capidrv_contr *findcontrbydriverid(int driverid)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capifs.c linux/drivers/isdn/avmb1/capifs.c
--- v2.4.2/linux/drivers/isdn/avmb1/capifs.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/isdn/avmb1/capifs.c	Fri Mar  2 11:12:07 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: capifs.c,v 1.14.6.1 2000/11/28 12:02:45 kai Exp $
+ * $Id: capifs.c,v 1.14.6.3 2001/02/13 11:43:29 kai Exp $
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
  *
  * Heavily based on devpts filesystem from H. Peter Anvin
  * 
  * $Log: capifs.c,v $
+ * Revision 1.14.6.3  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.14.6.2  2001/02/10 14:41:20  kai
+ * Changes from kernel tree
+ *
  * Revision 1.14.6.1  2000/11/28 12:02:45  kai
  * MODULE_DEVICE_TABLE for 2.4
  *
@@ -93,7 +99,7 @@
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
 
-static char *revision = "$Revision: 1.14.6.1 $";
+static char *revision = "$Revision: 1.14.6.3 $";
 
 struct capifs_ncci {
 	struct inode *inode;
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/capiutil.c linux/drivers/isdn/avmb1/capiutil.c
--- v2.4.2/linux/drivers/isdn/avmb1/capiutil.c	Tue Nov 28 21:43:13 2000
+++ linux/drivers/isdn/avmb1/capiutil.c	Fri Mar  2 11:12:07 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: capiutil.c,v 1.13 2000/11/23 20:45:14 kai Exp $
+ * $Id: capiutil.c,v 1.13.6.1 2001/02/13 11:43:29 kai Exp $
  *
  * CAPI 2.0 convert capi message to capi message struct
  *
@@ -7,6 +7,9 @@
  * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capiutil.c,v $
+ * Revision 1.13.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.13  2000/11/23 20:45:14  kai
  * fixed module_init/exit stuff
  * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- v2.4.2/linux/drivers/isdn/avmb1/kcapi.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/isdn/avmb1/kcapi.c	Fri Mar  2 11:12:08 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: kcapi.c,v 1.21.6.1 2000/12/10 23:39:19 kai Exp $
+ * $Id: kcapi.c,v 1.21.6.2 2001/02/13 11:43:29 kai Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: kcapi.c,v $
+ * Revision 1.21.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.21.6.1  2000/12/10 23:39:19  kai
  * in 2.4 we don't have tq_scheduler anymore.
  * also add one supported card to hfc_pci.c
@@ -136,7 +139,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.21.6.1 $";
+static char *revision = "$Revision: 1.21.6.2 $";
 
 /* ------------------------------------------------------------- */
 
@@ -814,7 +817,7 @@
 	}
 }
 /*
- * ncci managment
+ * ncci management
  */
 
 static void controllercb_new_ncci(struct capi_ctr * card,
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c
--- v2.4.2/linux/drivers/isdn/avmb1/t1isa.c	Tue Nov 28 21:43:13 2000
+++ linux/drivers/isdn/avmb1/t1isa.c	Fri Mar  2 11:12:08 2001
@@ -1,11 +1,17 @@
 /*
- * $Id: t1isa.c,v 1.16 2000/11/23 20:45:14 kai Exp $
+ * $Id: t1isa.c,v 1.16.6.2 2001/02/16 16:43:24 kai Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1isa.c,v $
+ * Revision 1.16.6.2  2001/02/16 16:43:24  kai
+ * Changes from -ac16, little bug fixes, typos and the like
+ *
+ * Revision 1.16.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.16  2000/11/23 20:45:14  kai
  * fixed module_init/exit stuff
  * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
@@ -33,7 +39,7 @@
  * - fixed problem with memory mapping if address is not aligned
  *
  * Revision 1.9  2000/01/25 14:37:39  calle
- * new message after successfull detection including card revision and
+ * new message after successful detection including card revision and
  * used resources.
  *
  * Revision 1.8  1999/11/05 16:38:01  calle
@@ -104,7 +110,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.16 $";
+static char *revision = "$Revision: 1.16.6.2 $";
 
 /* ------------------------------------------------------------- */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- v2.4.2/linux/drivers/isdn/avmb1/t1pci.c	Tue Nov 28 21:44:41 2000
+++ linux/drivers/isdn/avmb1/t1pci.c	Fri Mar  2 11:12:08 2001
@@ -1,11 +1,14 @@
 /*
- * $Id: t1pci.c,v 1.13.6.1 2000/11/28 12:02:45 kai Exp $
+ * $Id: t1pci.c,v 1.13.6.2 2001/02/13 11:43:29 kai Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1pci.c,v $
+ * Revision 1.13.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
  * Revision 1.13.6.1  2000/11/28 12:02:45  kai
  * MODULE_DEVICE_TABLE for 2.4
  *
@@ -88,7 +91,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.13.6.1 $";
+static char *revision = "$Revision: 1.13.6.2 $";
 
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/divert/divert_init.c linux/drivers/isdn/divert/divert_init.c
--- v2.4.2/linux/drivers/isdn/divert/divert_init.c	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/divert/divert_init.c	Fri Mar  2 11:12:08 2001
@@ -1,5 +1,5 @@
 /* 
- * $Id: divert_init.c,v 1.5 2000/11/13 22:51:47 kai Exp $
+ * $Id: divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
  *
  * Module init for DSS1 diversion services for i4l.
  *
@@ -23,6 +23,7 @@
 
 #include <linux/module.h>
 #include <linux/version.h>
+#include <linux/init.h>
 #include "isdn_divert.h"
 
 /********************/
@@ -46,7 +47,7 @@
 /* Module interface code */
 /* no cmd line parms     */
 /*************************/
-int init_module(void)
+static int __init divert_init(void)
 { int i;
 
   if (divert_dev_init())
@@ -63,12 +64,12 @@
 #endif
   printk(KERN_INFO "dss1_divert module successfully installed\n");
   return(0);
-} /* init_module */
+}
 
 /**********************/
 /* Module deinit code */
 /**********************/
-void cleanup_module(void)
+static void __exit divert_exit(void)
 { int flags;
   int i;
 
@@ -89,6 +90,8 @@
   deleterule(-1); /* delete all rules and free mem */
   deleteprocs();
   printk(KERN_INFO "dss1_divert module successfully removed \n");
-} /* cleanup_module */
+}
 
+module_init(divert_init);
+module_exit(divert_exit);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c
--- v2.4.2/linux/drivers/isdn/divert/isdn_divert.c	Wed Feb 21 18:20:22 2001
+++ linux/drivers/isdn/divert/isdn_divert.c	Fri Mar  2 11:12:08 2001
@@ -1,5 +1,5 @@
 /* 
- * $Id: isdn_divert.c,v 1.6.6.1 2001/02/07 11:31:31 kai Exp $
+ * $Id: isdn_divert.c,v 1.6.6.2 2001/02/16 16:43:25 kai Exp $
  *
  * DSS1 main diversion supplementary handling for i4l.
  *
@@ -290,7 +290,7 @@
 /* insert a new rule before idx */
 /********************************/
 int insertrule(int idx, divert_rule *newrule)
-{ struct deflect_struc *ds,*ds1;
+{ struct deflect_struc *ds,*ds1=NULL;
   int flags;
 
   if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc), 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c
--- v2.4.2/linux/drivers/isdn/eicon/Divas_mod.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/eicon/Divas_mod.c	Fri Mar  2 11:12:08 2001
@@ -1,13 +1,6 @@
 
 /*
  *
- * Copyright (C) Eicon Technology Corporation, 2000.
- *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
- * Eicon File Revision :    1.15  
- *
  * 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)
@@ -26,6 +19,7 @@
 
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/fs.h>
 #undef N_DATA
 
@@ -40,27 +34,23 @@
 #include "adapter.h"
 #include "uxio.h"
 
+
 #ifdef MODULE
 #include "idi.h"
 void DIVA_DIDD_Write(DESCRIPTOR *, int);
 EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
 EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write);
 EXPORT_SYMBOL_NOVERS(DivasPrintf);
-#define Divas_init init_module
-#else
-#define Divas_init eicon_init
 #endif
 
-extern char *file_check(void);
-
 int DivasCardsDiscover(void);
 
-int
-Divas_init(void)
+static int __init
+divas_init(void)
 {
 	printk(KERN_DEBUG "DIVA Server Driver - initialising\n");
 	
-	printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.15 (%s)\n",file_check());
+	printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.16\n");
 
 
 #if !defined(CONFIG_PCI)
@@ -85,9 +75,8 @@
     return 0;
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void __exit
+divas_exit(void)
 {
 	card_t *pCard;
 	word wCardIndex;
@@ -156,15 +145,6 @@
 	unregister_chrdev(Divas_major, "Divas");
 }
 
-void mod_inc_use_count(void)
-{
-	MOD_INC_USE_COUNT;
-}
-
-void mod_dec_use_count(void)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-#endif
+module_init(divas_init);
+module_exit(divas_exit);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/Makefile linux/drivers/isdn/eicon/Makefile
--- v2.4.2/linux/drivers/isdn/eicon/Makefile	Fri Dec 29 14:40:54 2000
+++ linux/drivers/isdn/eicon/Makefile	Fri Mar  2 11:12:08 2001
@@ -12,10 +12,9 @@
 
 list-multi	:= eicon.o divas.o
 eicon-objs	:= eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \
-		   eicon_io.o fcheck.o
+		   eicon_io.o
 divas-objs	:= common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \
-		   fourbri.o lincfg.o linchr.o linsys.o linio.o fcheck.o \
-		   Divas_mod.o
+		   fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o
 
 # Optional parts of multipart objects.
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/adapter.h linux/drivers/isdn/eicon/adapter.h
--- v2.4.2/linux/drivers/isdn/eicon/adapter.h	Mon Dec 11 13:21:41 2000
+++ linux/drivers/isdn/eicon/adapter.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.7  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/bri.c linux/drivers/isdn/eicon/bri.c
--- v2.4.2/linux/drivers/isdn/eicon/bri.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/bri.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.8  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -63,6 +60,7 @@
 void io_inc(ADAPTER *a, void *adr);
 
 static int diva_server_bri_test_int(card_t *card);
+static int bri_ISR (card_t* card);
 
 #define PLX_IOBASE		0
 #define	DIVAS_IOBASE	1
@@ -80,7 +78,6 @@
 void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
 
 int DivasBRIInitPCI(card_t *card, dia_card_t *cfg);
-int bri_ISR (card_t* card);
 
 static
 int	diva_server_bri_reset(card_t *card)
@@ -361,7 +358,7 @@
 	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2);
 
 	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10);
-	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags);
 
 	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11);
 	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c
--- v2.4.2/linux/drivers/isdn/eicon/common.c	Wed Sep 27 13:45:40 2000
+++ linux/drivers/isdn/eicon/common.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.15  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -101,7 +98,6 @@
 	return;
 }
 
-static
 void 	DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength)
 {
         if (tablelength > sizeof(DIDD_Table))
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/constant.h linux/drivers/isdn/eicon/constant.h
--- v2.4.2/linux/drivers/isdn/eicon/constant.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/constant.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/divalog.h linux/drivers/isdn/eicon/divalog.h
--- v2.4.2/linux/drivers/isdn/eicon/divalog.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/divalog.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/divas.h linux/drivers/isdn/eicon/divas.h
--- v2.4.2/linux/drivers/isdn/eicon/divas.h	Mon Dec 11 13:21:41 2000
+++ linux/drivers/isdn/eicon/divas.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.5  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/dsp_defs.h linux/drivers/isdn/eicon/dsp_defs.h
--- v2.4.2/linux/drivers/isdn/eicon/dsp_defs.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/dsp_defs.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/dspdids.h linux/drivers/isdn/eicon/dspdids.h
--- v2.4.2/linux/drivers/isdn/eicon/dspdids.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/dspdids.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon.h linux/drivers/isdn/eicon/eicon.h
--- v2.4.2/linux/drivers/isdn/eicon/eicon.h	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/eicon/eicon.h	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.23 2000/06/21 11:28:42 armin Exp $
+/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
@@ -150,7 +150,6 @@
 
 #include <linux/isdn.h>
 #include <linux/isdnif.h>
-
 
 typedef struct {
   __u16 length __attribute__ ((packed)); /* length of data/parameter field */
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c
--- v2.4.2/linux/drivers/isdn/eicon/eicon_idi.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/eicon_idi.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.41 2000/08/12 18:00:47 armin Exp $
+/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  *        IDI interface 
@@ -36,7 +36,7 @@
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.41 $";
+char *eicon_idi_revision = "$Revision: 1.41.6.1 $";
 
 eicon_manifbuf *manbuf;
 
@@ -2506,7 +2506,7 @@
 						case ISDN_PROTO_L2_TRANS:
 							idi_do_req(ccard, chan, N_CONNECT, 1);
 							break;
-						default:
+						default:;
 							/* On most incoming calls we use automatic connect */
 							/* idi_do_req(ccard, chan, N_CONNECT, 1); */
 					}
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_io.c linux/drivers/isdn/eicon/eicon_io.c
--- v2.4.2/linux/drivers/isdn/eicon/eicon_io.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/eicon_io.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.13 2000/05/07 08:51:04 armin Exp $
+/* $Id: eicon_io.c,v 1.13.6.1 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Code for communicating with hardware.
@@ -6,7 +6,7 @@
  * Copyright 1999,2000  by Armin Schindler (mac@melware.de)
  * Copyright 1999,2000  Cytronics & Melware (info@melware.de)
  *
- * Thanks to	Eicon Technology GmbH & Co. oHG for 
+ * Thanks to	Eicon Networks for 
  *		documents, informations and hardware. 
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c
--- v2.4.2/linux/drivers/isdn/eicon/eicon_mod.c	Wed Sep 27 13:45:40 2000
+++ linux/drivers/isdn/eicon/eicon_mod.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.37 2000/09/02 11:16:47 armin Exp $
+/* $Id: eicon_mod.c,v 1.37.6.4 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  * 
@@ -6,7 +6,7 @@
  * Copyright 1998-2000 by Armin Schindler (mac@melware.de) 
  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
  * 
- * Thanks to    Eicon Technology GmbH & Co. oHG for
+ * Thanks to    Eicon Networks for
  *              documents, informations and hardware.
  *
  *		Deutsche Mailbox Saar-Lor-Lux GmbH
@@ -32,7 +32,7 @@
 
 #define DRIVERNAME "Eicon active ISDN driver"
 #define DRIVERRELEASE "2.0"
-#define DRIVERPATCH ".15"
+#define DRIVERPATCH ".16"
 
 
 #include <linux/config.h>
@@ -55,7 +55,7 @@
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.37 $";
+static char *eicon_revision = "$Revision: 1.37.6.4 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
@@ -64,9 +64,6 @@
 extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
 			unsigned int command, unsigned long arg);
 extern void eicon_pci_init_conf(eicon_card *card);
-void mod_inc_use_count(void);
-void mod_dec_use_count(void);
-extern char *file_check(void);
 
 #ifdef MODULE
 #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
@@ -377,7 +374,7 @@
 #ifdef MODULE
 				case EICON_IOCTL_FREEIT:
 					while (MOD_USE_COUNT > 0) MOD_DEC_USE_COUNT;
-					mod_inc_use_count();
+					MOD_INC_USE_COUNT;
 					return 0;
 #endif
 				case EICON_IOCTL_LOADPCI:
@@ -573,14 +570,10 @@
 			eicon_log(card, 1, "eicon CMD_GETSIL not implemented\n");
 			return 0;
 		case ISDN_CMD_LOCK:
-#ifdef MODULE
-			mod_inc_use_count();
-#endif
+			MOD_INC_USE_COUNT;
 			return 0;
 		case ISDN_CMD_UNLOCK:
-#ifdef MODULE
-			mod_dec_use_count();
-#endif
+			MOD_DEC_USE_COUNT;
 			return 0;
 #ifdef CONFIG_ISDN_TTY_FAX
 		case ISDN_CMD_FAXCMD:
@@ -1177,8 +1170,7 @@
         return 0;
 }
 
-#ifdef MODULE
-static void
+static void __exit
 unregister_card(eicon_card * card)
 {
         isdn_ctrl cmd;
@@ -1204,7 +1196,6 @@
 			break;
         }
 }
-#endif /* MODULE */
 
 static void
 eicon_freecard(eicon_card *card) {
@@ -1311,11 +1302,7 @@
 }
 
 
-#ifdef MODULE
-#define eicon_init init_module
-#endif
-
-int
+static int __init
 eicon_init(void)
 {
 	int card_count = 0;
@@ -1341,8 +1328,8 @@
 #endif
 	strcpy(tmprev, eicon_idi_revision);
 	printk("%s\n", eicon_getrev(tmprev));
-        printk(KERN_INFO "%s Release: %s%s (%s)\n", DRIVERNAME,
-		DRIVERRELEASE, DRIVERPATCH, file_check());
+        printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME,
+		DRIVERRELEASE, DRIVERPATCH);
 
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 #ifdef CONFIG_MCA
@@ -1391,19 +1378,6 @@
         return 0;
 }
 
-
-#ifdef MODULE
-
-void mod_inc_use_count(void)
-{
-        MOD_INC_USE_COUNT;
-}
-
-void mod_dec_use_count(void)
-{
-        MOD_DEC_USE_COUNT;
-}
-
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
 void DIVA_DIDD_Write(DESCRIPTOR *, int);
 EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
@@ -1414,8 +1388,8 @@
 card_t DivasCards[1];
 #endif
 
-void
-cleanup_module(void)
+static void __exit
+eicon_exit(void)
 {
 #if CONFIG_PCI	
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
@@ -1499,7 +1473,7 @@
         printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
 }
 
-#else /* no module */
+#ifndef MODULE
 
 static int __init
 eicon_setup(char *line)
@@ -1712,3 +1686,5 @@
 #endif /* CONFIG_MCA */
 #endif /* CONFIG_ISDN_DRV_EICON_ISA */
 
+module_init(eicon_init);
+module_exit(eicon_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/eicon_pci.c linux/drivers/isdn/eicon/eicon_pci.c
--- v2.4.2/linux/drivers/isdn/eicon/eicon_pci.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/eicon_pci.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.15 2000/06/12 12:44:02 armin Exp $
+/* $Id: eicon_pci.c,v 1.15.6.2 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for PCI cards.
@@ -6,7 +6,7 @@
  * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
  *
- * Thanks to	Eicon Technology GmbH & Co. oHG for 
+ * Thanks to	Eicon Networks for 
  *		documents, informations and hardware. 
  *
  * This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@
 #include "adapter.h"
 #include "uxio.h"
 
-char *eicon_pci_revision = "$Revision: 1.15 $";
+char *eicon_pci_revision = "$Revision: 1.15.6.2 $";
 
 #if CONFIG_PCI	         /* intire stuff is only for PCI */
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
@@ -86,7 +86,7 @@
 				printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n",
 					eicon_ctype_name[ctype], did, card_id);
 			}
-err:
+err:;
 		}
 		pCard++;
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/fcheck.c linux/drivers/isdn/eicon/fcheck.c
--- v2.4.2/linux/drivers/isdn/eicon/fcheck.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/fcheck.c	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/* $Id: fcheck.c,v 1.3 2000/06/12 12:44:02 armin Exp $
- * 
- * (c) 2000 Cytronics & Melware
- *
- *  This file is (c) under GNU PUBLIC LICENSE
- *  For changes and modifications please read
- *  ../../../Documentation/isdn/README.eicon
- *
- *
- */
- 
-#include <linux/kernel.h>
-
-char *
-file_check(void) {
-
-#ifdef FILECHECK
-#if FILECHECK == 0
-	return("verified");
-#endif
-#if FILECHECK == 1 
-	return("modified");
-#endif
-#if FILECHECK == 127 
-	return("verification failed");
-#endif
-#else
-	return("not verified");
-#endif
-}
-
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/fourbri.c linux/drivers/isdn/eicon/fourbri.c
--- v2.4.2/linux/drivers/isdn/eicon/fourbri.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/fourbri.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.7  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -67,7 +64,7 @@
 void mem_inc(ADAPTER *a, void *adr);
 
 int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg);
-int fourbri_ISR (card_t* card);
+static int fourbri_ISR (card_t* card);
 
 int FPGA_Download(word, dword, byte *, byte *, int);
 extern byte FPGA_Bytes[];
@@ -113,7 +110,7 @@
 
 	UxCardMemOut(card->hw, &shared[ 8], config->tei);
 	UxCardMemOut(card->hw, &shared[ 9], config->nt2);
-	UxCardMemOut(card->hw, &shared[10], 0);
+	UxCardMemOut(card->hw, &shared[10], config->sig_flags);
 	UxCardMemOut(card->hw, &shared[11], config->watchdog);
 	UxCardMemOut(card->hw, &shared[12], config->permanent);
 	UxCardMemOut(card->hw, &shared[13], config->x_interface);
@@ -561,23 +558,16 @@
 }*/
 
 
-int fourbri_ISR (card_t* card) 
+static int fourbri_ISR (card_t* card) 
 {
-	int served = 0;
 	byte *ctl;
-	byte *reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
 
-	if (UxCardPortIoIn(card->hw, reg, PLX9054_INTCSR) & 0x80) 
-	{
-		served = 1;
-		card->int_pend  += 1;
-		DivasDpcSchedule(); /* ISR DPC */
+	card->int_pend  += 1;
+	DivasDpcSchedule(); /* ISR DPC */
 
-		ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
-		UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
-		UxCardMemDetach(card->hw, ctl);
-	}
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+	UxCardMemDetach(card->hw, ctl);
 
-	UxCardMemDetach(card->hw, reg);
-	return (served != 0);
+	return (1);
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/fpga.c linux/drivers/isdn/eicon/fpga.c
--- v2.4.2/linux/drivers/isdn/eicon/fpga.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/fpga.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.2  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/idi.c linux/drivers/isdn/eicon/idi.c
--- v2.4.2/linux/drivers/isdn/eicon/idi.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/idi.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.8  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -248,13 +245,13 @@
 /*
  * IDI request function for active cards
  */
-
 static
 void	request(card_t *card, ENTITY *e)
 {
 	word	*special_req;
 	int		i;
 	int		ipl;
+
 
 	if (card->log_types & DIVAS_LOG_IDI)
 	{
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/idi.h linux/drivers/isdn/eicon/idi.h
--- v2.4.2/linux/drivers/isdn/eicon/idi.h	Mon Dec 11 13:21:41 2000
+++ linux/drivers/isdn/eicon/idi.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -65,7 +62,7 @@
 struct postcall_s {
   word        command;         /* command = 0x0300 */
   word        dummy;           /* not used */
-  IDI_CALL    callback;        /* routine adress to call back */
+  IDI_CALL    callback;        /* routine address to call back */
   ENTITY      *contxt;         /* ptr to entity to use */
 };
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/kprintf.c linux/drivers/isdn/eicon/kprintf.c
--- v2.4.2/linux/drivers/isdn/eicon/kprintf.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/kprintf.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.3  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/lincfg.c linux/drivers/isdn/eicon/lincfg.c
--- v2.4.2/linux/drivers/isdn/eicon/lincfg.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/lincfg.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.9  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c
--- v2.4.2/linux/drivers/isdn/eicon/linchr.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/eicon/linchr.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.12  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -24,6 +21,8 @@
  *
  */
 
+#define __NO_VERSION__
+#include <linux/module.h>
 
 #include <linux/kernel.h>
 #include <linux/poll.h>
@@ -240,14 +239,12 @@
 
 	return 0;
 }
-int private_usage_count;
-extern void mod_inc_use_count(void);
-extern void mod_dec_use_count(void);
+static int private_usage_count;
 
 int do_open(struct inode *pInode, struct file *pFile)
 {
-#if defined(MODULE)
-	mod_inc_use_count();
+	MOD_INC_USE_COUNT;
+#ifdef MODULE
 	private_usage_count++;
 #endif
 	return 0;
@@ -255,8 +252,8 @@
 
 int do_release(struct inode *pInode, struct file *pFile)
 {
-#if defined(MODULE)
-	mod_dec_use_count();
+	MOD_DEC_USE_COUNT;
+#ifdef MODULE
 	private_usage_count--;
 #endif
 	return 0;
@@ -267,8 +264,6 @@
 	while (private_usage_count > 0)
 	{
 		private_usage_count--;
-#if defined(MODULE)
-		mod_dec_use_count();
-#endif
+		MOD_DEC_USE_COUNT;
 	}
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/linio.c linux/drivers/isdn/eicon/linio.c
--- v2.4.2/linux/drivers/isdn/eicon/linio.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/eicon/linio.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.16  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/linsys.c linux/drivers/isdn/eicon/linsys.c
--- v2.4.2/linux/drivers/isdn/eicon/linsys.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/linsys.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.10  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/log.c linux/drivers/isdn/eicon/log.c
--- v2.4.2/linux/drivers/isdn/eicon/log.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/log.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.5  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/md5sums.asc linux/drivers/isdn/eicon/md5sums.asc
--- v2.4.2/linux/drivers/isdn/eicon/md5sums.asc	Wed Sep 27 13:45:40 2000
+++ linux/drivers/isdn/eicon/md5sums.asc	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-# These are valid md5sums to detect modifications
-# in eicon driver files provided by Eicon Technology.
-# For changes and modifications in these files please
-# read ../../../Documentation/isdn/README.eicon
-# 
-34bfe8d08d337a97c699ac8326f1d9b6  common.c
-dbb92cba52db31ff8325a252b3f595c3  idi.c
-15687687ef82f099966ed42772001cd3  bri.c
-c3e3b720c3351b66635bd548195e29e8  pri.c
-b0a6d2ab49bcfcfd1825860f178a84b4  log.c
-673746176316b72271a09c0a27287a01  xlog.c
-07e1bbabdb4d69880db196ef31bfb241  kprintf.c
-b60b40ad630f26b7923369df95b4d1b9  fpga.c
-5013ecca0a38a8fcc4a61642754f2076  fourbri.c
-1501ae468a0c5eaab1e60720fa723a67  fcheck.c
-# end of md5sums
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pc.h linux/drivers/isdn/eicon/pc.h
--- v2.4.2/linux/drivers/isdn/eicon/pc.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/pc.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.2  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pc_maint.h linux/drivers/isdn/eicon/pc_maint.h
--- v2.4.2/linux/drivers/isdn/eicon/pc_maint.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/pc_maint.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pr_pc.h linux/drivers/isdn/eicon/pr_pc.h
--- v2.4.2/linux/drivers/isdn/eicon/pr_pc.h	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/pr_pc.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.0  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/pri.c linux/drivers/isdn/eicon/pri.c
--- v2.4.2/linux/drivers/isdn/eicon/pri.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/pri.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.5  
  *
  * This program is free software; you can redistribute it and/or modify
@@ -82,7 +79,7 @@
 void mem_inc(ADAPTER *a, void *adr);
 
 int DivasPRIInitPCI(card_t *card, dia_card_t *cfg);
-int pri_ISR (card_t* card);
+static int pri_ISR (card_t* card);
 
 static int diva_server_reset(card_t *card)
 {
@@ -156,7 +153,7 @@
 
 	UxCardMemOut(card->hw, &shared[ 8], config->tei);
 	UxCardMemOut(card->hw, &shared[ 9], config->nt2);
-	UxCardMemOut(card->hw, &shared[10], 0);
+	UxCardMemOut(card->hw, &shared[10], config->sig_flags);
 	UxCardMemOut(card->hw, &shared[11], config->watchdog);
 	UxCardMemOut(card->hw, &shared[12], config->permanent);
 	UxCardMemOut(card->hw, &shared[13], config->x_interface);
@@ -509,7 +506,7 @@
 }
 
 
-int pri_ISR (card_t* card) 
+static int pri_ISR (card_t* card) 
 {
 	int served = 0;
 	byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/sys.h linux/drivers/isdn/eicon/sys.h
--- v2.4.2/linux/drivers/isdn/eicon/sys.h	Mon Dec 11 13:21:41 2000
+++ linux/drivers/isdn/eicon/sys.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.2  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/uxio.h linux/drivers/isdn/eicon/uxio.h
--- v2.4.2/linux/drivers/isdn/eicon/uxio.h	Mon Dec 11 13:21:41 2000
+++ linux/drivers/isdn/eicon/uxio.h	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.6  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/eicon/xlog.c linux/drivers/isdn/eicon/xlog.c
--- v2.4.2/linux/drivers/isdn/eicon/xlog.c	Sun Aug 13 10:05:32 2000
+++ linux/drivers/isdn/eicon/xlog.c	Fri Mar  2 11:12:08 2001
@@ -3,9 +3,6 @@
  *
  * Copyright (C) Eicon Technology Corporation, 2000.
  *
- * This source file is supplied for the exclusive use with Eicon
- * Technology Corporation's range of DIVA Server Adapters.
- *
  * Eicon File Revision :    1.2  
  *
  * This program is free software; you can redistribute it and/or modify
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- v2.4.2/linux/drivers/isdn/hisax/Makefile	Sat Feb  3 19:51:27 2001
+++ linux/drivers/isdn/hisax/Makefile	Fri Mar  2 11:12:08 2001
@@ -34,6 +34,7 @@
 hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
 hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o
+hisax-objs-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
 hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c
--- v2.4.2/linux/drivers/isdn/hisax/amd7930.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/amd7930.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: amd7930.c,v 1.5 2000/11/24 17:05:37 kai Exp $
+/* $Id: amd7930.c,v 1.5.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * HiSax ISDN driver - chip specific routines for AMD 7930
  *
@@ -14,7 +14,7 @@
  *
  * The code is unreliable enough to be consider alpha
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
  * SparcStation 1+.  The chip provides microphone and speaker interfaces
@@ -94,7 +94,7 @@
 #include "rawhdlc.h"
 #include <linux/interrupt.h>
 
-static const char *amd7930_revision = "$Revision: 1.5 $";
+static const char *amd7930_revision = "$Revision: 1.5.6.1 $";
 
 #define RCV_BUFSIZE	1024	/* Size of raw receive buffer in bytes */
 #define RCV_BUFBLKS	4	/* Number of blocks to divide buffer into
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c
--- v2.4.2/linux/drivers/isdn/hisax/arcofi.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/arcofi.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: arcofi.c,v 1.12 2000/11/25 17:01:00 kai Exp $
+/* $Id: arcofi.c,v 1.12.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * arcofi.c   Ansteuerung ARCOFI 2165
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
  
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/arcofi.h linux/drivers/isdn/hisax/arcofi.h
--- v2.4.2/linux/drivers/isdn/hisax/arcofi.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/arcofi.h	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: arcofi.h,v 1.6 2000/06/26 08:59:12 keil Exp $
+/* $Id: arcofi.h,v 1.6.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * arcofi.h   Ansteuerung ARCOFI 2165
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
  
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c
--- v2.4.2/linux/drivers/isdn/hisax/asuscom.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/asuscom.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: asuscom.c,v 1.11 2000/11/24 17:05:37 kai Exp $
+/* $Id: asuscom.c,v 1.11.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * asuscom.c     low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
  *
@@ -6,7 +6,7 @@
  *
  * Thanks to  ASUSCOM NETWORK INC. Taiwan and  Dynalink NL for informations
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -20,7 +20,7 @@
 
 extern const char *CardType[];
 
-const char *Asuscom_revision = "$Revision: 1.11 $";
+const char *Asuscom_revision = "$Revision: 1.11.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- v2.4.2/linux/drivers/isdn/hisax/avm_a1.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/avm_a1.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: avm_a1.c,v 2.13 2000/11/24 17:05:37 kai Exp $
+/* $Id: avm_a1.c,v 2.13.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -15,7 +15,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static const char *avm_revision = "$Revision: 2.13 $";
+static const char *avm_revision = "$Revision: 2.13.6.1 $";
 
 #define	 AVM_A1_STAT_ISAC	0x01
 #define	 AVM_A1_STAT_HSCX	0x02
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c
--- v2.4.2/linux/drivers/isdn/hisax/avm_a1p.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/avm_a1p.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: avm_a1p.c,v 2.7 2000/11/24 17:05:37 kai Exp $
+/* $Id: avm_a1p.c,v 2.7.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * avm_a1p.c    low level stuff for the following AVM cards:
  *              A1 PCMCIA
@@ -7,7 +7,7 @@
  *
  * Author       Carsten Paeth (calle@calle.in-berlin.de)
  *
- *  This file is (c) under GNU PUBLIC LICENSE
+ *  This file is (c) under GNU General Public License
  */
 #define __NO_VERSION__
 #include <linux/init.h>
@@ -53,7 +53,7 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static const char *avm_revision = "$Revision: 2.7 $";
+static const char *avm_revision = "$Revision: 2.7.6.1 $";
 
 static inline u_char
 ReadISAC(struct IsdnCardState *cs, u_char offset)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c
--- v2.4.2/linux/drivers/isdn/hisax/avm_pci.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/avm_pci.c	Fri Mar  2 11:12:08 2001
@@ -1,11 +1,11 @@
-/* $Id: avm_pci.c,v 1.22.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: avm_pci.c,v 1.22.6.4 2001/02/16 16:43:25 kai Exp $
  *
  * avm_pci.c    low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
  *              Thanks to AVM, Berlin for informations
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -18,7 +18,7 @@
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.22.6.2 $";
+static const char *avm_pci_rev = "$Revision: 1.22.6.4 $";
 
 #define  AVM_FRITZ_PCI		1
 #define  AVM_FRITZ_PNP		2
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c
--- v2.4.2/linux/drivers/isdn/hisax/bkm_a4t.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/bkm_a4t.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a4t.c,v 1.13.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: bkm_a4t.c,v 1.13.6.4 2001/02/16 16:43:25 kai Exp $
  * bkm_a4t.c    low level stuff for T-Berkom A4T
  *              derived from the original file sedlbauer.c
  *              derived from the original file niccy.c
@@ -6,7 +6,7 @@
  *
  * Author       Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -24,7 +24,7 @@
 
 extern const char *CardType[];
 
-const char *bkm_a4t_revision = "$Revision: 1.13.6.2 $";
+const char *bkm_a4t_revision = "$Revision: 1.13.6.4 $";
 
 
 static inline u_char
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c
--- v2.4.2/linux/drivers/isdn/hisax/bkm_a8.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/bkm_a8.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.14.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: bkm_a8.c,v 1.14.6.4 2001/02/16 16:43:25 kai Exp $
  * bkm_a8.c     low level stuff for Scitel Quadro (4*S0, passive)
  *              derived from the original file sedlbauer.c
  *              derived from the original file niccy.c
@@ -6,7 +6,7 @@
  *
  * Author       Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -27,7 +27,7 @@
 
 extern const char *CardType[];
 
-const char sct_quadro_revision[] = "$Revision: 1.14.6.2 $";
+const char sct_quadro_revision[] = "$Revision: 1.14.6.4 $";
 
 static const char *sct_quadro_subtypes[] =
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/bkm_ax.h linux/drivers/isdn/hisax/bkm_ax.h
--- v2.4.2/linux/drivers/isdn/hisax/bkm_ax.h	Tue Nov 28 21:44:41 2000
+++ linux/drivers/isdn/hisax/bkm_ax.h	Fri Mar  2 18:38:37 2001
@@ -1,9 +1,9 @@
-/* $Id: bkm_ax.h,v 1.5.6.1 2000/11/28 12:02:46 kai Exp $
+/* $Id: bkm_ax.h,v 1.5.6.2 2001/02/16 16:43:25 kai Exp $
  * bkm_ax.h   low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
  *
  * Author     Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- v2.4.2/linux/drivers/isdn/hisax/callc.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/callc.c	Fri Mar  2 11:12:08 2001
@@ -1,9 +1,9 @@
-/* $Id: callc.c,v 2.51 2000/11/24 17:05:37 kai Exp $
+/* $Id: callc.c,v 2.51.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -20,7 +20,7 @@
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif	/* MODULE */
 
-const char *lli_revision = "$Revision: 2.51 $";
+const char *lli_revision = "$Revision: 2.51.6.1 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -337,7 +337,7 @@
  * RESUME
  */
 
-/* incomming call */
+/* incoming call */
 
 static void
 lli_deliver_call(struct FsmInst *fi, int event, void *arg)
@@ -1026,9 +1026,11 @@
 	printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg);
 }
 
-static void
+static int
 init_PStack(struct PStack **stp) {
 	*stp = kmalloc(sizeof(struct PStack), GFP_ATOMIC);
+	if (!*stp)
+		return -ENOMEM;
 	(*stp)->next = NULL;
 	(*stp)->l1.l1l2 = dummy_pstack;
 	(*stp)->l1.l1hw = dummy_pstack;
@@ -1041,16 +1043,20 @@
 	(*stp)->l3.l3l4 = dummy_pstack;
 	(*stp)->lli.l4l3 = dummy_pstack;
 	(*stp)->ma.layer = dummy_pstack;
+	return 0;
 }
 
-static void
+static int
 init_d_st(struct Channel *chanp)
 {
 	struct PStack *st;
 	struct IsdnCardState *cs = chanp->cs;
 	char tmp[16];
+	int err;
 
-	init_PStack(&chanp->d_st);
+	err = init_PStack(&chanp->d_st);
+	if (err)
+		return err;
 	st = chanp->d_st;
 	st->next = NULL;
 	HiSax_addlist(cs, st);
@@ -1075,6 +1081,8 @@
 	st->lli.userdata = chanp;
 	st->lli.l2writewakeup = NULL;
 	st->l3.l3l4 = dchan_l3l4;
+
+	return 0;
 }
 
 static void
@@ -1090,10 +1098,11 @@
 	va_end(args);
 }
 
-static void
+static int
 init_chan(int chan, struct IsdnCardState *csta)
 {
 	struct Channel *chanp = csta->channel + chan;
+	int err;
 
 	chanp->cs = csta;
 	chanp->bcs = csta->bcs + chan;
@@ -1102,7 +1111,9 @@
 	chanp->debug = 0;
 	chanp->Flags = 0;
 	chanp->leased = 0;
-	init_PStack(&chanp->b_st);
+	err = init_PStack(&chanp->b_st);
+	if (err)
+		return err;
 	chanp->b_st->l1.delay = DEFAULT_B_DELAY;
 	chanp->fi.fsm = &callcfsm;
 	chanp->fi.state = ST_NULL;
@@ -1112,31 +1123,41 @@
 	FsmInitTimer(&chanp->fi, &chanp->dial_timer);
 	FsmInitTimer(&chanp->fi, &chanp->drel_timer);
 	if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) {
-		init_d_st(chanp);
+		err = init_d_st(chanp);
+		if (err)
+			return err;
 	} else {
 		chanp->d_st = csta->channel->d_st;
 	}
 	chanp->data_open = 0;
+	return 0;
 }
 
 int
 CallcNewChan(struct IsdnCardState *csta) {
-	int i;
+	int i, err;
 
 	chancount += 2;
-	init_chan(0, csta);
-	init_chan(1, csta);
+	err = init_chan(0, csta);
+	if (err)
+		return err;
+	err = init_chan(1, csta);
+	if (err)
+		return err;
 	printk(KERN_INFO "HiSax: 2 channels added\n");
 
-	for (i = 0; i < MAX_WAITING_CALLS; i++) 
-		init_chan(i+2,csta);
+	for (i = 0; i < MAX_WAITING_CALLS; i++) { 
+		err = init_chan(i+2,csta);
+		if (err)
+			return err;
+	}
 	printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n");
 	if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) {
 		printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n");
 		csta->channel->d_st->lli.l4l3(csta->channel->d_st,
 			DL_ESTABLISH | REQUEST, NULL);
 	}
-	return (2);
+	return (0);
 }
 
 static void
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c
--- v2.4.2/linux/drivers/isdn/hisax/cert.c	Mon Aug 21 07:49:02 2000
+++ linux/drivers/isdn/hisax/cert.c	Fri Mar  2 11:12:08 2001
@@ -1,8 +1,8 @@
-/* $Id: cert.c,v 2.3 2000/06/26 08:59:12 keil Exp $
+/* $Id: cert.c,v 2.3.6.1 2001/02/16 16:43:25 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.4.2/linux/drivers/isdn/hisax/config.c	Sat Feb  3 19:51:27 2001
+++ linux/drivers/isdn/hisax/config.c	Fri Mar  2 11:12:08 2001
@@ -1,9 +1,9 @@
-/* $Id: config.c,v 2.57.6.6 2000/12/10 23:39:19 kai Exp $
+/* $Id: config.c,v 2.57.6.10 2001/02/16 16:43:25 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #include <linux/types.h>
@@ -11,7 +11,6 @@
 #include <linux/timer.h>
 #include <linux/config.h>
 #include <linux/init.h>
-#include <linux/pci.h>
 #include "hisax.h"
 #include <linux/module.h>
 #include <linux/kernel_stat.h>
@@ -1195,7 +1194,12 @@
 		return (0);
 	}
 	init_tei(cs, cs->protocol);
-	CallcNewChan(cs);
+	ret = CallcNewChan(cs);
+	if (ret) {
+		closecard(cardnr);
+		restore_flags(flags);
+		return 0;
+	}
 	/* ISAR needs firmware download first */
 	if (!test_bit(HW_ISAR, &cs->HW_Flags))
 		ll_run(cs, 0);
@@ -1326,8 +1330,7 @@
 #endif
 }
 
-int __init
-HiSax_init(void)
+static int __init HiSax_init(void)
 {
 	int i,j;
 	int nzproto = 0;
@@ -1497,11 +1500,7 @@
 	}
 }
 
-#ifdef MODULE
-int init_module(void) { return HiSax_init(); }
-
-void
-cleanup_module(void)
+static void __exit HiSax_exit(void)
 {
 	int cardnr = nrcards -1;
 	long flags;
@@ -1518,7 +1517,6 @@
 	restore_flags(flags);
 	printk(KERN_INFO "HiSax module removed\n");
 }
-#endif
 
 #ifdef CONFIG_HISAX_ELSA
 int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
@@ -1707,6 +1705,8 @@
 	return (ret);
 }
 
+#include <linux/pci.h>
+
 static struct pci_device_id hisax_pci_tbl[] __initdata = {
 #ifdef CONFIG_HISAX_FRITZPCI
 	{PCI_VENDOR_ID_AVM,      PCI_DEVICE_ID_AVM_A1,          PCI_ANY_ID, PCI_ANY_ID},
@@ -1770,3 +1770,6 @@
 };
 
 MODULE_DEVICE_TABLE(pci, hisax_pci_tbl);
+
+module_init(HiSax_init);
+module_exit(HiSax_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- v2.4.2/linux/drivers/isdn/hisax/diva.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/diva.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: diva.c,v 1.25.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: diva.c,v 1.25.6.4 2001/02/16 16:43:25 kai Exp $
  *
  * diva.c     low level stuff for Eicon.Diehl Diva Family ISDN cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -24,7 +24,7 @@
 
 extern const char *CardType[];
 
-const char *Diva_revision = "$Revision: 1.25.6.2 $";
+const char *Diva_revision = "$Revision: 1.25.6.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- v2.4.2/linux/drivers/isdn/hisax/elsa.c	Tue Nov 28 21:44:41 2000
+++ linux/drivers/isdn/hisax/elsa.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: elsa.c,v 2.26.6.1 2000/11/28 12:02:46 kai Exp $
+/* $Id: elsa.c,v 2.26.6.3 2001/02/16 16:43:25 kai Exp $
  *
  * elsa.c     low level stuff for Elsa isdn cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -30,7 +30,7 @@
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 2.26.6.1 $";
+const char *Elsa_revision = "$Revision: 2.26.6.3 $";
 const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
  "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c
--- v2.4.2/linux/drivers/isdn/hisax/elsa_ser.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/elsa_ser.c	Fri Mar  2 11:12:08 2001
@@ -1,8 +1,8 @@
-/* $Id: elsa_ser.c,v 2.10 2000/11/19 17:02:47 kai Exp $
+/* $Id: elsa_ser.c,v 2.10.6.1 2001/02/16 16:43:26 kai Exp $
  *
  * stuff for the serial modem on ELSA cards
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #include <linux/config.h>
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c
--- v2.4.2/linux/drivers/isdn/hisax/fsm.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/fsm.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: fsm.c,v 1.14 2000/11/24 17:05:37 kai Exp $
+/* $Id: fsm.c,v 1.14.6.1 2001/02/16 16:43:26 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
@@ -6,7 +6,7 @@
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c
--- v2.4.2/linux/drivers/isdn/hisax/gazel.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/gazel.c	Fri Mar  2 11:12:08 2001
@@ -1,11 +1,11 @@
-/* $Id: gazel.c,v 2.11.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: gazel.c,v 2.11.6.4 2001/02/16 16:43:26 kai Exp $
  *
  * gazel.c     low level stuff for Gazel isdn cards
  *
  * Author       BeWan Systems
  *              based on source code from Karsten Keil
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #include <linux/config.h>
@@ -19,7 +19,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.11.6.2 $";
+const char *gazel_revision = "$Revision: 2.11.6.4 $";
 
 #define R647      1
 #define R685      2
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hfc_2bds0.c,v 1.15 2000/11/24 17:05:37 kai Exp $
+/* $Id: hfc_2bds0.c,v 1.15.6.1 2001/02/16 16:43:26 kai Exp $
  *
  *  specific routines for CCD's HFC 2BDS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.h linux/drivers/isdn/hisax/hfc_2bds0.h
--- v2.4.2/linux/drivers/isdn/hisax/hfc_2bds0.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/hfc_2bds0.h	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hfc_2bds0.h,v 1.4 2000/06/26 08:59:12 keil Exp $
+/* $Id: hfc_2bds0.h,v 1.4.6.1 2001/02/16 16:43:27 kai Exp $
  *
  *  specific defines for CCD's HFC 2BDS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c
--- v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/hfc_2bs0.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hfc_2bs0.c,v 1.17 2000/11/24 17:05:37 kai Exp $
+/* $Id: hfc_2bs0.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $
  *
  *  specific routines for CCD's HFC 2BS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.h linux/drivers/isdn/hisax/hfc_2bs0.h
--- v2.4.2/linux/drivers/isdn/hisax/hfc_2bs0.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/hfc_2bs0.h	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hfc_2bs0.h,v 1.3 2000/06/26 08:59:13 keil Exp $
+/* $Id: hfc_2bs0.h,v 1.3.6.1 2001/02/16 16:43:27 kai Exp $
  *
  *  specific defines for CCD's HFC 2BS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- v2.4.2/linux/drivers/isdn/hisax/hfc_pci.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/isdn/hisax/hfc_pci.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.34.6.3 2000/12/10 23:39:19 kai Exp $
+/* $Id: hfc_pci.c,v 1.34.6.4 2001/02/13 10:33:58 kai Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
@@ -35,7 +35,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.34.6.3 $";
+static const char *hfcpci_revision = "$Revision: 1.34.6.4 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c
--- v2.4.2/linux/drivers/isdn/hisax/hfcscard.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/hfcscard.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hfcscard.c,v 1.8 2000/11/24 17:05:37 kai Exp $
+/* $Id: hfcscard.c,v 1.8.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * hfcscard.c     low level stuff for hfcs based cards (Teles3c, ACER P10)
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -16,7 +16,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcs_revision = "$Revision: 1.8 $";
+static const char *hfcs_revision = "$Revision: 1.8.6.1 $";
 
 static void
 hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.4.2/linux/drivers/isdn/hisax/hisax.h	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/hisax/hisax.h	Fri Mar  2 11:12:08 2001
@@ -1,8 +1,8 @@
-/* $Id: hisax.h,v 2.52.6.1 2000/12/06 16:59:19 kai Exp $
+/* $Id: hisax.h,v 2.52.6.3 2001/02/16 16:43:27 kai Exp $
  *
  *   Basic declarations, defines and prototypes
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #include <linux/config.h>
@@ -126,13 +126,13 @@
   #define l3dss1_process
   #include "l3dss1.h" 
   #undef  l3dss1_process
-#endif CONFIG_HISAX_EURO
+#endif /* CONFIG_HISAX_EURO */
 
 #ifdef CONFIG_HISAX_NI1
   #define l3ni1_process
   #include "l3ni1.h" 
   #undef  l3ni1_process
-#endif CONFIG_HISAX_NI1
+#endif /* CONFIG_HISAX_NI1 */
 
 #define MAX_DFRAME_LEN	260
 #define MAX_DFRAME_LEN_L1	300
@@ -318,10 +318,10 @@
 	 { u_char uuuu; /* only as dummy */
 #ifdef CONFIG_HISAX_EURO
            dss1_stk_priv dss1; /* private dss1 data */
-#endif CONFIG_HISAX_EURO              
+#endif /* CONFIG_HISAX_EURO */              
 #ifdef CONFIG_HISAX_NI1
            ni1_stk_priv ni1; /* private ni1 data */
-#endif CONFIG_HISAX_NI1              
+#endif /* CONFIG_HISAX_NI1 */             
 	 } prot;
 };
 
@@ -342,10 +342,10 @@
 	 { u_char uuuu; /* only when euro not defined, avoiding empty union */
 #ifdef CONFIG_HISAX_EURO 
            dss1_proc_priv dss1; /* private dss1 data */
-#endif CONFIG_HISAX_EURO            
+#endif /* CONFIG_HISAX_EURO */            
 #ifdef CONFIG_HISAX_NI1
            ni1_proc_priv ni1; /* private ni1 data */
-#endif CONFIG_HISAX_NI1              
+#endif /* CONFIG_HISAX_NI1 */             
 	 } prot;
 };
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c
--- v2.4.2/linux/drivers/isdn/hisax/hscx.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/hscx.c	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hscx.c,v 1.21 2000/11/24 17:05:37 kai Exp $
+/* $Id: hscx.c,v 1.21.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * hscx.c   HSCX specific routines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hscx.h linux/drivers/isdn/hisax/hscx.h
--- v2.4.2/linux/drivers/isdn/hisax/hscx.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/hscx.h	Fri Mar  2 11:12:08 2001
@@ -1,10 +1,10 @@
-/* $Id: hscx.h,v 1.6 2000/06/26 08:59:13 keil Exp $
+/* $Id: hscx.h,v 1.6.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * hscx.h   HSCX specific defines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c
--- v2.4.2/linux/drivers/isdn/hisax/hscx_irq.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/hscx_irq.c	Fri Mar  2 11:12:08 2001
@@ -1,4 +1,4 @@
-/* $Id: hscx_irq.c,v 1.16 2000/11/19 17:02:47 kai Exp $
+/* $Id: hscx_irq.c,v 1.16.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * hscx_irq.c     low level b-channel stuff for Siemens HSCX
  *
@@ -6,7 +6,7 @@
  *
  * This is an include file for fast inline IRQ stuff
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c
--- v2.4.2/linux/drivers/isdn/hisax/icc.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/icc.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-// $Id: icc.c,v 1.5 2000/11/24 17:05:37 kai Exp $
+// $Id: icc.c,v 1.5.6.1 2001/02/16 16:43:27 kai Exp $
 //-----------------------------------------------------------------------------
 //
 // ICC specific routines
@@ -7,10 +7,10 @@
 //              www.traverse.com.au
 //
 // 1999.6.25 Initial implementation of routines for Siemens ISDN
-// Communication Controler PEB 2070 based on the ISAC routines
+// Communication Controller PEB 2070 based on the ISAC routines
 // written by Karsten Keil.
 //
-// This file is (c) under GNU PUBLIC LICENSE
+// This file is (c) under GNU General Public License
 //
 //-----------------------------------------------------------------------------
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/icc.h linux/drivers/isdn/hisax/icc.h
--- v2.4.2/linux/drivers/isdn/hisax/icc.h	Mon Aug 21 07:49:03 2000
+++ linux/drivers/isdn/hisax/icc.h	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $
+// $Id: icc.h,v 1.2.6.1 2001/02/16 16:43:27 kai Exp $
 //-----------------------------------------------------------------------------
 //
 // ICC specific routines
@@ -7,10 +7,10 @@
 //              www.traverse.com.au
 //
 // 1999.7.14 Initial implementation of routines for Siemens ISDN 
-// Communication Controler PEB 2070 based on the ISAC routines 
+// Communication Controller PEB 2070 based on the ISAC routines 
 // written by Karsten Keil.
 //
-// This file is (c) under GNU PUBLIC LICENSE
+// This file is (c) under GNU General Public License
 //
 //-----------------------------------------------------------------------------
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/ipac.h linux/drivers/isdn/hisax/ipac.h
--- v2.4.2/linux/drivers/isdn/hisax/ipac.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/ipac.h	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: ipac.h,v 1.5 2000/06/26 08:59:13 keil Exp $
+/* $Id: ipac.h,v 1.5.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * ipac.h   IPAC specific defines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c
--- v2.4.2/linux/drivers/isdn/hisax/isac.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/isac.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: isac.c,v 1.28 2000/11/24 17:05:37 kai Exp $
+/* $Id: isac.c,v 1.28.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * isac.c   ISAC specific routines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  */
@@ -445,7 +445,7 @@
 				if (cs->debug & L1_DEB_MONITOR)
 					debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp -1]);
 			}
-		      AfterMOX1:
+		      AfterMOX1:;
 #endif
 		}
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isac.h linux/drivers/isdn/hisax/isac.h
--- v2.4.2/linux/drivers/isdn/hisax/isac.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/isac.h	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: isac.h,v 1.7 2000/06/26 08:59:13 keil Exp $
+/* $Id: isac.h,v 1.7.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * isac.h   ISAC specific defines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- v2.4.2/linux/drivers/isdn/hisax/isar.c	Mon Nov 27 16:56:09 2000
+++ linux/drivers/isdn/hisax/isar.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: isar.c,v 1.17 2000/11/24 17:05:37 kai Exp $
+/* $Id: isar.c,v 1.17.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isar.h linux/drivers/isdn/hisax/isar.h
--- v2.4.2/linux/drivers/isdn/hisax/isar.h	Mon Aug 21 07:49:03 2000
+++ linux/drivers/isdn/hisax/isar.h	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: isar.h,v 1.9 2000/06/26 08:59:13 keil Exp $
+/* $Id: isar.h,v 1.9.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * isar.h   ISAR (Siemens PSB 7110) specific defines
  *
  * Author Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
  
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- v2.4.2/linux/drivers/isdn/hisax/isdnl1.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/isdn/hisax/isdnl1.c	Fri Mar  2 11:12:09 2001
@@ -1,11 +1,11 @@
-/* $Id: isdnl1.c,v 2.41.6.1 2000/12/10 22:01:04 kai Exp $
+/* $Id: isdnl1.c,v 2.41.6.2 2001/02/16 16:43:27 kai Exp $
  *
  * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
  *              based on the teles driver from Jan den Ouden
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -15,7 +15,7 @@
  *
  */
 
-const char *l1_revision = "$Revision: 2.41.6.1 $";
+const char *l1_revision = "$Revision: 2.41.6.2 $";
 
 #define __NO_VERSION__
 #include <linux/init.h>
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl1.h linux/drivers/isdn/hisax/isdnl1.h
--- v2.4.2/linux/drivers/isdn/hisax/isdnl1.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/isdnl1.h	Fri Mar  2 11:12:09 2001
@@ -1,8 +1,8 @@
-/* $Id: isdnl1.h,v 2.9 2000/06/26 08:59:13 keil Exp $
+/* $Id: isdnl1.h,v 2.9.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * Layer 1 defines
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- v2.4.2/linux/drivers/isdn/hisax/isdnl2.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/isdnl2.c	Fri Mar  2 11:12:09 2001
@@ -1,9 +1,9 @@
-/* $Id: isdnl2.c,v 2.25 2000/11/24 17:05:38 kai Exp $
+/* $Id: isdnl2.c,v 2.25.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -16,7 +16,7 @@
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.25 $";
+const char *l2_revision = "$Revision: 2.25.6.1 $";
 
 static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl2.h linux/drivers/isdn/hisax/isdnl2.h
--- v2.4.2/linux/drivers/isdn/hisax/isdnl2.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/isdnl2.h	Fri Mar  2 11:12:09 2001
@@ -1,8 +1,8 @@
-/* $Id: isdnl2.h,v 1.3 2000/06/26 08:59:13 keil Exp $
+/* $Id: isdnl2.h,v 1.3.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * Layer 2 defines
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- v2.4.2/linux/drivers/isdn/hisax/isdnl3.c	Sat Feb  3 19:51:27 2001
+++ linux/drivers/isdn/hisax/isdnl3.c	Fri Mar  2 11:12:09 2001
@@ -1,9 +1,9 @@
-/* $Id: isdnl3.c,v 2.17 2000/11/24 17:05:38 kai Exp $
+/* $Id: isdnl3.c,v 2.17.6.2 2001/02/16 16:43:27 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -18,7 +18,7 @@
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.17 $";
+const char *l3_revision = "$Revision: 2.17.6.2 $";
 
 static struct Fsm l3fsm;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isdnl3.h linux/drivers/isdn/hisax/isdnl3.h
--- v2.4.2/linux/drivers/isdn/hisax/isdnl3.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/isdnl3.h	Fri Mar  2 11:12:09 2001
@@ -1,6 +1,6 @@
-/* $Id: isdnl3.h,v 2.6 2000/06/26 08:59:13 keil Exp $
+/* $Id: isdnl3.h,v 2.6.6.1 2001/02/16 16:43:27 kai Exp $
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c
--- v2.4.2/linux/drivers/isdn/hisax/isurf.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/isurf.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: isurf.c,v 1.10 2000/11/24 17:05:38 kai Exp $
+/* $Id: isurf.c,v 1.10.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * isurf.c  low level stuff for Siemens I-Surf/I-Talk cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -17,7 +17,7 @@
 
 extern const char *CardType[];
 
-static const char *ISurf_revision = "$Revision: 1.10 $";
+static const char *ISurf_revision = "$Revision: 1.10.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c
--- v2.4.2/linux/drivers/isdn/hisax/ix1_micro.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/ix1_micro.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: ix1_micro.c,v 2.10 2000/11/24 17:05:38 kai Exp $
+/* $Id: ix1_micro.c,v 2.10.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * ix1_micro.c  low level stuff for ITK ix1-micro Rev.2 isdn cards
  *              derived from the original file teles3.c from Karsten Keil
@@ -14,7 +14,7 @@
 
 /*
    For the modification done by the author the following terms and conditions
-   apply (GNU PUBLIC LICENSE)
+   apply (GNU General Public License)
 
 
    This program is free software; you can redistribute it and/or modify
@@ -50,7 +50,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.10 $";
+const char *ix1_revision = "$Revision: 2.10.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c
--- v2.4.2/linux/drivers/isdn/hisax/jade.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/jade.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: jade.c,v 1.6 2000/11/24 17:05:38 kai Exp $
+/* $Id: jade.c,v 1.6.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * jade.c   JADE stuff (derived from original hscx.c)
  *
  * Author   Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/jade.h linux/drivers/isdn/hisax/jade.h
--- v2.4.2/linux/drivers/isdn/hisax/jade.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/jade.h	Fri Mar  2 11:12:09 2001
@@ -1,9 +1,9 @@
-/* $Id: jade.h,v 1.3 2000/06/26 08:59:14 keil Exp $
+/* $Id: jade.h,v 1.3.6.1 2001/02/16 16:43:27 kai Exp $
  * jade.h   JADE specific defines
  *
  * Author   Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/jade_irq.c linux/drivers/isdn/hisax/jade_irq.c
--- v2.4.2/linux/drivers/isdn/hisax/jade_irq.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/jade_irq.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: jade_irq.c,v 1.5 2000/11/19 17:02:48 kai Exp $
+/* $Id: jade_irq.c,v 1.5.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * jade_irq.c   Low level JADE IRQ stuff (derived from original hscx_irq.c)
  *
  * Author   Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.c linux/drivers/isdn/hisax/l3_1tr6.c
--- v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/l3_1tr6.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: l3_1tr6.c,v 2.13 2000/11/19 17:02:48 kai Exp $
+/* $Id: l3_1tr6.c,v 2.13.6.1 2001/02/16 16:43:27 kai Exp $
  *
  *  German 1TR6 D-channel protocol
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -17,7 +17,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.13 $";
+const char *l3_1tr6_revision = "$Revision: 2.13.6.1 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
 	*ptr++ = dis; \
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.h linux/drivers/isdn/hisax/l3_1tr6.h
--- v2.4.2/linux/drivers/isdn/hisax/l3_1tr6.h	Sun Aug  6 12:43:41 2000
+++ linux/drivers/isdn/hisax/l3_1tr6.h	Fri Mar  2 11:12:09 2001
@@ -1,8 +1,8 @@
-/* $Id: l3_1tr6.h,v 2.2 2000/06/26 08:59:14 keil Exp $
+/* $Id: l3_1tr6.h,v 2.2.6.1 2001/02/16 16:43:27 kai Exp $
  *
  *  German 1TR6 D-channel protocol defines
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #ifndef l3_1tr6
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c
--- v2.4.2/linux/drivers/isdn/hisax/l3dss1.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/l3dss1.c	Fri Mar  2 11:12:09 2001
@@ -1,11 +1,11 @@
-/* $Id: l3dss1.c,v 2.30 2000/11/19 17:02:48 kai Exp $
+/* $Id: l3dss1.c,v 2.30.6.1 2001/02/16 16:43:27 kai Exp $
  *
  * EURO/DSS1 D-channel protocol
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -22,7 +22,7 @@
 #include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.30 $";
+const char *dss1_revision = "$Revision: 2.30.6.1 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -426,9 +426,9 @@
 #undef FOO1
 
 			}
-#else  not HISAX_DE_AOC
+#else  /* not HISAX_DE_AOC */
                         l3_debug(st, "invoke break");
-#endif not HISAX_DE_AOC 
+#endif /* not HISAX_DE_AOC */
 			break;
 		case 2:	/* return result */
 			 /* if no process available handle separately */ 
@@ -438,12 +438,12 @@
                            return; 
                          }   
                         if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id))
-                          { /* Diversion successfull */
+                          { /* Diversion successful */
                             free_invoke_id(st,pc->prot.dss1.invoke_id);
                             pc->prot.dss1.remote_result = 0; /* success */     
                             pc->prot.dss1.invoke_id = 0;
                             pc->redir_result = pc->prot.dss1.remote_result; 
-                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successfull */
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
                         else
                           l3_debug(st,"return error unknown identifier");
 			break;
@@ -2112,7 +2112,7 @@
         MsgHead(p, pc->callref, MT_FACILITY);
 
         for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
-        if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ 
+        if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ 
 
 	*p++ = 0x1c;   /* Facility info element */
         *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
@@ -2138,7 +2138,7 @@
 	 *p++ = pc->chan->setup.phone[l];
 
         if (len_sub)
-	  { *p++ = 0x04; /* called party subadress */
+	  { *p++ = 0x04; /* called party subaddress */
             *p++ = len_sub - 2;
             while (*subp) *p++ = *subp++;
           }
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3dss1.h linux/drivers/isdn/hisax/l3dss1.h
--- v2.4.2/linux/drivers/isdn/hisax/l3dss1.h	Sun Aug  6 12:43:42 2000
+++ linux/drivers/isdn/hisax/l3dss1.h	Fri Mar  2 11:12:09 2001
@@ -1,8 +1,8 @@
-/* $Id: l3dss1.h,v 1.10 2000/06/26 08:59:14 keil Exp $
+/* $Id: l3dss1.h,v 1.10.6.1 2001/02/16 16:43:28 kai Exp $
  *
  *  DSS1 (Euro) D-channel protocol defines
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3ni1.c linux/drivers/isdn/hisax/l3ni1.c
--- v2.4.2/linux/drivers/isdn/hisax/l3ni1.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/isdn/hisax/l3ni1.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-// $Id: l3ni1.c,v 2.5.6.1 2000/12/06 16:59:19 kai Exp $
+// $Id: l3ni1.c,v 2.5.6.2 2001/02/16 16:43:28 kai Exp $
 //
 //-----------------------------------------------------------------------------
 //
@@ -16,7 +16,7 @@
 // Will Scales - beta tester extraordinaire
 // Brett Whittacre - beta tester and remote devel system in Vegas
 //
-// This file is (c) under GNU PUBLIC LICENSE
+// This file is (c) under GNU General Public License
 //
 //-----------------------------------------------------------------------------
 #define __NO_VERSION__
@@ -26,7 +26,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *ni1_revision = "$Revision: 2.5.6.1 $";
+const char *ni1_revision = "$Revision: 2.5.6.2 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -372,12 +372,12 @@
                            return; 
                          }   
                         if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
-                          { /* Diversion successfull */
+                          { /* Diversion successful */
                             free_invoke_id(st,pc->prot.ni1.invoke_id);
                             pc->prot.ni1.remote_result = 0; /* success */     
                             pc->prot.ni1.invoke_id = 0;
                             pc->redir_result = pc->prot.ni1.remote_result; 
-                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successfull */
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */
                         else
                           l3_debug(st,"return error unknown identifier");
 			break;
@@ -1973,7 +1973,7 @@
         MsgHead(p, pc->callref, MT_FACILITY);
 
         for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
-        if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ 
+        if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ 
 
 	*p++ = 0x1c;   /* Facility info element */
         *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
@@ -1999,7 +1999,7 @@
 	 *p++ = pc->chan->setup.phone[l];
 
         if (len_sub)
-	  { *p++ = 0x04; /* called party subadress */
+	  { *p++ = 0x04; /* called party subaddress */
             *p++ = len_sub - 2;
             while (*subp) *p++ = *subp++;
           }
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/l3ni1.h linux/drivers/isdn/hisax/l3ni1.h
--- v2.4.2/linux/drivers/isdn/hisax/l3ni1.h	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/l3ni1.h	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-// $Id: l3ni1.h,v 2.3 2000/11/16 13:50:43 keil Exp $
+// $Id: l3ni1.h,v 2.3.6.1 2001/02/16 16:43:28 kai Exp $
 //-----------------------------------------------------------------------------
 //
 // NI1 D-channel protocol
@@ -12,7 +12,7 @@
 // code provided by Ragnar Paulson.
 //
 //
-// This file is (c) under GNU PUBLIC LICENSE
+// This file is (c) under GNU General Public License
 //
 //-----------------------------------------------------------------------------
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/lmgr.c linux/drivers/isdn/hisax/lmgr.c
--- v2.4.2/linux/drivers/isdn/hisax/lmgr.c	Sun Aug  6 12:43:42 2000
+++ linux/drivers/isdn/hisax/lmgr.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: lmgr.c,v 1.7 2000/06/26 08:59:14 keil Exp $
+/* $Id: lmgr.c,v 1.7.6.1 2001/02/16 16:43:28 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *  Layermanagement module
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c
--- v2.4.2/linux/drivers/isdn/hisax/mic.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/mic.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: mic.c,v 1.10 2000/11/24 17:05:38 kai Exp $
+/* $Id: mic.c,v 1.10.6.1 2001/02/16 16:43:28 kai Exp $
  *
  * mic.c  low level stuff for mic cards
  *
@@ -6,7 +6,7 @@
  *
  * Author  Stephan von Krawczynski <skraw@ithnet.com>
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -19,7 +19,7 @@
 
 extern const char *CardType[];
 
-const char *mic_revision = "$Revision: 1.10 $";
+const char *mic_revision = "$Revision: 1.10.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- v2.4.2/linux/drivers/isdn/hisax/netjet.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/hisax/netjet.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: netjet.c,v 1.24.6.2 2000/12/17 22:45:11 kai Exp $
+/* $Id: netjet.c,v 1.24.6.4 2001/02/16 16:43:28 kai Exp $
  *
  * netjet.c     low level stuff for Traverse Technologie NETJet ISDN cards
  *
@@ -6,7 +6,7 @@
  *
  * Thanks to Traverse Technologie Australia for documents and informations
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -22,7 +22,7 @@
 #include <asm/io.h>
 #include "netjet.h"
 
-const char *NETjet_revision = "$Revision: 1.24.6.2 $";
+const char *NETjet_revision = "$Revision: 1.24.6.4 $";
 
 /* Interface functions */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/netjet.h linux/drivers/isdn/hisax/netjet.h
--- v2.4.2/linux/drivers/isdn/hisax/netjet.h	Tue Nov 28 21:44:41 2000
+++ linux/drivers/isdn/hisax/netjet.h	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-// $Id: netjet.h,v 2.5.6.1 2000/11/28 12:02:46 kai Exp $
+// $Id: netjet.h,v 2.5.6.2 2001/02/16 16:43:28 kai Exp $
 //-----------------------------------------------------------------------------
 //
 // NETjet common header file
@@ -6,7 +6,7 @@
 // Author       Kerstern Keil repackaged by
 //              Matt Henderson - Traverse Technologies P/L www.traverse.com.au
 //
-// This file is (c) under GNU PUBLIC LICENSE
+// This file is (c) under GNU General Public License
 //
 //-----------------------------------------------------------------------------
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- v2.4.2/linux/drivers/isdn/hisax/niccy.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/niccy.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: niccy.c,v 1.15.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: niccy.c,v 1.15.6.4 2001/02/16 16:43:28 kai Exp $
  *
  * niccy.c  low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
  *          compatible (SAGEM cybermodem)
@@ -7,7 +7,7 @@
  * 
  * Thanks to Dr. Neuhaus and SAGEM for informations
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -22,7 +22,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.15.6.2 $";
+const char *niccy_revision = "$Revision: 1.15.6.4 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c
--- v2.4.2/linux/drivers/isdn/hisax/nj_s.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/hisax/nj_s.c	Fri Mar  2 11:12:09 2001
@@ -1,6 +1,6 @@
-// $Id: nj_s.c,v 2.7.6.2 2001/02/07 11:31:31 kai Exp $
+// $Id: nj_s.c,v 2.7.6.4 2001/02/16 16:43:28 kai Exp $
 //
-// This file is (c) under GNU PUBLIC LICENSE
+// This file is (c) under GNU General Public License
 //
 
 #define __NO_VERSION__
@@ -14,7 +14,7 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_S_revision = "$Revision: 2.7.6.2 $";
+const char *NETjet_S_revision = "$Revision: 2.7.6.4 $";
 
 static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c
--- v2.4.2/linux/drivers/isdn/hisax/nj_u.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/hisax/nj_u.c	Fri Mar  2 11:12:09 2001
@@ -1,6 +1,6 @@
-/* $Id: nj_u.c,v 2.8.6.2 2001/02/07 11:31:31 kai Exp $ 
+/* $Id: nj_u.c,v 2.8.6.4 2001/02/16 16:43:28 kai Exp $ 
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -15,7 +15,7 @@
 #include <linux/ppp_defs.h>
 #include "netjet.h"
 
-const char *NETjet_U_revision = "$Revision: 2.8.6.2 $";
+const char *NETjet_U_revision = "$Revision: 2.8.6.4 $";
 
 static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/q931.c linux/drivers/isdn/hisax/q931.c
--- v2.4.2/linux/drivers/isdn/hisax/q931.c	Mon Aug 21 07:49:03 2000
+++ linux/drivers/isdn/hisax/q931.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: q931.c,v 1.10 2000/06/26 08:59:14 keil Exp $
+/* $Id: q931.c,v 1.10.6.1 2001/02/16 16:43:28 kai Exp $
  *
  * q931.c       code to decode ITU Q.931 call control messages
  *
  * Author       Jan den Ouden
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  * Changelog
  *
@@ -1228,7 +1228,7 @@
 				finish = 1;
 			}
 		} else if (sapi == TEI_SAPI) {
-			dp += sprintf(dp, "tei managment\n");
+			dp += sprintf(dp, "tei management\n");
 			finish = 1;
 		} else {
 			dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/rawhdlc.c linux/drivers/isdn/hisax/rawhdlc.c
--- v2.4.2/linux/drivers/isdn/hisax/rawhdlc.c	Sun Aug  6 12:43:42 2000
+++ linux/drivers/isdn/hisax/rawhdlc.c	Fri Mar  2 11:12:09 2001
@@ -1,11 +1,11 @@
-/* $Id: rawhdlc.c,v 1.5 2000/06/26 08:59:14 keil Exp $
+/* $Id: rawhdlc.c,v 1.5.6.1 2001/02/16 16:43:28 kai Exp $
  *
  * rawhdlc.c     support routines for cards that don't support HDLC
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *            Brent Baccala <baccala@FreeSoft.org>
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
  * don't perform HDLC encapsulation over the B channel.  Drivers for
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/rawhdlc.h linux/drivers/isdn/hisax/rawhdlc.h
--- v2.4.2/linux/drivers/isdn/hisax/rawhdlc.h	Sun Aug  6 12:43:42 2000
+++ linux/drivers/isdn/hisax/rawhdlc.h	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: rawhdlc.h,v 1.3 2000/06/26 08:59:14 keil Exp $
+/* $Id: rawhdlc.h,v 1.3.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * rawhdlc.h     support routines for cards that don't support HDLC
  *
  * Author     Brent Baccala <baccala@FreeSoft.org>
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c
--- v2.4.2/linux/drivers/isdn/hisax/s0box.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/s0box.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: s0box.c,v 2.4 2000/11/24 17:05:38 kai Exp $
+/* $Id: s0box.c,v 2.4.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * s0box.c      low level stuff for Creatix S0BOX
  *
  * Author       S0BOX specific stuff: Enrik Berkhan (enrik@starfleet.inka.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -15,7 +15,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.4 $";
+const char *s0box_revision = "$Revision: 2.4.6.1 $";
 
 static inline void
 writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c
--- v2.4.2/linux/drivers/isdn/hisax/saphir.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/saphir.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: saphir.c,v 1.8 2000/11/24 17:05:38 kai Exp $
+/* $Id: saphir.c,v 1.8.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * saphir.c low level stuff for HST Saphir 1
  *
@@ -6,7 +6,7 @@
  *
  * Thanks to    HST High Soft Tech GmbH
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -19,7 +19,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static char *saphir_rev = "$Revision: 1.8 $";
+static char *saphir_rev = "$Revision: 1.8.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- v2.4.2/linux/drivers/isdn/hisax/sedlbauer.c	Wed Nov 29 10:35:15 2000
+++ linux/drivers/isdn/hisax/sedlbauer.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: sedlbauer.c,v 1.25.6.2 2000/11/29 17:48:59 kai Exp $
+/* $Id: sedlbauer.c,v 1.25.6.4 2001/02/16 16:43:29 kai Exp $
  *
  * sedlbauer.c  low level stuff for Sedlbauer cards
  *              includes support for the Sedlbauer speed star (speed star II),
@@ -16,7 +16,7 @@
  *            Sedlbauer AG for informations
  *            Edgar Toernig
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -52,7 +52,7 @@
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.25.6.2 $";
+const char *Sedlbauer_revision = "$Revision: 1.25.6.4 $";
 
 const char *Sedlbauer_Types[] =
 	{"None", "speed card/win", "speed star", "speed fax+", 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/sedlbauer_cs.c linux/drivers/isdn/hisax/sedlbauer_cs.c
--- v2.4.2/linux/drivers/isdn/hisax/sedlbauer_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/isdn/hisax/sedlbauer_cs.c	Fri Mar  2 11:12:09 2001
@@ -0,0 +1,682 @@
+/*======================================================================
+
+    A Sedlbauer PCMCIA client driver
+
+    This driver is for the Sedlbauer Speed Star and Speed Star II, 
+    which are ISDN PCMCIA Cards.
+    
+    sedlbauer_cs.c 1.1a 2001/01/28 15:04:04
+
+    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.
+
+    Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann
+    <maniemann@users.sourceforge.net>. All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU 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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.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/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#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 =
+"sedlbauer_cs.c 1.1a 2001/01/28 15:04:04 (M.Niemann)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+static int protocol = 2;        /* EURO-ISDN Default */
+MODULE_PARM(protocol, "i");
+
+extern int sedl_init_pcmcia(int, int, int*, int);
+
+/*====================================================================*/
+
+/*
+   The event() function is this driver's Card Services event handler.
+   It will be called by Card Services when an appropriate card status
+   event is received.  The config() and release() entry points are
+   used to configure or release a socket, in response to card
+   insertion and ejection events.  They are invoked from the sedlbauer
+   event handler. 
+*/
+
+static void sedlbauer_config(dev_link_t *link);
+static void sedlbauer_release(u_long arg);
+static int sedlbauer_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+/*
+   The attach() and detach() entry points are used to create and destroy
+   "instances" of the driver, where each instance represents everything
+   needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *sedlbauer_attach(void);
+static void sedlbauer_detach(dev_link_t *);
+
+/*
+   You'll also need to prototype all the functions that will actually
+   be used to talk to your device.  See 'memory_cs' for a good example
+   of a fully self-sufficient driver; the other drivers rely more or
+   less on other parts of the kernel.
+*/
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "sedlbauer_cs";
+
+/*
+   A linked list of "instances" of the sedlbauer device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   To simplify the data structure handling, we actually include the
+   dev_link_t structure in the device's private data structure.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally shouldn't be allocated dynamically.
+
+   In this case, we also provide a flag to indicate if a device is
+   "stopped" due to a power management event, or card ejection.  The
+   device IO routines can use a flag like this to throttle IO to a
+   card that is not ready to accept it.
+
+   The bus_operations pointer is used on platforms for which we need
+   to use special socket-specific versions of normal IO primitives
+   (inb, outb, readb, writeb, etc) for card IO.
+*/
+   
+typedef struct local_info_t {
+    dev_link_t		link;
+    dev_node_t		node;
+    int			stop;
+    struct bus_operations *bus;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    sedlbauer_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+    
+======================================================================*/
+
+static dev_link_t *sedlbauer_attach(void)
+{
+    local_info_t *local;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int ret, i;
+    
+    DEBUG(0, "sedlbauer_attach()\n");
+
+    /* Allocate space for private device-specific data */
+    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    if (!local) return NULL;
+    memset(local, 0, sizeof(local_info_t));
+    link = &local->link; link->priv = local;
+    
+    /* Initialize the dev_link_t structure */
+    link->release.function = &sedlbauer_release;
+    link->release.data = (u_long)link;
+
+    /* Interrupt setup */
+    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->irq.Handler = NULL;
+    
+    /*
+      General socket configuration defaults can go here.  In this
+      client, we assume very little, and rely on the CIS for almost
+      everything.  In most clients, many details (i.e., number, sizes,
+      and attributes of IO windows) are fixed by the nature of the
+      device, and can be hard-wired here.
+    */
+
+    /* from old sedl_cs 
+    */
+    /* The io structure describes IO port mapping */
+    link->io.NumPorts1 = 8;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+
+
+    link->conf.Attributes = 0;
+    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 = &sedlbauer_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);
+	sedlbauer_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* sedlbauer_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 sedlbauer_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "sedlbauer_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    /*
+       If the device is currently configured and active, we won't
+       actually delete it yet.  Instead, it is marked so that when
+       the release() function is called, that will trigger a proper
+       detach().
+    */
+    if (link->state & DEV_CONFIG) {
+#ifdef PCMCIA_DEBUG
+	printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' "
+	       "still locked\n", link->dev->dev_name);
+#endif
+	link->state |= DEV_STALE_LINK;
+	return;
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, and free it */
+    *linkp = link->next;
+    /* This points to the parent local_info_t struct */
+    kfree(link->priv);
+} /* sedlbauer_detach */
+
+/*======================================================================
+
+    sedlbauer_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    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
+
+static void sedlbauer_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    local_info_t *dev = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int last_fn, last_ret;
+    u_char buf[64];
+    config_info_t conf;
+    win_req_t req;
+    memreq_t map;
+    
+
+    DEBUG(0, "sedlbauer_config(0x%p)\n", link);
+
+    /*
+       This reads the card's CONFIG tuple to find its configuration
+       registers.
+    */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    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;
+
+    /* Look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+
+    /*
+      In this loop, we scan the CIS for configuration table entries,
+      each of which describes a valid card configuration, including
+      voltage, IO window, memory window, and interrupt settings.
+
+      We make no assumptions about the card to be configured: we use
+      just the information available in the CIS.  In an ideal world,
+      this would work for any PCMCIA card, but it requires a complete
+      and accurate CIS.  In practice, a driver usually "knows" most of
+      these things without consulting the CIS, and most client drivers
+      will only use the CIS to fill in implementation-defined details.
+    */
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	cistpl_cftable_entry_t dflt = { 0 };
+	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (cfg->index == 0) goto next_entry;
+	link->conf.ConfigIndex = cfg->index;
+	
+	/* Does this card need audio output? */
+	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+	    link->conf.Attributes |= CONF_ENABLE_SPKR;
+	    link->conf.Status = CCSR_AUDIO_ENA;
+	}
+	
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	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;
+	
+	/* Do we need to allocate an interrupt? */
+	if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+	    link->conf.Attributes |= CONF_ENABLE_IRQ;
+	
+	/* IO window settings */
+	link->io.NumPorts1 = link->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	    if (!(io->flags & CISTPL_IO_8BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+/* new in dummy.cs 2001/01/28 MN 
+            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+*/
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.NumPorts1 = io->win[0].len;
+	    if (io->nwin > 1) {
+		link->io.Attributes2 = link->io.Attributes1;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = io->win[1].len;
+	    }
+	    /* This reserves IO space but doesn't actually enable it */
+	    CFG_CHECK(RequestIO, link->handle, &link->io);
+	}
+
+	/*
+	  Now set up a common memory window, if needed.  There is room
+	  in the dev_link_t structure for one memory window handle,
+	  but if the base addresses need to be saved, or if multiple
+	  windows are needed, the info should go in the private data
+	  structure for this device.
+
+	  Note that the memory window base is a physical address, and
+	  needs to be mapped to virtual space with ioremap() before it
+	  is used.
+	*/
+	if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+	    cistpl_mem_t *mem =
+		(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+	    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+	    req.Attributes |= WIN_ENABLE;
+	    req.Base = mem->win[0].host_addr;
+	    req.Size = mem->win[0].len;
+/* new in dummy.cs 2001/01/28 MN 
+            if (req.Size < 0x1000)
+                req.Size = 0x1000;
+*/
+	    req.AccessSpeed = 0;
+	    link->win = (window_handle_t)link->handle;
+	    CFG_CHECK(RequestWindow, &link->win, &req);
+	    map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+	    CFG_CHECK(MapMemPage, link->win, &map);
+	}
+	/* If we got this far, we're cool! */
+	break;
+	
+    next_entry:
+/* new in dummy.cs 2001/01/28 MN 
+        if (link->io.NumPorts1)
+           CardServices(ReleaseIO, link->handle, &link->io);
+*/
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+    
+    /*
+       Allocate an interrupt line.  Note that this does not assign a
+       handler to the interrupt, unless the 'Handler' member of the
+       irq structure is initialized.
+    */
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+	CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	
+    /*
+       This actually configures the PCMCIA socket -- setting up
+       the I/O windows and the interrupt mapping, and putting the
+       card and host interface into "Memory and IO" mode.
+    */
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+    /*
+      At this point, the dev_node_t structure(s) need to be
+      initialized and arranged in a linked list at link->dev.
+    */
+    sprintf(dev->node.dev_name, "sedlbauer");
+    dev->node.major = dev->node.minor = 0;
+    link->dev = &dev->node;
+
+    /* Finally, report what we've done */
+    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	   dev->node.dev_name, link->conf.ConfigIndex,
+	   link->conf.Vcc/10, link->conf.Vcc%10);
+    if (link->conf.Vpp1)
+	printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+	printk(", irq %d", link->irq.AssignedIRQ);
+    if (link->io.NumPorts1)
+	printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+	       link->io.BasePort1+link->io.NumPorts1-1);
+    if (link->io.NumPorts2)
+	printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+	       link->io.BasePort2+link->io.NumPorts2-1);
+    if (link->win)
+	printk(", mem 0x%06lx-0x%06lx", req.Base,
+	       req.Base+req.Size-1);
+    printk("\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+ 
+    sedl_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ,
+                     &(((local_info_t*)link->priv)->stop),
+                     protocol);
+
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    sedlbauer_release((u_long)link);
+
+} /* sedlbauer_config */
+
+/*======================================================================
+
+    After a card is removed, sedlbauer_release() will unregister the
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void sedlbauer_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "sedlbauer_release(0x%p)\n", link);
+
+    /*
+       If the device is currently in use, we won't release until it
+       is actually closed, because until then, we can't be sure that
+       no one will try to access the device or its data structures.
+    */
+    if (link->open) {
+	DEBUG(1, "sedlbauer_cs: release postponed, '%s' still open\n",
+	      link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    /* Unlink the device chain */
+    link->dev = NULL;
+
+    /*
+      In a normal driver, additional code may be needed to release
+      other kernel data structures associated with this device. 
+    */
+    
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win)
+	CardServices(ReleaseWindow, link->win);
+    CardServices(ReleaseConfiguration, link->handle);
+    if (link->io.NumPorts1)
+	CardServices(ReleaseIO, link->handle, &link->io);
+    if (link->irq.AssignedIRQ)
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+    link->state &= ~DEV_CONFIG;
+    
+    if (link->state & DEV_STALE_LINK)
+	sedlbauer_detach(link);
+    
+} /* sedlbauer_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.
+
+    When a CARD_REMOVAL event is received, we immediately set a
+    private flag to block future accesses to this device.  All the
+    functions that actually access the device should check this flag
+    to make sure the card is still present.
+    
+======================================================================*/
+
+static int sedlbauer_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    local_info_t *dev = link->priv;
+    
+    DEBUG(1, "sedlbauer_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    ((local_info_t *)link->priv)->stop = 1;
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	dev->bus = args->bus;
+	sedlbauer_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	/* Mark the device as stopped, to block IO until later */
+	dev->stop = 1;
+	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 (link->state & DEV_CONFIG)
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	dev->stop = 0;
+	/*
+	  In a normal driver, additional code may go here to restore
+	  the device state and restart IO. 
+	*/
+	break;
+    }
+    return 0;
+} /* sedlbauer_event */
+
+/*====================================================================*/
+
+static int __init init_sedlbauer_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "sedlbauer_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &sedlbauer_attach, &sedlbauer_detach);
+    return 0;
+}
+
+static void __exit exit_sedlbauer_cs(void)
+{
+    DEBUG(0, "sedlbauer_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL) {
+	del_timer(&dev_list->release);
+	if (dev_list->state & DEV_CONFIG)
+	    sedlbauer_release((u_long)dev_list);
+	sedlbauer_detach(dev_list);
+    }
+}
+
+module_init(init_sedlbauer_cs);
+module_exit(exit_sedlbauer_cs);
+
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c
--- v2.4.2/linux/drivers/isdn/hisax/sportster.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/sportster.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: sportster.c,v 1.14 2000/11/24 17:05:38 kai Exp $
+/* $Id: sportster.c,v 1.14.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * sportster.c     low level stuff for USR Sportster internal TA
  *
@@ -6,7 +6,7 @@
  *
  * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -17,7 +17,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.14 $";
+const char *sportster_revision = "$Revision: 1.14.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c
--- v2.4.2/linux/drivers/isdn/hisax/tei.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/tei.c	Fri Mar  2 11:12:09 2001
@@ -1,9 +1,9 @@
-/* $Id: tei.c,v 2.17 2000/11/24 17:05:38 kai Exp $
+/* $Id: tei.c,v 2.17.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- *		This file is (c) under GNU PUBLIC LICENSE
+ *		This file is (c) under GNU General Public License
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
@@ -17,7 +17,7 @@
 #include <linux/init.h>
 #include <linux/random.h>
 
-const char *tei_revision = "$Revision: 2.17 $";
+const char *tei_revision = "$Revision: 2.17.6.1 $";
 
 #define ID_REQUEST	1
 #define ID_ASSIGNED	2
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c
--- v2.4.2/linux/drivers/isdn/hisax/teleint.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/teleint.c	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: teleint.c,v 1.14 2000/11/24 17:05:38 kai Exp $
+/* $Id: teleint.c,v 1.14.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * teleint.c     low level stuff for TeleInt isdn cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
@@ -17,7 +17,7 @@
 
 extern const char *CardType[];
 
-const char *TeleInt_revision = "$Revision: 1.14 $";
+const char *TeleInt_revision = "$Revision: 1.14.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- v2.4.2/linux/drivers/isdn/hisax/teles0.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/teles0.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: teles0.c,v 2.13 2000/11/24 17:05:38 kai Exp $
+/* $Id: teles0.c,v 2.13.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * teles0.c     low level stuff for Teles Memory IO isdn cards
  *              based on the teles driver from Jan den Ouden
@@ -9,7 +9,7 @@
  *              Fritz Elfert
  *              Beat Doebeli
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -21,7 +21,7 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.13 $";
+const char *teles0_revision = "$Revision: 2.13.6.1 $";
 
 #define TELES_IOMEM_SIZE	0x400
 #define byteout(addr,val) outb(val,addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- v2.4.2/linux/drivers/isdn/hisax/teles3.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hisax/teles3.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: teles3.c,v 2.17 2000/11/24 17:05:38 kai Exp $
+/* $Id: teles3.c,v 2.17.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
  *
@@ -10,7 +10,7 @@
  *              Fritz Elfert
  *              Beat Doebeli
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -21,7 +21,7 @@
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.17 $";
+const char *teles3_revision = "$Revision: 2.17.6.1 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c
--- v2.4.2/linux/drivers/isdn/hisax/telespci.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/telespci.c	Fri Mar  2 11:12:09 2001
@@ -1,11 +1,11 @@
-/* $Id: telespci.c,v 2.16.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: telespci.c,v 2.16.6.4 2001/02/16 16:43:29 kai Exp $
  *
  * telespci.c     low level stuff for Teles PCI isdn cards
  *
  * Author       Ton van Rosmalen 
  *              Karsten Keil (keil@isdn4linux.de)
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 #define __NO_VERSION__
@@ -18,7 +18,7 @@
 #include <linux/pci.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.16.6.2 $";
+const char *telespci_revision = "$Revision: 2.16.6.4 $";
 
 #define ZORAN_PO_RQ_PEN	0x02000000
 #define ZORAN_PO_WR	0x00800000
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c
--- v2.4.2/linux/drivers/isdn/hisax/w6692.c	Wed Nov 29 10:12:29 2000
+++ linux/drivers/isdn/hisax/w6692.c	Fri Mar  2 11:12:09 2001
@@ -1,11 +1,11 @@
-/* $Id: w6692.c,v 1.12.6.2 2000/11/29 16:00:14 kai Exp $
+/* $Id: w6692.c,v 1.12.6.4 2001/02/16 16:43:29 kai Exp $
  *
  * w6692.c   Winbond W6692 specific routines
  *
  * Author       Petr Novak <petr.novak@i.cz>
  *              (based on HiSax driver by Karsten Keil)
  *
- *              This file is (c) under GNU PUBLIC LICENSE
+ *              This file is (c) under GNU General Public License
  *
  */
 
@@ -35,7 +35,7 @@
 
 extern const char *CardType[];
 
-const char *w6692_revision = "$Revision: 1.12.6.2 $";
+const char *w6692_revision = "$Revision: 1.12.6.4 $";
 
 #define DBUSY_TIMER_VALUE 80
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hisax/w6692.h linux/drivers/isdn/hisax/w6692.h
--- v2.4.2/linux/drivers/isdn/hisax/w6692.h	Sun Aug  6 12:43:42 2000
+++ linux/drivers/isdn/hisax/w6692.h	Fri Mar  2 11:12:09 2001
@@ -1,10 +1,10 @@
-/* $Id: w6692.h,v 1.2 2000/06/26 08:59:15 keil Exp $
+/* $Id: w6692.h,v 1.2.6.1 2001/02/16 16:43:29 kai Exp $
  *
  * w6692.h   Winbond W6692 specific defines
  *
  * Author       Petr Novak <petr.novak@i.cz>
  *
- * This file is (c) under GNU PUBLIC LICENSE
+ * This file is (c) under GNU General Public License
  *
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/boardergo.c linux/drivers/isdn/hysdn/boardergo.c
--- v2.4.2/linux/drivers/isdn/hysdn/boardergo.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/isdn/hysdn/boardergo.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: boardergo.c,v 1.5.6.1 2000/12/10 22:01:04 kai Exp $
+/* $Id: boardergo.c,v 1.5.6.2 2001/02/16 16:43:30 kai Exp $
 
  * Linux driver for HYSDN cards, specific routines for ergo type boards.
  *
@@ -270,7 +270,7 @@
 			return (-ERR_BOOTIMG_FAIL);
 		}
 	}			/* start_boot_img */
-	return (0);		/* successfull */
+	return (0);		/* successful */
 }				/* ergo_writebootimg */
 
 /********************************************************************************/
@@ -337,7 +337,7 @@
 
 /***********************************************************************************/
 /* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
-/* boot process. If the process has been successfull 0 is returned otherwise a     */
+/* boot process. If the process has been successful 0 is returned otherwise a     */
 /* negative error code is returned.                                                */
 /***********************************************************************************/
 static int
@@ -361,7 +361,7 @@
 			    (dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
 			    (dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
 			    ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
-				break;	/* an error occured */
+				break;	/* an error occurred */
 
 			/* Check for additional data delivered during SysReady */
 			msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hycapi.c linux/drivers/isdn/hysdn/hycapi.c
--- v2.4.2/linux/drivers/isdn/hysdn/hycapi.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hysdn/hycapi.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hycapi.c,v 1.8 2000/11/22 17:13:13 kai Exp $
+/* $Id: hycapi.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $
  *
  * Linux driver for HYSDN cards, CAPI2.0-Interface.
  * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH
@@ -41,7 +41,7 @@
 #include "hysdn_defs.h"
 #include <linux/kernelcapi.h>
 
-static char hycapi_revision[]="$Revision: 1.8 $";
+static char hycapi_revision[]="$Revision: 1.8.6.1 $";
 
 typedef struct _hycapi_appl {
 	unsigned int ctrl_mask;
@@ -522,7 +522,7 @@
 /******************************************************************
 hycapi_rx_capipkt
 
-Recieve a capi-message.
+Receive a capi-message.
 
 All B3_DATA_IND are converted to 64K-extension compatible format.
 New nccis are created if neccessary.
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_boot.c linux/drivers/isdn/hysdn/hysdn_boot.c
--- v2.4.2/linux/drivers/isdn/hysdn/hysdn_boot.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/hysdn/hysdn_boot.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_boot.c,v 1.4 2000/11/13 22:51:47 kai Exp $
+/* $Id: hysdn_boot.c,v 1.4.6.2 2001/02/16 16:43:30 kai Exp $
 
  * Linux driver for HYSDN cards, specific routines for booting and pof handling.
  *
@@ -49,7 +49,7 @@
 	uchar pof_state;	/* actual state of read handler */
 	uchar is_crypted;	/* card data is crypted */
 	int BufSize;		/* actual number of bytes bufferd */
-	int last_error;		/* last occured error */
+	int last_error;		/* last occurred error */
 	word pof_recid;		/* actual pof recid */
 	ulong pof_reclen;	/* total length of pof record data */
 	ulong pof_recoffset;	/* actual offset inside pof record */
@@ -62,7 +62,7 @@
 };
 
 /*****************************************************/
-/*  start decryption of sucessive POF file chuncks.  */
+/*  start decryption of successive POF file chuncks.  */
 /*                                                   */
 /*  to be called at start of POF file reading,       */
 /*  before starting any decryption on any POF record. */
@@ -93,7 +93,7 @@
 
 /********************************************************************************/
 /* pof_handle_data executes the required actions dependant on the active record */
-/* id. If successfull 0 is returned, a negative value shows an error.           */
+/* id. If successful 0 is returned, a negative value shows an error.           */
 /********************************************************************************/
 static int
 pof_handle_data(hysdn_card * card, int datlen)
@@ -182,7 +182,7 @@
 /* number of data bytes. The number delivered is additionally supplied for    */
 /* verification. The functions handles the data and returns the needed number */
 /* of bytes for the next action. If the returned value is 0 or less an error  */
-/* occured and booting must be aborted.                                       */
+/* occurred and booting must be aborted.                                       */
 /******************************************************************************/
 int
 pof_write_buffer(hysdn_card * card, int datlen)
@@ -253,7 +253,7 @@
 				break;
 			}
 			if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
-				return (boot->last_error);	/* an error occured */
+				return (boot->last_error);	/* an error occurred */
 			boot->pof_recoffset += datlen;
 			if (boot->pof_recoffset >= boot->pof_reclen) {
 				boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */
@@ -346,7 +346,7 @@
 
 /*********************************************************************************/
 /* EvalSysrTokData checks additional records delivered with the Sysready Message */
-/* when POF has been booted. A return value of 0 is used if no error occured.    */
+/* when POF has been booted. A return value of 0 is used if no error occurred.    */
 /*********************************************************************************/
 int
 EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_init.c linux/drivers/isdn/hysdn/hysdn_init.c
--- v2.4.2/linux/drivers/isdn/hysdn/hysdn_init.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/hysdn/hysdn_init.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_init.c,v 1.6.6.1 2000/11/28 12:02:47 kai Exp $
+/* $Id: hysdn_init.c,v 1.6.6.5 2001/02/16 16:43:30 kai Exp $
 
  * Linux driver for HYSDN cards, init functions.
  * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
@@ -32,7 +32,7 @@
 
 #include "hysdn_defs.h"
 
-static char *hysdn_init_revision = "$Revision: 1.6.6.1 $";
+static char *hysdn_init_revision = "$Revision: 1.6.6.5 $";
 int cardmax;			/* number of found cards */
 hysdn_card *card_root = NULL;	/* pointer to first card */
 
@@ -89,6 +89,7 @@
 					     akt_pcidev)) != NULL) {
 		if (pci_enable_device(akt_pcidev))
 			continue;
+
 		if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
 			printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
 			return;
@@ -173,7 +174,6 @@
 /* image becomes smaller and the driver code is only loaded when needed.    */
 /* Additionally newer versions may be activated without rebooting.          */
 /****************************************************************************/
-#ifdef CONFIG_MODULES
 
 /******************************************************/
 /* extract revision number from string for log output */
@@ -197,12 +197,12 @@
 /****************************************************************************/
 /* init_module is called once when the module is loaded to do all necessary */
 /* things like autodetect...                                                */
-/* If the return value of this function is 0 the init has been successfull  */
+/* If the return value of this function is 0 the init has been successful   */
 /* and the module is added to the list in /proc/modules, otherwise an error */
 /* is assumed and the module will not be kept in memory.                    */
 /****************************************************************************/
-int
-init_module(void)
+static int __init
+hysdn_init(void)
 {
 	char tmp[50];
 
@@ -235,14 +235,14 @@
 
 /***********************************************************************/
 /* cleanup_module is called when the module is released by the kernel. */
-/* The routine is only called if init_module has been successfull and  */
+/* The routine is only called if init_module has been successful and   */
 /* the module counter has a value of 0. Otherwise this function will   */
 /* not be called. This function must release all resources still allo- */
 /* cated as after the return from this function the module code will   */
 /* be removed from memory.                                             */
 /***********************************************************************/
-void
-cleanup_module(void)
+static void __exit
+hysdn_exit(void)
 {
 #ifdef CONFIG_HYSDN_CAPI
 	hysdn_card *card;
@@ -261,4 +261,5 @@
 	printk(KERN_NOTICE "HYSDN: module unloaded\n");
 }				/* cleanup_module */
 
-#endif				/* CONFIG_MODULES */
+module_init(hysdn_init);
+module_exit(hysdn_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_net.c linux/drivers/isdn/hysdn/hysdn_net.c
--- v2.4.2/linux/drivers/isdn/hysdn/hysdn_net.c	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/hysdn/hysdn_net.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: hysdn_net.c,v 1.8 2000/11/13 22:51:47 kai Exp $
+/* $Id: hysdn_net.c,v 1.8.6.1 2001/02/16 16:43:30 kai Exp $
 
  * Linux driver for HYSDN cards, net (ethernet type) handling routines.
  *
@@ -38,7 +38,7 @@
 #include "hysdn_defs.h"
 
 /* store the actual version for log reporting */
-char *hysdn_net_revision = "$Revision: 1.8 $";
+char *hysdn_net_revision = "$Revision: 1.8.6.1 $";
 
 #define MAX_SKB_BUFFERS 20	/* number of buffers for keeping TX-data */
 
@@ -350,7 +350,7 @@
 	if (card->debug_flags & LOG_NET_INIT)
 		hysdn_addlog(card, "network device deleted");
 
-	return (0);		/* always successfull */
+	return (0);		/* always successful */
 }				/* hysdn_net_release */
 
 /*****************************************************************************/
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c
--- v2.4.2/linux/drivers/isdn/hysdn/hysdn_procconf.c	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/hysdn/hysdn_procconf.c	Fri Mar  2 11:12:10 2001
@@ -56,7 +56,7 @@
 /***********************************************************************/
 /* process_line parses one config line and transfers it to the card if */
 /* necessary.                                                          */
-/* if the return value is negative an error occured.                   */
+/* if the return value is negative an error occurred.                   */
 /***********************************************************************/
 static int
 process_line(struct conf_writedata *cnf)
@@ -130,7 +130,7 @@
 		if (ch == 0x1A) {
 			/* we detected a pof file */
 			if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
-				return (cnf->needed_size);	/* an error occured -> exit */
+				return (cnf->needed_size);	/* an error occurred -> exit */
 			cnf->buf_size = 0;	/* buffer is empty */
 			cnf->state = CONF_STATE_POF;	/* new state */
 		} else {
@@ -158,7 +158,7 @@
 			cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size);	/* write data */
 			if (cnf->needed_size <= 0) {
 				cnf->card->state = CARD_STATE_BOOTERR;	/* show boot error */
-				return (cnf->needed_size);	/* an error occured */
+				return (cnf->needed_size);	/* an error occurred */
 			}
 			cnf->buf_size = 0;	/* buffer is empty again */
 		}
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_procfs.c linux/drivers/isdn/hysdn/hysdn_procfs.c
--- v2.4.2/linux/drivers/isdn/hysdn/hysdn_procfs.c	Wed Jul 12 21:58:42 2000
+++ linux/drivers/isdn/hysdn/hysdn_procfs.c	Fri Mar  2 11:12:10 2001
@@ -139,7 +139,7 @@
 		return (-ESPIPE);
 
 	if ((retval = pof_boot_write(card, buf, count)) < 0)
-		retval = -EFAULT;	/* an error occured */
+		retval = -EFAULT;	/* an error occurred */
 
 	return (retval);
 }				/* hysdn_log_write */
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/hysdn/hysdn_sched.c linux/drivers/isdn/hysdn/hysdn_sched.c
--- v2.4.2/linux/drivers/isdn/hysdn/hysdn_sched.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/hysdn/hysdn_sched.c	Fri Mar  2 11:12:10 2001
@@ -141,7 +141,7 @@
 
 
 /*****************************************************************************/
-/* send one config line to the card and return 0 if successfull, otherwise a */
+/* send one config line to the card and return 0 if successful, otherwise a */
 /* negative error code.                                                      */
 /* The function works with timeouts perhaps not giving the greatest speed    */
 /* sending the line, but this should be meaningless beacuse only some lines  */
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c
--- v2.4.2/linux/drivers/isdn/icn/icn.c	Fri Nov 17 11:16:20 2000
+++ linux/drivers/isdn/icn/icn.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.65 2000/11/13 22:51:48 kai Exp $
+/* $Id: icn.c,v 1.65.6.3 2001/02/16 16:43:31 kai Exp $
 
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -21,6 +21,7 @@
  */
 
 #include "icn.h"
+#include <linux/init.h>
 
 /*
  * Verbose bootcode- and protocol-downloading.
@@ -33,7 +34,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.65 $";
+*revision = "$Revision: 1.65.6.3 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -867,7 +868,7 @@
 	SLEEP(1);
 	memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);	/* Copy code        */
 #ifdef BOOT_DEBUG
-	printk(KERN_DEBUG "Bootloader transfered\n");
+	printk(KERN_DEBUG "Bootloader transferred\n");
 #endif
 	if (card->doubleS0) {
 		SLEEP(1);
@@ -883,7 +884,7 @@
 		SLEEP(1);
 		memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1);	/* Copy code        */
 #ifdef BOOT_DEBUG
-		printk(KERN_DEBUG "Bootloader transfered\n");
+		printk(KERN_DEBUG "Bootloader transferred\n");
 #endif
 	}
 	kfree(codebuf);
@@ -1638,10 +1639,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-#define icn_init init_module
-#else
-#include <linux/init.h>
+#ifndef MODULE
 static int __init
 icn_setup(char *line)
 {
@@ -1667,10 +1665,9 @@
 	return(1);
 }
 __setup("icn=", icn_setup);
-#endif /* MODULES */
+#endif /* MODULE */
 
-int
-icn_init(void)
+static int __init icn_init(void)
 {
 	char *p;
 	char rev[10];
@@ -1681,9 +1678,6 @@
 	dev.mcard = NULL;
 	dev.firstload = 1;
 
-	/* No symbols to export, hide all symbols */
-	EXPORT_NO_SYMBOLS;
-
 	if ((p = strchr(revision, ':'))) {
 		strcpy(rev, p + 1);
 		p = strchr(rev, '$');
@@ -1695,9 +1689,7 @@
 	return (icn_addcard(portbase, icn_id, icn_id2));
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void __exit icn_exit(void)
 {
 	isdn_ctrl cmd;
 	icn_card *card = cards;
@@ -1731,4 +1723,6 @@
 		release_shmem((ulong) dev.shmem, 0x4000);
 	printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
 }
-#endif
+
+module_init(icn_init);
+module_exit(icn_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h
--- v2.4.2/linux/drivers/isdn/icn/icn.h	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/icn/icn.h	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.30 2000/11/13 22:51:48 kai Exp $
+/* $Id: icn.h,v 1.30.6.2 2001/02/16 16:43:31 kai Exp $
 
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -217,9 +217,9 @@
 #ifdef MODULE
 MODULE_AUTHOR("Fritz Elfert");
 MODULE_PARM(portbase, "i");
-MODULE_PARM_DESC(portbase, "Port adress of first card");
+MODULE_PARM_DESC(portbase, "Port address of first card");
 MODULE_PARM(membase, "i");
-MODULE_PARM_DESC(membase, "Shared memory adress of all cards");
+MODULE_PARM_DESC(membase, "Shared memory address of all cards");
 MODULE_PARM(icn_id, "s");
 MODULE_PARM_DESC(icn_id, "ID-String of first card");
 MODULE_PARM(icn_id2, "s");
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_bsdcomp.c linux/drivers/isdn/isdn_bsdcomp.c
--- v2.4.2/linux/drivers/isdn/isdn_bsdcomp.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/isdn_bsdcomp.c	Fri Mar  2 11:12:09 2001
@@ -47,12 +47,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MODULE
-#error This file must be compiled as a module.
-#endif
-
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -919,7 +915,7 @@
  * Module support routines
  *************************************************************/
 
-int init_module(void)
+static int __init isdn_bsdcomp_init(void)
 {
 	int answer = isdn_ppp_register_compressor (&ippp_bsd_compress);
 	if (answer == 0)
@@ -927,7 +923,10 @@
 	return answer;
 }
 
-void cleanup_module(void)
+static void __exit isdn_bsdcomp_exit(void)
 {
 	isdn_ppp_unregister_compressor (&ippp_bsd_compress);
 }
+
+module_init(isdn_bsdcomp_init);
+module_exit(isdn_bsdcomp_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c
--- v2.4.2/linux/drivers/isdn/isdn_cards.c	Fri Dec 29 14:40:54 2000
+++ linux/drivers/isdn/isdn_cards.c	Wed Dec 31 16:00:00 1969
@@ -1,63 +0,0 @@
-/* $Id: isdn_cards.c,v 1.14 2000/11/23 20:45:14 kai Exp $
-
- * Linux ISDN subsystem, initialization for non-modularized drivers.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * 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.
- *
- * 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>
-
-#ifdef CONFIG_ISDN_DRV_ICN
-extern void icn_init(void);
-#endif
-
-#ifdef CONFIG_ISDN_DRV_HISAX
-extern void HiSax_init(void);
-#endif
-
-#ifdef CONFIG_ISDN_DRV_PCBIT
-extern void pcbit_init(void);
-#endif
-
-#if defined(CONFIG_ISDN_DRV_EICON_OLD) || defined(CONFIG_ISDN_DRV_EICON_DIVAS)
-extern void eicon_init(void);
-#endif
-
-#if CONFIG_ISDN_DRV_ACT2000
-extern void act2000_init(void);
-#endif
-
-void
-isdn_cards_init(void)
-{
-#if CONFIG_ISDN_DRV_ICN
-	icn_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_HISAX
-	HiSax_init();
-#endif
-#if CONFIG_ISDN_DRV_PCBIT
-	pcbit_init();
-#endif
-#if CONFIG_ISDN_DRV_ACT2000
-	act2000_init();
-#endif
-#if defined(CONFIG_ISDN_DRV_EICON_OLD) || defined(CONFIG_ISDN_DRV_EICON_DIVAS)
-	eicon_init();
-#endif
-}
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h
--- v2.4.2/linux/drivers/isdn/isdn_cards.h	Sun Aug  6 12:43:42 2000
+++ linux/drivers/isdn/isdn_cards.h	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-/* $Id: isdn_cards.h,v 1.4 2000/05/11 22:29:20 kai Exp $
-
- * Linux ISDN subsystem, initialization for non-modularized drivers.
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * 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.
- *
- * 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.
- *
- */
-
-extern void isdn_cards_init(void);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- v2.4.2/linux/drivers/isdn/isdn_common.c	Wed Feb 21 18:20:23 2001
+++ linux/drivers/isdn/isdn_common.c	Fri Mar  2 11:12:10 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.114.6.6 2001/02/07 11:31:30 kai Exp $
+/* $Id: isdn_common.c,v 1.114.6.8 2001/02/16 16:43:22 kai Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -42,9 +42,8 @@
 #endif
 #ifdef CONFIG_ISDN_DIVERSION
 #include <linux/isdn_divertif.h>
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 #include "isdn_v110.h"
-#include "isdn_cards.h"
 #include <linux/devfs_fs_kernel.h>
 
 /* Debugflags */
@@ -52,7 +51,7 @@
 
 isdn_dev *dev;
 
-static char *isdn_revision = "$Revision: 1.114.6.6 $";
+static char *isdn_revision = "$Revision: 1.114.6.8 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -70,7 +69,7 @@
 
 #ifdef CONFIG_ISDN_DIVERSION
 static isdn_divert_if *divert_if; /* = NULL */
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 
 
 static int isdn_writebuf_stub(int, int, const u_char *, int, int);
@@ -520,7 +519,7 @@
                                          if (divert_if)
                  	                  if ((retval = divert_if->stat_callback(c))) 
 					    return(retval); /* processed */
-#endif CONFIG_ISDN_DIVERSION                        
+#endif /* CONFIG_ISDN_DIVERSION */                       
 					if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
 						/* No tty responding */
 						cmd.driver = di;
@@ -593,7 +592,7 @@
 #ifdef CONFIG_ISDN_DIVERSION
                         if (divert_if)
                          divert_if->stat_callback(c); 
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 			break;
 		case ISDN_STAT_DISPLAY:
 #ifdef ISDN_DEBUG_STATCALLB
@@ -603,7 +602,7 @@
 #ifdef CONFIG_ISDN_DIVERSION
                         if (divert_if)
                          divert_if->stat_callback(c); 
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 			break;
 		case ISDN_STAT_DCONN:
 			if (i < 0)
@@ -645,7 +644,7 @@
 #ifdef CONFIG_ISDN_DIVERSION
                         if (divert_if)
                          divert_if->stat_callback(c); 
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 			break;
 			break;
 		case ISDN_STAT_BCONN:
@@ -774,7 +773,7 @@
 	        case ISDN_STAT_REDIR:
                         if (divert_if)
                           return(divert_if->stat_callback(c));
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 		default:
 			return -1;
 	}
@@ -2160,7 +2159,7 @@
 
 EXPORT_SYMBOL(DIVERT_REG_NAME);
 
-#endif CONFIG_ISDN_DIVERSION
+#endif /* CONFIG_ISDN_DIVERSION */
 
 
 EXPORT_SYMBOL(register_isdn);
@@ -2409,7 +2408,6 @@
 	printk(" loaded\n");
 #else
 	printk("\n");
-	isdn_cards_init();
 #endif
 	isdn_info_update();
 	return 0;
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.4.2/linux/drivers/isdn/isdn_tty.c	Mon Nov 27 16:53:43 2000
+++ linux/drivers/isdn/isdn_tty.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.94 2000/11/25 17:00:59 kai Exp $
+/* $Id: isdn_tty.c,v 1.94.6.1 2001/02/16 16:43:22 kai Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -66,7 +66,7 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.94 $";
+char *isdn_tty_revision = "$Revision: 1.94.6.1 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -3773,7 +3773,7 @@
                                                 sprintf(ds, "\r\n%d", info->emu.charge);
                                                 isdn_tty_at_cout(ds, info);
                                                 break;
-					default:
+					default:;
 				}
 				break;
 #ifdef DUMMY_HAYES_AT
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c
--- v2.4.2/linux/drivers/isdn/isdn_v110.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/isdn_v110.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.5.6.1 2001/01/23 17:45:02 kai Exp $
+/* $Id: isdn_v110.c,v 1.5.6.3 2001/02/16 16:43:23 kai Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -30,7 +30,7 @@
 
 #undef ISDN_V110_DEBUG
 
-char *isdn_v110_revision = "$Revision: 1.5.6.1 $";
+char *isdn_v110_revision = "$Revision: 1.5.6.3 $";
 
 #define V110_38400 255
 #define V110_19200  15
@@ -70,7 +70,7 @@
  * FlipBits reorders sequences of keylen bits in one byte.
  * E.g. source order 7654321 will be converted to 45670123 when keylen = 4,
  * and to 67452301 when keylen = 2. This is necessary because ordering on
- * the isdn line is the the other way.
+ * the isdn line is the other way.
  */
 static __inline unsigned char
 FlipBits(unsigned char c, int keylen)
@@ -600,7 +600,7 @@
 					case ISDN_PROTO_L2_V11038:
 						dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize);
 						break;
-					default:
+					default:;
 				}
 				if ((v = dev->v110[idx])) {
 					while (v->SyncInit) {
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c
--- v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.c	Fri Nov 17 11:16:21 2000
+++ linux/drivers/isdn/isdnloop/isdnloop.c	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.11 2000/11/13 22:51:50 kai Exp $
+/* $Id: isdnloop.c,v 1.11.6.2 2001/02/16 16:43:32 kai Exp $
 
  * ISDN low-level module implementing a dummy loop driver.
  *
@@ -21,10 +21,12 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
 #include "isdnloop.h"
 
 static char
-*revision = "$Revision: 1.11 $";
+*revision = "$Revision: 1.11.6.2 $";
 
 static int isdnloop_addcard(char *);
 
@@ -975,7 +977,7 @@
  *   user = flag: 1 = called form userlevel, 0 called from kernel.
  *   card = pointer to card struct.
  * Return:
- *   number of bytes transfered (currently always equals len).
+ *   number of bytes transferred (currently always equals len).
  */
 static int
 isdnloop_writecmd(const u_char * buf, int len, int user, isdnloop_card * card)
@@ -1534,22 +1536,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-#define isdnloop_init init_module
-#else
-void
-isdnloop_setup(char *str, int *ints)
-{
-	static char sid[20];
-
-	if (strlen(str)) {
-		strcpy(sid, str);
-		isdnloop_id = sid;
-	}
-}
-#endif
-
-int
+static int __init
 isdnloop_init(void)
 {
 	char *p;
@@ -1568,9 +1555,8 @@
 	return (isdnloop_addcard(isdnloop_id));
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void __exit
+isdnloop_exit(void)
 {
 	isdn_ctrl cmd;
 	isdnloop_card *card = cards;
@@ -1598,4 +1584,6 @@
 	}
 	printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
 }
-#endif
+
+module_init(isdnloop_init);
+module_exit(isdnloop_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.h linux/drivers/isdn/isdnloop/isdnloop.h
--- v2.4.2/linux/drivers/isdn/isdnloop/isdnloop.h	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/isdnloop/isdnloop.h	Fri Mar  2 11:12:09 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.h,v 1.5 2000/11/13 22:51:50 kai Exp $
+/* $Id: isdnloop.h,v 1.5.6.1 2001/02/10 14:41:23 kai Exp $
 
  * Loopback lowlevel module for testing of linklevel.
  *
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c
--- v2.4.2/linux/drivers/isdn/pcbit/callbacks.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/pcbit/callbacks.c	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/callbacks.h linux/drivers/isdn/pcbit/callbacks.h
--- v2.4.2/linux/drivers/isdn/pcbit/callbacks.h	Tue Apr 23 02:31:35 1996
+++ linux/drivers/isdn/pcbit/callbacks.h	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c
--- v2.4.2/linux/drivers/isdn/pcbit/capi.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/pcbit/capi.c	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/capi.h linux/drivers/isdn/pcbit/capi.h
--- v2.4.2/linux/drivers/isdn/pcbit/capi.h	Sat Jun 29 10:36:22 1996
+++ linux/drivers/isdn/pcbit/capi.h	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c
--- v2.4.2/linux/drivers/isdn/pcbit/drv.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/pcbit/drv.c	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c
--- v2.4.2/linux/drivers/isdn/pcbit/edss1.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/pcbit/edss1.c	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/edss1.h linux/drivers/isdn/pcbit/edss1.h
--- v2.4.2/linux/drivers/isdn/pcbit/edss1.h	Tue Apr 23 02:31:35 1996
+++ linux/drivers/isdn/pcbit/edss1.h	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c
--- v2.4.2/linux/drivers/isdn/pcbit/layer2.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/isdn/pcbit/layer2.c	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/layer2.h linux/drivers/isdn/pcbit/layer2.h
--- v2.4.2/linux/drivers/isdn/pcbit/layer2.h	Mon Dec 11 13:21:16 2000
+++ linux/drivers/isdn/pcbit/layer2.h	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c
--- v2.4.2/linux/drivers/isdn/pcbit/module.c	Mon Aug 21 07:49:03 2000
+++ linux/drivers/isdn/pcbit/module.c	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
@@ -12,7 +12,7 @@
  */
 
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -26,21 +26,12 @@
 static int irq[MAX_PCBIT_CARDS] = {0, };
 
 static int num_boards;
-struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0};
-
-int init_module(void);
-void cleanup_module(void);
+struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, };
 
 extern void pcbit_terminate(int board);
 extern int pcbit_init_dev(int board, int mem_base, int irq);
 
-#ifdef MODULE
-MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
-#define pcbit_init init_module
-#endif
-
-int pcbit_init(void)
+static int __init pcbit_init(void)
 {
 	int board;
 
@@ -83,15 +74,10 @@
 		else
 			return -EIO;
 	}
-
-	/* No symbols to export, hide all symbols */
-	EXPORT_NO_SYMBOLS;
-
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit pcbit_exit(void)
 {
 	int board;
 
@@ -101,9 +87,8 @@
 	       "PCBIT-D module unloaded\n");
 }
 
-#else
+#ifndef MODULE
 #define MAX_PARA	(MAX_PCBIT_CARDS * 2)
-#include <linux/init.h>
 static int __init pcbit_setup(char *line)
 {
 	int i, j, argc;
@@ -134,5 +119,9 @@
 __setup("pcbit=", pcbit_setup);
 #endif
 
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
 
+module_init(pcbit_init);
+module_exit(pcbit_exit);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/pcbit/pcbit.h linux/drivers/isdn/pcbit/pcbit.h
--- v2.4.2/linux/drivers/isdn/pcbit/pcbit.h	Thu Nov 18 21:03:01 1999
+++ linux/drivers/isdn/pcbit/pcbit.h	Fri Mar  2 11:12:09 2001
@@ -4,7 +4,7 @@
  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
  *
  * This software may be used and distributed according to the terms of 
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  */
 
 /*        
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c
--- v2.4.2/linux/drivers/isdn/sc/init.c	Thu Oct 12 14:19:32 2000
+++ linux/drivers/isdn/sc/init.c	Fri Mar  2 11:12:10 2001
@@ -1,3 +1,5 @@
+#include <linux/module.h>
+#include <linux/init.h>
 #include "includes.h"
 #include "hardware.h"
 #include "card.h"
@@ -37,23 +39,12 @@
 	return 0;
 }
 
-#ifdef MODULE
 MODULE_PARM(io, "1-4i");
 MODULE_PARM(irq, "1-4i");
 MODULE_PARM(ram, "1-4i");
 MODULE_PARM(do_reset, "i");
-#define init_sc init_module
-#else
-/*
-Initialization code for non-module version to be included
 
-void sc_setup(char *str, int *ints)
-{
-}
-*/
-#endif
-
-int init_sc(void)
+static int __init sc_init(void)
 {
 	int b = -1;
 	int i, j;
@@ -410,8 +401,7 @@
 	return status;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit sc_exit(void)
 {
 	int i, j;
 
@@ -463,7 +453,6 @@
 	}
 	pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
 }
-#endif
 
 int identify_board(unsigned long rambase, unsigned int iobase) 
 {
@@ -579,3 +568,6 @@
 		
 	return -1;
 }
+
+module_init(sc_init);
+module_exit(sc_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/isdn/sc/interrupt.c linux/drivers/isdn/sc/interrupt.c
--- v2.4.2/linux/drivers/isdn/sc/interrupt.c	Wed Apr  1 16:21:04 1998
+++ linux/drivers/isdn/sc/interrupt.c	Fri Mar  2 11:12:10 2001
@@ -141,7 +141,7 @@
 			}
 			else if(callid>=0x0000 && callid<=0x7FFF)
 			{
-				pr_debug("%s: Got Incomming Call\n", adapter[card]->devicename);	
+				pr_debug("%s: Got Incoming Call\n", adapter[card]->devicename);	
 				strcpy(setup.phone,&(rcvmsg.msg_data.byte_array[4]));
 				strcpy(setup.eazmsn,adapter[card]->channel[rcvmsg.phy_link_no-1].dn);
 				setup.si1 = 7;
diff -u --recursive --new-file v2.4.2/linux/drivers/md/md.c linux/drivers/md/md.c
--- v2.4.2/linux/drivers/md/md.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/md/md.c	Mon Mar 12 18:13:28 2001
@@ -682,6 +682,8 @@
 	rdev->bdev = NULL;
 }
 
+void md_autodetect_dev (kdev_t dev);
+
 static void export_rdev (mdk_rdev_t * rdev)
 {
 	printk("export_rdev(%s)\n",partition_name(rdev->dev));
@@ -696,6 +698,9 @@
 		md_list_del(&rdev->pending);
 		MD_INIT_LIST_HEAD(&rdev->pending);
 	}
+#ifndef MODULE
+	md_autodetect_dev(rdev->dev);
+#endif
 	rdev->dev = 0;
 	rdev->faulty = 0;
 	kfree(rdev);
@@ -3525,6 +3530,7 @@
 int md__init md_init (void)
 {
 	static char * name = "mdrecoveryd";
+	int minor;
 	
 	printk (KERN_INFO "md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n",
 			MD_MAJOR_VERSION, MD_MINOR_VERSION,
@@ -3536,9 +3542,14 @@
 		return (-1);
 	}
 	devfs_handle = devfs_mk_dir (NULL, "md", NULL);
-	devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT,
-				MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR,
-				&md_fops, NULL);
+	/* we don't use devfs_register_series because we want to fill md_hd_struct */
+	for (minor=0; minor < MAX_MD_DEVS; ++minor) {
+		char devname[128];
+		sprintf (devname, "%u", minor);
+		md_hd_struct[minor].de = devfs_register (devfs_handle,
+			devname, DEVFS_FL_DEFAULT, MAJOR_NR, minor,
+			S_IFBLK | S_IRUSR | S_IWUSR, &md_fops, NULL);
+	}
 
 	/* forward all md request to md_make_request */
 	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request);
@@ -3581,10 +3592,10 @@
  * Searches all registered partitions for autorun RAID arrays
  * at boot time.
  */
-static int detected_devices[128] md__initdata;
+static int detected_devices[128];
 static int dev_cnt;
 
-void md_autodetect_dev(kdev_t dev)
+void md_autodetect_dev (kdev_t dev)
 {
 	if (dev_cnt >= 0 && dev_cnt < 127)
 		detected_devices[dev_cnt++] = dev;
@@ -3598,7 +3609,7 @@
 
 	printk(KERN_INFO "autodetecting RAID arrays\n");
 
-	for (i=0; i<dev_cnt; i++) {
+	for (i = 0; i < dev_cnt; i++) {
 		kdev_t dev = detected_devices[i];
 
 		if (md_import_device(dev,1)) {
@@ -3620,6 +3631,7 @@
 		}
 		md_list_add(&rdev->pending, &pending_raid_disks);
 	}
+	dev_cnt = 0;
 
 	autorun_devices(-1);
 }
@@ -3656,7 +3668,7 @@
 	kdev_t device;
 	char *devnames, *pername = "";
 
-	if(get_option(&str, &minor) != 2) {	/* MD Number */
+	if (get_option(&str, &minor) != 2) {	/* MD Number */
 		printk("md: Too few arguments supplied to md=.\n");
 		return 0;
 	}
@@ -3667,7 +3679,7 @@
 		printk ("md: Warning - md=%d,... has been specified twice;\n"
 			"    will discard the first definition.\n", minor);
 	}
-	switch(get_option(&str, &level)) {	/* RAID Personality */
+	switch (get_option(&str, &level)) {	/* RAID Personality */
 	case 2: /* could be 0 or -1.. */
 		if (level == 0 || level == -1) {
 			if (get_option(&str, &factor) != 2 ||	/* Chunk Size */
@@ -3820,7 +3832,6 @@
 		printk(KERN_INFO "skipping autodetection of RAID arrays\n");
 	else
 		autostart_arrays();
-	dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */
 	md_setup_drive();
 	return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in
--- v2.4.2/linux/drivers/media/radio/Config.in	Tue Sep 19 08:01:34 2000
+++ linux/drivers/media/radio/Config.in	Fri Mar  2 11:12:10 2001
@@ -21,6 +21,7 @@
 if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
    hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
 fi
+dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
 dep_tristate '  Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
 dep_tristate '  SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile
--- v2.4.2/linux/drivers/media/radio/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/media/radio/Makefile	Fri Mar  2 11:12:10 2001
@@ -31,6 +31,7 @@
 obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
 obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
 obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
+obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
 obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-aimslab.c linux/drivers/media/radio/radio-aimslab.c
--- v2.4.2/linux/drivers/media/radio/radio-aimslab.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-aimslab.c	Fri Mar  2 11:12:10 2001
@@ -308,20 +308,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void rt_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct rt_device rtrack_unit;
 
 static struct video_device rtrack_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"RadioTrack radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_RTRACK,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-aztech.c linux/drivers/media/radio/radio-aztech.c
--- v2.4.2/linux/drivers/media/radio/radio-aztech.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-aztech.c	Fri Mar  2 11:12:10 2001
@@ -259,20 +259,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void az_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct az_device aztech_unit;
 
 static struct video_device aztech_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"Aztech radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_AZTECH,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-cadet.c linux/drivers/media/radio/radio-cadet.c
--- v2.4.2/linux/drivers/media/radio/radio-cadet.c	Mon Nov 27 17:47:38 2000
+++ linux/drivers/media/radio/radio-cadet.c	Fri Mar  2 11:12:10 2001
@@ -16,6 +16,10 @@
  * 2000-04-29	Russell Kroll <rkroll@exploits.org>
  *		Added ISAPnP detection for Linux 2.3/2.4
  *
+ * 2001-01-10	Russell Kroll <rkroll@exploits.org>
+ *		Removed dead CONFIG_RADIO_CADET_PORT code
+ *		PnP detection on load is now default (no args necessary)
+ *
 */
 
 #include <linux/module.h>	/* Modules 			*/
@@ -25,16 +29,12 @@
 #include <asm/io.h>		/* outb, outb_p			*/
 #include <asm/uaccess.h>	/* copy to/from user		*/
 #include <linux/videodev.h>	/* kernel radio structs		*/
-#include <linux/config.h>	/* CONFIG_RADIO_CADET_PORT 	*/
 #include <linux/param.h>
 #include <linux/isapnp.h>
 
-#ifndef CONFIG_RADIO_CADET_PORT
-#define CONFIG_RADIO_CADET_PORT 0x330
-#endif
 #define RDS_BUFFER 256
 
-static int io=CONFIG_RADIO_CADET_PORT; 
+static int io=-1;		/* default to isapnp activation */
 static int users=0;
 static int curtuner=0;
 static int tunestat=0;
@@ -518,7 +518,6 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	init_waitqueue_head(&readq);
 	return 0;
 }
@@ -530,12 +529,12 @@
 		rdsstat=0;
 	}
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 
 static struct video_device cadet_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"Cadet radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_CADET,
@@ -587,6 +586,11 @@
 	return -1;
 }
 
+	/* 
+	 * io should only be set if the user has used something like
+	 * isapnp (the userspace program) to initialize this card for us
+	 */
+
 static int __init cadet_init(void)
 {
 	/*
@@ -626,6 +630,14 @@
 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
 MODULE_PARM(io, "i");
 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
+
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('M','S','M'), ISAPNP_FUNCTION(0x0c24), 0 },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
 
 EXPORT_NO_SYMBOLS;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-gemtek.c linux/drivers/media/radio/radio-gemtek.c
--- v2.4.2/linux/drivers/media/radio/radio-gemtek.c	Sat Dec 30 11:19:13 2000
+++ linux/drivers/media/radio/radio-gemtek.c	Fri Mar  2 11:12:10 2001
@@ -235,20 +235,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void gemtek_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct gemtek_device gemtek_unit;
 
 static struct video_device gemtek_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"GemTek radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_GEMTEK,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-maestro.c linux/drivers/media/radio/radio-maestro.c
--- v2.4.2/linux/drivers/media/radio/radio-maestro.c	Fri Nov 17 17:56:51 2000
+++ linux/drivers/media/radio/radio-maestro.c	Fri Mar  2 11:12:10 2001
@@ -69,6 +69,7 @@
 
 static struct video_device maestro_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"Maestro radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_SF16MI,
@@ -282,14 +283,12 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void radio_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-maxiradio.c linux/drivers/media/radio/radio-maxiradio.c
--- v2.4.2/linux/drivers/media/radio/radio-maxiradio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/radio-maxiradio.c	Fri Mar  2 11:12:10 2001
@@ -0,0 +1,388 @@
+/* 
+ * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux 
+ * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
+ *
+ * Based in the radio Maestro PCI driver. Actually it uses the same chip
+ * for radio but different pci controller.
+ *
+ * I didn't have any specs I reversed engineered the protocol from
+ * the windows driver (radio.dll). 
+ *
+ * The card uses the TEA5757 chip that includes a search function but it
+ * is useless as I haven't found any way to read back the frequency. If 
+ * anybody does please mail me.
+ *
+ * For the pdf file see:
+ * http://www.semiconductors.philips.com/pip/TEA5757H/V1
+ *
+ *
+ * CHANGES:
+ *   0.75b
+ *     - better pci interface thanks to Francois Romieu <romieu@cogenit.fr>
+ *
+ *   0.75
+ *     - tiding up
+ *     - removed support for multiple devices as it didn't work anyway
+ *
+ * BUGS: 
+ *   - card unmutes if you change frequency
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <linux/pci.h>
+#include <linux/videodev.h>
+
+/* version 0.75      Sun Feb  4 22:51:27 EET 2001 */
+#define DRIVER_VERSION	"0.75"
+
+#ifndef PCI_VENDOR_ID_GUILLEMOT
+#define PCI_VENDOR_ID_GUILLEMOT 0x5046
+#endif
+
+#ifndef PCI_DEVICE_ID_GUILLEMOT
+#define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
+#endif
+
+
+/* TEA5757 pin mappings */
+const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ;
+
+
+#define FREQ_LO		 50*16000
+#define FREQ_HI		150*16000
+
+#define FREQ_IF         171200 /* 10.7*16000   */
+#define FREQ_STEP       200    /* 12.5*16      */
+
+#define FREQ2BITS(x)	((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
+			/(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
+
+#define BITS2FREQ(x)	((x) * FREQ_STEP - FREQ_IF)
+
+
+static int radio_open(struct video_device *, int);
+static int radio_ioctl(struct video_device *, unsigned int, void *);
+static void radio_close(struct video_device *);
+
+static struct video_device maxiradio_radio=
+{
+	owner:		THIS_MODULE,
+	name:		"Maxi Radio FM2000 radio",
+	type:		VID_TYPE_TUNER,
+	hardware:	VID_HARDWARE_SF16MI,
+	open:		radio_open,
+	close:		radio_close,
+	ioctl:		radio_ioctl,
+};
+
+static struct radio_device
+{
+	__u16	io,	/* base of radio io */
+		muted,	/* VIDEO_AUDIO_MUTE */
+		stereo,	/* VIDEO_TUNER_STEREO_ON */	
+		tuned;	/* signal strength (0 or 0xffff) */
+		
+	unsigned long freq;
+	
+	struct  semaphore lock;
+} radio_unit = {0, 0, 0, 0, };
+
+
+static void sleep_125ms(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ >> 3);
+}
+
+
+static void outbit(unsigned long bit, __u16 io)
+{
+	if(bit != 0)
+		{
+			outb(  power|wren|data     ,io); udelay(4);
+			outb(  power|wren|data|clk ,io); udelay(4);
+			outb(  power|wren|data     ,io); udelay(4);
+		}
+	else	
+		{
+			outb(  power|wren          ,io); udelay(4);
+			outb(  power|wren|clk      ,io); udelay(4);
+			outb(  power|wren          ,io); udelay(4);
+		}
+}
+
+static void turn_power(__u16 io, int p)
+{
+	if(p != 0) outb(power, io); else outb(0,io);
+}
+
+
+static void set_freq(__u16 io, __u32 data)
+{
+	unsigned long int si;
+	int bl;
+	
+	/* TEA5757 shift register bits (see pdf) */
+
+	outbit(0,io); // 24  search 
+	outbit(1,io); // 23  search up/down
+	
+	outbit(0,io); // 22  stereo/mono
+
+	outbit(0,io); // 21  band
+	outbit(0,io); // 20  band (only 00=FM works I think)
+
+	outbit(0,io); // 19  port ?
+	outbit(0,io); // 18  port ?
+	
+	outbit(0,io); // 17  search level
+	outbit(0,io); // 16  search level
+ 
+	si = 0x8000;
+	for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
+	
+	outb(power,io);
+}
+
+static int get_stereo(__u16 io)
+{	
+	outb(power,io); udelay(4);
+	return !(inb(io) & mo_st);
+}
+
+static int get_tune(__u16 io)
+{	
+	outb(power+clk,io); udelay(4);
+	return !(inb(io) & mo_st);
+}
+
+
+inline static int radio_function(struct video_device *dev, 
+				 unsigned int cmd, void *arg)
+{
+	struct radio_device *card=dev->priv;
+	switch(cmd) {
+		case VIDIOCGCAP: {
+			struct video_capability v;
+			
+			strcpy(v.name, "Maxi Radio FM2000 radio");
+			v.type=VID_TYPE_TUNER;
+			v.channels=v.audios=1;
+			v.maxwidth=v.maxheight=v.minwidth=v.minheight=0;
+			
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+				
+			return 0;
+		}
+		case VIDIOCGTUNER: {
+			struct video_tuner v;
+			
+			if(copy_from_user(&v, arg,sizeof(v))!=0)
+				return -EFAULT;
+				
+			if(v.tuner)
+				return -EINVAL;
+				
+			card->stereo = 0xffff * get_stereo(card->io);
+			card->tuned = 0xffff * get_tune(card->io);
+			
+			v.flags = VIDEO_TUNER_LOW | card->stereo;
+			v.signal = card->tuned;
+			
+			strcpy(v.name, "FM");
+			
+			v.rangelow = FREQ_LO;
+			v.rangehigh = FREQ_HI;
+			v.mode = VIDEO_MODE_AUTO;
+			
+			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;
+				
+			return 0;
+		}
+		case VIDIOCGFREQ: {
+			unsigned long tmp=card->freq;
+			
+			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 ( tmp<FREQ_LO || tmp>FREQ_HI )
+				return -EINVAL;
+				
+			card->freq = tmp;
+			
+			set_freq(card->io, FREQ2BITS(card->freq));
+			sleep_125ms();
+
+			return 0;
+		}
+		case VIDIOCGAUDIO: {	
+			struct video_audio v;
+			strcpy(v.name, "Radio");
+			v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0;
+			v.flags=VIDEO_AUDIO_MUTABLE | card->muted;
+			v.mode=VIDEO_SOUND_STEREO;
+			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;
+				
+			
+			card->muted = v.flags & VIDEO_AUDIO_MUTE;
+				
+			if(card->muted)
+				turn_power(card->io, 0);
+			else
+				set_freq(card->io, FREQ2BITS(card->freq));
+				
+			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;
+			v.teletext=VIDEO_NO_UNIT;
+			if(copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;		
+		}
+		default: return -ENOIOCTLCMD;
+	}
+}
+
+static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct radio_device *card=dev->priv;
+	int ret;
+	down(&card->lock);
+	ret = radio_function(dev, cmd, arg);
+	up(&card->lock);
+	return ret;
+}
+
+static int radio_open(struct video_device *dev, int flags)
+{
+	return 0;
+}
+
+static void radio_close(struct video_device *dev)
+{
+}
+
+MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
+
+EXPORT_NO_SYMBOLS;
+
+static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	if(!request_region(pci_resource_start(pdev, 0),
+	                   pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+	        printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+	        goto err_out;
+	}
+
+	if (pci_enable_device(pdev))
+	        goto err_out_free_region;
+
+	radio_unit.io = pci_resource_start(pdev, 0);
+	init_MUTEX(&radio_unit.lock);
+	maxiradio_radio.priv = &radio_unit;
+
+	if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO)==-1) {
+	        printk("radio-maxiradio: can't register device!");
+	        goto err_out_free_region;
+	}
+
+	printk(KERN_INFO "radio-maxiradio: version "
+	       DRIVER_VERSION
+	       " time "
+	       __TIME__ "  "
+	       __DATE__
+	       "\n");
+
+	printk(KERN_INFO "radio-maxiradio: found Guillemot MAXI Radio device (io = 0x%x)\n",
+	       radio_unit.io);
+	return 0;
+
+err_out_free_region:
+	release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+err_out:
+	return -ENODEV;
+}
+
+static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
+{
+	video_unregister_device(&maxiradio_radio);
+	release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+}
+
+static struct pci_device_id maxiradio_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0,}
+};
+
+MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
+
+static struct pci_driver maxiradio_driver = {
+	name:		"radio-maxiradio",
+	id_table:	maxiradio_pci_tbl,
+	probe:		maxiradio_init_one,
+	remove:		maxiradio_remove_one,
+};
+
+int __init maxiradio_radio_init(void)
+{
+	return pci_module_init(&maxiradio_driver);
+}
+
+void __exit maxiradio_radio_exit(void)
+{
+	pci_unregister_driver(&maxiradio_driver);
+}
+
+module_init(maxiradio_radio_init);
+module_exit(maxiradio_radio_exit);
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-miropcm20.c linux/drivers/media/radio/radio-miropcm20.c
--- v2.4.2/linux/drivers/media/radio/radio-miropcm20.c	Fri Nov 17 17:56:51 2000
+++ linux/drivers/media/radio/radio-miropcm20.c	Fri Mar  2 11:12:10 2001
@@ -178,20 +178,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void pcm20_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct pcm20_device pcm20_unit;
 
 static struct video_device pcm20_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"Miro PCM 20 radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_RTRACK,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-rtrack2.c linux/drivers/media/radio/radio-rtrack2.c
--- v2.4.2/linux/drivers/media/radio/radio-rtrack2.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-rtrack2.c	Fri Mar  2 11:12:10 2001
@@ -201,20 +201,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void rt_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct rt_device rtrack2_unit;
 
 static struct video_device rtrack2_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"RadioTrack II radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_RTRACK2,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c
--- v2.4.2/linux/drivers/media/radio/radio-sf16fmi.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-sf16fmi.c	Fri Mar  2 11:12:10 2001
@@ -41,7 +41,7 @@
 static struct semaphore lock;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
-/* It is only usefull to give freq in intervall of 800 (=0.05Mhz),
+/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
  * other bits will be truncated, e.g 92.7400016 -> 92.7, but 
  * 92.7400017 -> 92.75
  */
@@ -262,20 +262,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void fmi_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct fmi_device fmi_unit;
 
 static struct video_device fmi_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"SF16FMx radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_SF16MI,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-terratec.c linux/drivers/media/radio/radio-terratec.c
--- v2.4.2/linux/drivers/media/radio/radio-terratec.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-terratec.c	Fri Mar  2 11:12:10 2001
@@ -280,20 +280,19 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void tt_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct tt_device terratec_unit;
 
 static struct video_device terratec_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"TerraTec ActiveRadio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_TERRATEC,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-trust.c linux/drivers/media/radio/radio-trust.c
--- v2.4.2/linux/drivers/media/radio/radio-trust.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-trust.c	Fri Mar  2 11:12:10 2001
@@ -274,18 +274,17 @@
 	if(users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void tr_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct video_device trust_radio=
 {
+	owner:		THIS_MODULE,
 	name:		"Trust FM Radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_TRUST,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-typhoon.c linux/drivers/media/radio/radio-typhoon.c
--- v2.4.2/linux/drivers/media/radio/radio-typhoon.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-typhoon.c	Fri Mar  2 11:12:10 2001
@@ -260,7 +260,6 @@
 	if (typhoon->users)
 		return -EBUSY;
 	typhoon->users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -268,7 +267,6 @@
 {
 	struct typhoon_device *typhoon = dev->priv;
 	typhoon->users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct typhoon_device typhoon_unit =
@@ -280,6 +278,7 @@
 
 static struct video_device typhoon_radio =
 {
+	owner:		THIS_MODULE,
 	name:		"Typhoon Radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_TYPHOON,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/radio/radio-zoltrix.c linux/drivers/media/radio/radio-zoltrix.c
--- v2.4.2/linux/drivers/media/radio/radio-zoltrix.c	Mon Jan  1 10:14:31 2001
+++ linux/drivers/media/radio/radio-zoltrix.c	Fri Mar  2 11:12:10 2001
@@ -327,20 +327,19 @@
 	if (users)
 		return -EBUSY;
 	users++;
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void zol_close(struct video_device *dev)
 {
 	users--;
-	MOD_DEC_USE_COUNT;
 }
 
 static struct zol_device zoltrix_unit;
 
 static struct video_device zoltrix_radio =
 {
+	owner:		THIS_MODULE,
 	name:		"Zoltrix Radio Plus",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_ZOLTRIX,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.4.2/linux/drivers/media/video/bttv-driver.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/bttv-driver.c	Fri Mar  2 11:12:10 2001
@@ -1352,7 +1352,6 @@
 	if (bttv_debug)
 		printk("bttv%d: open called\n",btv->nr);
 
-	MOD_INC_USE_COUNT;
 	down(&btv->lock);
 	if (btv->user)
 		goto out_unlock;
@@ -1378,7 +1377,6 @@
 
  out_unlock:
 	up(&btv->lock);
-	MOD_DEC_USE_COUNT;
 	return ret;
 }
 
@@ -1423,7 +1421,6 @@
 		rvfree((void *) btv->fbuffer, gbuffers*gbufsize);
 	btv->fbuffer=0;
 	up(&btv->lock);
-	MOD_DEC_USE_COUNT;  
 }
 
 
@@ -2053,6 +2050,7 @@
 
 static struct video_device bttv_template=
 {
+	owner:		THIS_MODULE,
 	name:		"UNSET",
 	type:		VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT,
 	hardware:	VID_HARDWARE_BT848,
@@ -2140,7 +2138,6 @@
 	struct bttv *btv=(struct bttv *)(dev-2);
  	unsigned long irq_flags;
 
-	MOD_INC_USE_COUNT;
         down(&btv->lock);
 	if (btv->needs_restart)
 		bt848_restart(btv);
@@ -2164,7 +2161,6 @@
 	btv->vbi_on = 0;
 	bt848_set_risc_jmps(btv,-1);
 	spin_unlock_irqrestore(&btv->s_lock, irq_flags);
-	MOD_DEC_USE_COUNT;  
 }
 
 static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -2202,6 +2198,7 @@
 
 static struct video_device vbi_template=
 {
+	owner:		THIS_MODULE,
 	name:		"bttv vbi",
 	type:		VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
 	hardware:	VID_HARDWARE_BT848,
@@ -2220,7 +2217,6 @@
 	struct bttv *btv = (struct bttv *)(dev-1);
 	unsigned long v;
 
-	MOD_INC_USE_COUNT;
         down(&btv->lock);
 	if (btv->user)
 		goto busy_unlock;
@@ -2237,7 +2233,6 @@
 
  busy_unlock:
 	up(&btv->lock);
-	MOD_DEC_USE_COUNT;
 	return -EBUSY;
 }
 
@@ -2249,7 +2244,6 @@
 	btv->user--;
 	btv->radio = 0;
 	up(&btv->lock);
-	MOD_DEC_USE_COUNT;  
 }
 
 static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
@@ -2320,6 +2314,7 @@
 
 static struct video_device radio_template=
 {
+	owner:		THIS_MODULE,
 	name:		"bttv radio",
 	type:		VID_TYPE_TUNER,
 	hardware:	VID_HARDWARE_BT848,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- v2.4.2/linux/drivers/media/video/bttv.h	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/bttv.h	Tue Mar  6 19:44:34 2001
@@ -151,7 +151,7 @@
 
 /* returns card type + card ID (for bt878-based ones)
    for possible values see lines below beginning with #define BTTV_UNKNOWN
-   returns negative value if error ocurred 
+   returns negative value if error occurred 
 */
 extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
 
@@ -160,19 +160,19 @@
 
 /* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
    data | (current_GPOE_value & ~mask)
-   returns negative value if error ocurred
+   returns negative value if error occurred
 */
 extern int bttv_gpio_enable(unsigned int card,
 			    unsigned long mask, unsigned long data);
 
 /* fills data with GPDATA register contents
-   returns negative value if error ocurred
+   returns negative value if error occurred
 */
 extern int bttv_read_gpio(unsigned int card, unsigned long *data);
 
 /* sets GPDATA register to new value:
   (data & mask) | (current_GPDATA_value & ~mask)
-  returns negative value if error ocurred 
+  returns negative value if error occurred 
 */
 extern int bttv_write_gpio(unsigned int card,
 			   unsigned long mask, unsigned long data);
@@ -182,7 +182,7 @@
    in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated
    (wake_up_interruptible) and following call to the function bttv_read_gpio 
    should return new value of GPDATA,
-   returns NULL value if error ocurred or queue is not available
+   returns NULL value if error occurred or queue is not available
    WARNING: because there is no buffer for GPIO data, one MUST 
    process data ASAP
 */
@@ -190,6 +190,9 @@
 
 /* i2c */
 #define I2C_CLIENTS_MAX 8
+extern struct i2c_algo_bit_data bttv_i2c_algo_template;
+extern struct i2c_adapter bttv_i2c_adap_template;
+extern struct i2c_client bttv_i2c_client_template;
 extern void bttv_bit_setscl(void *data, int state);
 extern void bttv_bit_setsda(void *data, int state);
 extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c
--- v2.4.2/linux/drivers/media/video/buz.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/buz.c	Tue Mar  6 19:44:35 2001
@@ -1,4 +1,3 @@
-#define MAX_KMALLOC_MEM (512*1024)
 /*
    buz - Iomega Buz driver version 1.0
 
@@ -114,12 +113,12 @@
    or set in in a VIDIOCSFBUF ioctl
  */
 
-static unsigned long vidmem = 0;	/* Video memory base address */
+static unsigned long vidmem;	/* Video memory base address (default 0) */
 
 /* Special purposes only: */
 
-static int triton = 0;		/* 0=no, 1=yes */
-static int natoma = 0;		/* 0=no, 1=yes */
+static int triton;		/* 0=no (default), 1=yes */
+static int natoma;		/* 0=no (default), 1=yes */
 
 /*
    Number and size of grab buffers for Video 4 Linux
@@ -145,8 +144,8 @@
    Default input and video norm at startup of the driver.
  */
 
-static int default_input = 0;	/* 0=Composite, 1=S-VHS */
-static int default_norm = 0;	/* 0=PAL, 1=NTSC */
+static int default_input;	/* 0=Composite (default), 1=S-VHS */
+static int default_norm;	/* 0=PAL (default), 1=NTSC */
 
 MODULE_PARM(vidmem, "i");
 MODULE_PARM(triton, "i");
@@ -174,7 +173,7 @@
  *   Allocate the V4L grab buffers
  *
  *   These have to be pysically contiguous.
- *   If v4l_bufsize <= MAX_KMALLOC_MEM we use kmalloc
+ *   If v4l_bufsize <= KMALLOC_MAXSIZE we use kmalloc
  */
 
 static int v4l_fbuffer_alloc(struct zoran *zr)
@@ -186,7 +185,7 @@
 		if (zr->v4l_gbuf[i].fbuffer)
 			printk(KERN_WARNING "%s: v4l_fbuffer_alloc: buffer %d allready allocated ?\n", zr->name, i);
 
-		if (v4l_bufsize <= MAX_KMALLOC_MEM) {
+		if (v4l_bufsize <= KMALLOC_MAXSIZE) {
 			/* Use kmalloc */
 
 			mem = (unsigned char *) kmalloc(v4l_bufsize, GFP_KERNEL);
@@ -231,7 +230,7 @@
 /*
  *   Allocate the MJPEG grab buffers.
  *
- *   If the requested buffer size is smaller than MAX_KMALLOC_MEM,
+ *   If the requested buffer size is smaller than KMALLOC_MAXSIZE,
  *   kmalloc is used to request a physically contiguous area,
  *   else we allocate the memory in framgents with get_free_page.
  *
@@ -240,7 +239,7 @@
  *   (RJ: This statement is from Dave Perks' original driver,
  *   I could never check it because I have a zr36067)
  *   The driver cares about this because it reduces the buffer
- *   size to MAX_KMALLOC_MEM in that case (which forces contiguous allocation).
+ *   size to KMALLOC_MAXSIZE in that case (which forces contiguous allocation).
  *
  *   RJ: The contents grab buffers needs never be accessed in the driver.
  *       Therefore there is no need to allocate them with vmalloc in order
@@ -260,7 +259,7 @@
 	/* Decide if we should alloc contiguous or fragmented memory */
 	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
 
-	alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM);
+	alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE);
 
 	for (i = 0; i < zr->jpg_nbufs; i++) {
 		if (zr->jpg_gbuf[i].frag_tab)
@@ -320,7 +319,7 @@
 	/* Decide if we should alloc contiguous or fragmented memory */
 	/* This has to be identical in jpg_fbuffer_alloc and jpg_fbuffer_free */
 
-	alloc_contig = (zr->jpg_bufsize < MAX_KMALLOC_MEM);
+	alloc_contig = (zr->jpg_bufsize < KMALLOC_MAXSIZE);
 
 	for (i = 0; i < zr->jpg_nbufs; i++) {
 		if (!zr->jpg_gbuf[i].frag_tab)
@@ -388,21 +387,16 @@
 	DEBUG(printk(BUZ_DEBUG "-%u: i2c detach %02x\n", zr->id, id));
 }
 
-static struct i2c_bus zoran_i2c_bus_template =
-{
-	"zr36057",
-	I2C_BUSID_BT848,
-	NULL,
-
-	SPIN_LOCK_UNLOCKED,
+static struct i2c_bus zoran_i2c_bus_template = {
+	name:			"zr36057",
+	id:			I2C_BUSID_BT848,
+	bus_lock:		SPIN_LOCK_UNLOCKED,
 
-	attach_inform,
-	detach_inform,
+	attach_inform:		attach_inform,
+	detach_inform:		detach_inform,
 
-	i2c_setlines,
-	i2c_getdataline,
-	NULL,
-	NULL,
+	i2c_setlines:		i2c_setlines,
+	i2c_getdataline:	i2c_getdataline,
 };
 
 
@@ -2267,7 +2261,6 @@
 		return -EBUSY;
 
 	}
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -2295,7 +2288,6 @@
 	jpg_fbuffer_free(zr);
 	zr->jpg_nbufs = 0;
 
-	MOD_DEC_USE_COUNT;
 	DEBUG(printk(KERN_INFO ": zoran_close done\n"));
 }
 
@@ -2580,7 +2572,7 @@
 #endif
 #endif
 
-			/* Check for vaild parameters */
+			/* Check for valid parameters */
 			if (vw.width < BUZ_MIN_WIDTH || vw.height < BUZ_MIN_HEIGHT ||
 			    vw.width > BUZ_MAX_WIDTH || vw.height > BUZ_MAX_HEIGHT) {
 				return -EINVAL;
@@ -2842,8 +2834,8 @@
 			/* br.size is limited by 1 page for the stat_com tables to a Maximum of 2 MB */
 			if (br.size > (512 * 1024))
 				br.size = (512 * 1024);		/* 512 K should be enough */
-			if (zr->need_contiguous && br.size > MAX_KMALLOC_MEM)
-				br.size = MAX_KMALLOC_MEM;
+			if (zr->need_contiguous && br.size > KMALLOC_MAXSIZE)
+				br.size = KMALLOC_MAXSIZE;
 
 			zr->jpg_nbufs = br.count;
 			zr->jpg_bufsize = br.size;
@@ -3029,6 +3021,7 @@
 
 static struct video_device zoran_template =
 {
+	owner:		THIS_MODULE,
 	name:		BUZ_NAME,
 	type:		VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
 			VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE,
@@ -3343,7 +3336,7 @@
 		zr->zr36057_mem = ioremap(zr->zr36057_adr, 0x1000);
 		if (!zr->zr36057_mem) {
 			printk(KERN_ERR "%s: ioremap failed\n", zr->name);
-			/* XXX handle error */
+			break;
 		}
 
 		/* set PCI latency timer */
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/bw-qcam.c linux/drivers/media/video/bw-qcam.c
--- v2.4.2/linux/drivers/media/video/bw-qcam.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/bw-qcam.c	Fri Mar  2 11:12:10 2001
@@ -696,13 +696,11 @@
 
 static int qcam_open(struct video_device *dev, int flags)
 {
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void qcam_close(struct video_device *dev)
 {
-	MOD_DEC_USE_COUNT;
 }
 
 static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
@@ -918,6 +916,7 @@
  
 static struct video_device qcam_template=
 {
+	owner:		THIS_MODULE,
 	name:		"Connectix Quickcam",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_QCAM_BW,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c
--- v2.4.2/linux/drivers/media/video/c-qcam.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/c-qcam.c	Fri Mar  2 11:12:10 2001
@@ -500,13 +500,11 @@
 
 static int qcam_open(struct video_device *dev, int flags)
 {
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void qcam_close(struct video_device *dev)
 {
-	MOD_DEC_USE_COUNT;
 }
 
 static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
@@ -725,6 +723,7 @@
 /* video device template */
 static struct video_device qcam_template=
 {
+	owner:		THIS_MODULE,
 	name:		"Colour QuickCam",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_QCAM_C,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- v2.4.2/linux/drivers/media/video/cpia.c	Fri Nov 17 17:56:51 2000
+++ linux/drivers/media/video/cpia.c	Fri Mar  2 11:12:10 2001
@@ -2499,9 +2499,6 @@
 	cam->mmap_kludge = 0;
 	
 	++cam->open_count;
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
 	return 0;
 }
 
@@ -2554,9 +2551,6 @@
 	}
 	
 
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
 	return;
 }
 
@@ -3031,6 +3025,7 @@
 }
 
 static struct video_device cpia_template = {
+	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_CPIA,      /* FIXME */
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/cpia.h linux/drivers/media/video/cpia.h
--- v2.4.2/linux/drivers/media/video/cpia.h	Mon Dec 11 13:15:37 2000
+++ linux/drivers/media/video/cpia.h	Fri Mar  2 11:12:10 2001
@@ -62,7 +62,7 @@
 	/* transferCmd sends commands to the camera.  command MUST point to
 	 * an  8 byte buffer in kernel space. data can be NULL if no extra
 	 * data is needed.  The size of the data is given by the last 2
-	 * bytes of comand.  data must also point to memory in kernel space.
+	 * bytes of command.  data must also point to memory in kernel space.
 	 * Returns negative value on error, otherwise 0.
 	 */
 	int (*transferCmd)(void *privdata, u8 *command, u8 *data);
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c
--- v2.4.2/linux/drivers/media/video/cpia_pp.c	Mon Mar 27 10:22:31 2000
+++ linux/drivers/media/video/cpia_pp.c	Fri Mar  2 11:12:10 2001
@@ -34,9 +34,7 @@
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif
 
 /* #define _CPIA_DEBUG_		define for verbose debug output */
 #include "cpia.h"
@@ -502,9 +500,6 @@
 	
 	++cam->open_count;
 	
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif
 	return 0;
 }
 
@@ -535,9 +530,6 @@
 static int cpia_pp_close(void *privdata)
 {
 	struct pp_cam_entry *cam = privdata;
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
 	if (--cam->open_count == 0) {
 		parport_release(cam->pdev);
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c
--- v2.4.2/linux/drivers/media/video/msp3400.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/msp3400.c	Tue Mar  6 19:44:35 2001
@@ -1189,7 +1189,7 @@
 	DECLARE_MUTEX_LOCKED(sem);
 	struct msp3400c *msp;
         struct i2c_client *c;
-	int              rev1,rev2,i;
+	int              rev1,rev2=0,i;
 
         client_template.adapter = adap;
         client_template.addr = addr;
@@ -1517,7 +1517,7 @@
 			 (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c));
 		break;
 #endif
-	default:
+	default:;
 		/* nothing */
 	}
 	return 0;
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/planb.c linux/drivers/media/video/planb.c
--- v2.4.2/linux/drivers/media/video/planb.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/planb.c	Fri Mar  2 11:12:10 2001
@@ -2037,6 +2037,7 @@
 
 static struct video_device planb_template=
 {
+	owner:		THIS_MODULE,
 	name:		PLANB_DEVICE_NAME,
 	type:		VID_TYPE_OVERLAY,
 	hardware:	VID_HARDWARE_PLANB,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/pms.c linux/drivers/media/video/pms.c
--- v2.4.2/linux/drivers/media/video/pms.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/pms.c	Fri Mar  2 11:12:10 2001
@@ -672,13 +672,11 @@
 
 static int pms_open(struct video_device *dev, int flags)
 {
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void pms_close(struct video_device *dev)
 {
-	MOD_DEC_USE_COUNT;
 }
 
 static long pms_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
@@ -902,6 +900,7 @@
  
 struct video_device pms_template=
 {
+	owner:		THIS_MODULE,
 	name:		"Mediavision PMS",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_PMS,
@@ -935,14 +934,15 @@
 		0xE4
 	};
 	
-	if(check_region(0x9A01,1))
+	if (!request_region(0x9A01, 1, "Mediavision PMS config"))
 	{
 		printk(KERN_WARNING "mediavision: unable to detect: 0x9A01 in use.\n");
 		return -EBUSY;
 	}
-	if(check_region(io_port,3))
+	if (!request_region(io_port, 3, "Mediavision PMS"))
 	{
 		printk(KERN_WARNING "mediavision: I/O port %d in use.\n", io_port);
+		release_region(0x9A01, 1);
 		return -EBUSY;
 	}
 	outb(0xB8, 0x9A01);		/* Unlock */
@@ -961,16 +961,16 @@
 	else 
 		idec=0;
 
-	printk(KERN_INFO "PMS type is %d\n", idec);		
-	if(idec==0)
-		return -ENODEV;	
+	printk(KERN_INFO "PMS type is %d\n", idec);
+	if(idec == 0) {
+		release_region(io_port, 3);
+		release_region(0x9A01, 1);
+		return -ENODEV;
+	}
 
 	/*
 	 *	Ok we have a PMS of some sort
 	 */
-	 
-	request_region(io_port,3, "Mediavision PMS");
-	request_region(0x9A01, 1, "Mediavision PMS config");
 	
 	mvv_write(0x04, mem_base>>12);	/* Set the memory area */
 	
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/stradis.c linux/drivers/media/video/stradis.c
--- v2.4.2/linux/drivers/media/video/stradis.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/stradis.c	Fri Mar  2 11:12:10 2001
@@ -672,7 +672,7 @@
 		/* auto mute off, power on, no de-emphasis */
 		/* I2S data up to 24-bit 64xFs internal SCLK */
 		I2CWrite(&(saa->i2c), 0x22, 0x01, 0x11, 2);
-		/* ATAPI mixer setings */
+		/* ATAPI mixer settings */
 		I2CWrite(&(saa->i2c), 0x22, 0x02, 0x49, 2);
 		/* attenuation left 3db */
 		I2CWrite(&(saa->i2c), 0x22, 0x03, 0x00, 2);
@@ -1988,6 +1988,7 @@
 /* template for video_device-structure */
 static struct video_device saa_template =
 {
+	owner:		THIS_MODULE,
 	name:		"SAA7146A",
 	type:		VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
 	hardware:	VID_HARDWARE_SAA7146,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- v2.4.2/linux/drivers/media/video/videodev.c	Tue Jan  2 16:45:37 2001
+++ linux/drivers/media/video/videodev.c	Fri Mar  2 11:12:10 2001
@@ -166,6 +166,9 @@
 		goto error_out;
 	}
 	vfl->busy=1;		/* In case vfl->open sleeps */
+	
+	if(vfl->owner)
+		__MOD_INC_USE_COUNT(vfl->owner);
 	unlock_kernel();
 	
 	if(vfl->open)
@@ -174,6 +177,9 @@
 		if(err)
 		{
 			vfl->busy=0;
+			if(vfl->owner)
+				__MOD_DEC_USE_COUNT(vfl->owner);
+			
 			return err;
 		}
 	}
@@ -195,6 +201,8 @@
 	if(vfl->close)
 		vfl->close(vfl);
 	vfl->busy=0;
+	if(vfl->owner)
+		__MOD_DEC_USE_COUNT(vfl->owner);
 	unlock_kernel();
 	return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/vino.c linux/drivers/media/video/vino.c
--- v2.4.2/linux/drivers/media/video/vino.c	Fri Nov 17 17:56:51 2000
+++ linux/drivers/media/video/vino.c	Fri Mar  2 11:12:10 2001
@@ -203,13 +203,11 @@
 
 static int vino_open(struct video_device *dev, int flags)
 {
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static void vino_close(struct video_device *dev)
 {
-	MOD_DEC_USE_COUNT;
 }
 
 static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
@@ -224,6 +222,7 @@
 }
 
 static struct video_device vino_dev = {
+	owner:		THIS_MODULE,
 	name:		"Vino IndyCam/TV",
 	type:		VID_TYPE_CAPTURE,
 	hardware:	VID_HARDWARE_VINO,
diff -u --recursive --new-file v2.4.2/linux/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c
--- v2.4.2/linux/drivers/media/video/zr36120.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/media/video/zr36120.c	Fri Mar  2 11:12:10 2001
@@ -788,7 +788,6 @@
 	/* do the common part of all open's */
 	zoran_common_open(ztv, flags);
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -820,7 +819,6 @@
 		kfree( ztv->overinfo.overlay );
 	ztv->overinfo.overlay = 0;
 
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1482,6 +1480,7 @@
 
 static struct video_device zr36120_template=
 {
+	owner:		THIS_MODULE,
 	name:		"UNSET",
 	type:		VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY,
 	hardware:	VID_HARDWARE_ZR36120,
@@ -1541,7 +1540,6 @@
 	/* start read-ahead */
 	zoran_cap(ztv, 1);
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -1573,7 +1571,6 @@
 		item->memadr = 0;
 	}
 
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1819,6 +1816,7 @@
 
 static struct video_device vbi_template=
 {
+	owner:		THIS_MODULE,
 	name:		"UNSET",
 	type:		VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
 	hardware:	VID_HARDWARE_ZR36120,
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c503.c linux/drivers/net/3c503.c
--- v2.4.2/linux/drivers/net/3c503.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/net/3c503.c	Tue Mar  6 19:28:33 2001
@@ -53,8 +53,8 @@
 #define WRD_COUNT 4
 
 int el2_probe(struct net_device *dev);
-int el2_pio_probe(struct net_device *dev);
-int el2_probe1(struct net_device *dev, int ioaddr);
+static int el2_pio_probe(struct net_device *dev);
+static int el2_probe1(struct net_device *dev, int ioaddr);
 
 /* A zero-terminated list of I/O addresses to be probed in PIO mode. */
 static unsigned int netcard_portlist[] __initdata =
@@ -115,7 +115,7 @@
 
 /*  Try all of the locations that aren't obviously empty.  This touches
     a lot of locations, and is much riskier than the code above. */
-int __init 
+static int __init 
 el2_pio_probe(struct net_device *dev)
 {
     int i;
@@ -136,13 +136,14 @@
 /* Probe for the Etherlink II card at I/O port base IOADDR,
    returning non-zero on success.  If found, set the station
    address and memory parameters in DEVICE. */
-int __init 
+static int __init 
 el2_probe1(struct net_device *dev, int ioaddr)
 {
     int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
     static unsigned version_printed;
     unsigned long vendor_id;
 
+    /* FIXME: code reads ioaddr + 0x400, we request ioaddr + 16 */
     if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name))
 	return -EBUSY;
 
@@ -250,7 +251,8 @@
 	}
 #endif  /* EL2MEMTEST */
 
-	dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
+	if (dev->mem_start)
+		dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
 
 	if (wordlength) {	/* No Tx pages to skip over to get to Rx */
 		dev->rmem_start = dev->mem_start;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v2.4.2/linux/drivers/net/3c505.c	Wed Feb 21 18:20:24 2001
+++ linux/drivers/net/3c505.c	Tue Mar 20 12:05:00 2001
@@ -601,15 +601,16 @@
 		printk("%s: memory squeeze, dropping packet\n", dev->name);
 		target = adapter->dma_buffer;
 		adapter->current_dma.target = NULL;
+		return;
+	}
+
+	skb_reserve(skb, 2);
+	target = skb_put(skb, rlen);
+	if (virt_to_bus(target + rlen) >= MAX_DMA_ADDRESS) {
+		adapter->current_dma.target = target;
+		target = adapter->dma_buffer;
 	} else {
-		skb_reserve(skb, 2);
-		target = skb_put(skb, rlen);
-		if (virt_to_bus(target + rlen) >= MAX_DMA_ADDRESS) {
-			adapter->current_dma.target = target;
-			target = adapter->dma_buffer;
-		} else {
-			adapter->current_dma.target = NULL;
-		}
+		adapter->current_dma.target = NULL;
 	}
 
 	/* if this happens, we die */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.4.2/linux/drivers/net/3c509.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/3c509.c	Mon Mar 12 18:13:28 2001
@@ -72,9 +72,9 @@
 #include <asm/irq.h>
 
 #ifdef EL3_DEBUG
-int el3_debug = EL3_DEBUG;
+static int el3_debug = EL3_DEBUG;
 #else
-int el3_debug = 2;
+static int el3_debug = 2;
 #endif
 
 /* To minimize the size of the driver source I only define operating
@@ -158,7 +158,7 @@
 	int id;
 };
 
-struct el3_mca_adapters_struct el3_mca_adapters[] = {
+static struct el3_mca_adapters_struct el3_mca_adapters[] = {
 	{ "3Com 3c529 EtherLink III (10base2)", 0x627c },
 	{ "3Com 3c529 EtherLink III (10baseT)", 0x627d },
 	{ "3Com 3c529 EtherLink III (test mode)", 0x62db },
@@ -166,27 +166,36 @@
 	{ "3Com 3c529 EtherLink III (TP)", 0x62f7 },
 	{ NULL, 0 },
 };
-#endif
+#endif /* CONFIG_MCA */
 
-#ifdef __ISAPNP__
-struct el3_isapnp_adapters_struct {
-	unsigned short vendor, function;
-	char *name;
-};
-static struct el3_isapnp_adapters_struct el3_isapnp_adapters[] = {
-	{ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090), "3Com Etherlink III (TP)"},
-	{ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091), "3Com Etherlink III"},
-	{ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094), "3Com Etherlink III (combo)"},
-	{ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095), "3Com Etherlink III (TPO)"},
-	{ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098), "3Com Etherlink III (TPC)"},
-	{ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8), "3Com Etherlink III compatible"},
-	{0, }
+#ifdef CONFIG_ISAPNP
+static struct isapnp_device_id el3_isapnp_adapters[] = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
+		(long) "3Com Etherlink III (TP)" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5091),
+		(long) "3Com Etherlink III" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5094),
+		(long) "3Com Etherlink III (combo)" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5095),
+		(long) "3Com Etherlink III (TPO)" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098),
+		(long) "3Com Etherlink III (TPC)" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8),
+		(long) "3Com Etherlink III compatible" },
+	{ }	/* terminate list */
 };
+
+MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
+
 static u16 el3_isapnp_phys_addr[8][3];
-#endif /* CONFIG_ISAPNP */
-#ifdef __ISAPNP__
 static int nopnp;
-#endif
+#endif /* CONFIG_ISAPNP */
 
 int el3_probe(struct net_device *dev)
 {
@@ -196,9 +205,9 @@
 	u16 phys_addr[3];
 	static int current_tag = 0;
 	int mca_slot = -1;
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 	static int pnp_cards = 0;
-#endif /* __ISAPNP__ */
+#endif /* CONFIG_ISAPNP */
 
 	if (dev) SET_MODULE_OWNER(dev);
 
@@ -294,7 +303,7 @@
 	}
 #endif /* CONFIG_MCA */
 
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 	if (nopnp == 1)
 		goto no_pnp;
 
@@ -318,7 +327,7 @@
 			irq = idev->irq_resource[0].start;
 			if (el3_debug > 3)
 				printk ("ISAPnP reports %s at i/o 0x%x, irq %d\n",
-					el3_isapnp_adapters[i].name, ioaddr, irq);
+					(char*) el3_isapnp_adapters[i].driver_data, ioaddr, irq);
 			EL3WINDOW(0);
 			for (j = 0; j < 3; j++)
 				el3_isapnp_phys_addr[pnp_cards][j] =
@@ -330,7 +339,7 @@
 		}
 	}
 no_pnp:
-#endif /* __ISAPNP__ */
+#endif /* CONFIG_ISAPNP */
 
 	/* Select an open I/O location at 0x1*0 to do contention select. */
 	for ( ; id_port < 0x200; id_port += 0x10) {
@@ -376,7 +385,7 @@
 		phys_addr[i] = htons(id_read_eeprom(i));
 	}
 
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 	if (nopnp == 0) {
 		/* The ISA PnP 3c509 cards respond to the ID sequence.
 		   This check is needed in order not to register them twice. */
@@ -396,7 +405,7 @@
 			}
 		}
 	}
-#endif /* __ISAPNP__ */
+#endif /* CONFIG_ISAPNP */
 
 	{
 		unsigned int iobase = id_read_eeprom(8);
@@ -984,7 +993,7 @@
 MODULE_PARM(irq,"1-8i");
 MODULE_PARM(xcvr,"1-8i");
 MODULE_PARM(max_interrupt_work, "i");
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 MODULE_PARM(nopnp, "i");
 #endif
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c515.c linux/drivers/net/3c515.c
--- v2.4.2/linux/drivers/net/3c515.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/3c515.c	Tue Mar 20 12:05:00 2001
@@ -46,6 +46,7 @@
 #define RX_RING_SIZE	16
 #define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer. */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/isapnp.h>
@@ -105,9 +106,9 @@
 #define CORKSCREW_TOTAL_SIZE 0x20
 
 #ifdef DRIVER_DEBUG
-int corkscrew_debug = DRIVER_DEBUG;
+static int corkscrew_debug = DRIVER_DEBUG;
 #else
-int corkscrew_debug = 1;
+static int corkscrew_debug = 1;
 #endif
 
 #define CORKSCREW_ID 10
@@ -351,21 +352,20 @@
 	{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
 };
 
-#ifdef __ISAPNP__
-struct corkscrew_isapnp_adapters_struct {
-	unsigned short vendor, function;
-	char *name;
-};
-struct corkscrew_isapnp_adapters_struct corkscrew_isapnp_adapters[] = {
-	{ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051), "3Com Fast EtherLink ISA"},
-	{0, }
-};
-int corkscrew_isapnp_phys_addr[3] = {
-	0, 0, 0
+#ifdef CONFIG_ISAPNP
+static struct isapnp_device_id corkscrew_isapnp_adapters[] = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5051),
+		(long) "3Com Fast EtherLink ISA" },
+	{ }	/* terminate list */
 };
 
+MODULE_DEVICE_TABLE(isapnp, corkscrew_isapnp_adapters);
+
+static int corkscrew_isapnp_phys_addr[3];
+
 static int nopnp;
-#endif
+#endif /* CONFIG_ISAPNP */
 
 static int corkscrew_scan(struct net_device *dev);
 static struct net_device *corkscrew_found_device(struct net_device *dev,
@@ -419,7 +419,7 @@
 		printk(version);
 
 	root_corkscrew_dev = NULL;
-	cards_found = corkscrew_scan(0);
+	cards_found = corkscrew_scan(NULL);
 	return cards_found ? 0 : -ENODEV;
 }
 
@@ -443,12 +443,12 @@
 {
 	int cards_found = 0;
 	static int ioaddr;
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 	short i;
 	static int pnp_cards = 0;
 #endif
 
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 	if(nopnp == 1)
 		goto no_pnp;
 	for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) {
@@ -475,7 +475,7 @@
 			irq = idev->irq_resource[0].start;
 			if(corkscrew_debug)
 				printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n",
-					corkscrew_isapnp_adapters[i].name,ioaddr, irq);
+					(char*) corkscrew_isapnp_adapters[i].driver_data, ioaddr, irq);
 					
 			if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0))
 				continue;
@@ -506,17 +506,17 @@
 		}
 	}
 no_pnp:
-#endif /* not __ISAPNP__ */
+#endif /* CONFIG_ISAPNP */
 
 	/* Check all locations on the ISA bus -- evil! */
 	for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) {
 		int irq;
-#ifdef __ISAPNP__
+#ifdef CONFIG_ISAPNP
 		/* Make sure this was not already picked up by isapnp */
 		if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue;
 		if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue;
 		if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue;
-#endif
+#endif /* CONFIG_ISAPNP */
 		if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE))
 			continue;
 		/* Check the resource configuration for a matching ioaddr. */
@@ -590,11 +590,11 @@
 	ether_setup(dev);
 	vp->next_module = root_corkscrew_dev;
 	root_corkscrew_dev = dev;
+	SET_MODULE_OWNER(dev);
 	if (register_netdev(dev) != 0) {
 		kfree(dev);
 		return NULL;
 	}
-	SET_MODULE_OWNER(dev);
 #else				/* not a MODULE */
 	/* Caution: quad-word alignment required for rings! */
 	dev->priv =
@@ -1219,7 +1219,7 @@
 #ifdef VORTEX_BUS_MASTER
 		if (status & DMADone) {
 			outw(0x1000, ioaddr + Wn7_MasterStatus);	/* Ack the event. */
-			dev_kfree_skb_irq(lp->tx_skb);	/* Release the transfered buffer */
+			dev_kfree_skb_irq(lp->tx_skb);	/* Release the transferred buffer */
 			netif_wake_queue(dev);
 		}
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c523.h linux/drivers/net/3c523.h
--- v2.4.2/linux/drivers/net/3c523.h	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/3c523.h	Sun Mar  4 14:05:04 2001
@@ -60,7 +60,7 @@
   unsigned short cbl_offset;    /* pointeroffset, command block list */
   unsigned short rfa_offset;    /* pointeroffset, receive frame area */
   unsigned short crc_errs;      /* CRC-Error counter */
-  unsigned short aln_errs;      /* allignmenterror counter */
+  unsigned short aln_errs;      /* alignmenterror counter */
   unsigned short rsc_errs;      /* Resourceerror counter */
   unsigned short ovrn_errs;     /* OVerrunerror counter */
 };
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c527.c linux/drivers/net/3c527.c
--- v2.4.2/linux/drivers/net/3c527.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/3c527.c	Sun Mar  4 14:05:04 2001
@@ -1,8 +1,9 @@
-/* 3c527.c: 3Com Etherlink/MC32 driver for Linux
+/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4
  *
  *	(c) Copyright 1998 Red Hat Software Inc
- *	Written by Alan Cox.
+ *	Written by Alan Cox. 
  *	Further debugging by Carl Drougge.
+ *      Modified by Richard Procter (rnp@netlink.co.nz)
  *
  *	Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
  *	(for the MCA stuff) written by Wim Dumon.
@@ -16,7 +17,7 @@
  */
 
 static const char *version =
-	"3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n";
+	"3c527.c:v0.6 2001/03/03 Richard Proctor (rnp@netlink.co.nz)\n";
 
 /**
  * DOC: Traps for the unwary
@@ -24,6 +25,13 @@
  *	The diagram (Figure 1-1) and the POS summary disagree with the
  *	"Interrupt Level" section in the manual.
  *
+ *	The manual contradicts itself when describing the minimum number 
+ *	buffers in the 'configure lists' command. 
+ *	My card accepts a buffer config of 4/4. 
+ *
+ *	Setting the SAV BP bit does not save bad packets, but
+ *	only enables RX on-card stats collection. 
+ *
  *	The documentation in places seems to miss things. In actual fact
  *	I've always eventually found everything is documented, it just
  *	requires careful study.
@@ -35,25 +43,39 @@
  *	Intel NIC. For performance we want to keep the transmit queue deep
  *	as the card can transmit packets while fetching others from main
  *	memory by bus master DMA. Transmission and reception are driven by
- *	ring buffers. When updating the ring we are required to do some
- *	housekeeping work using the mailboxes and the command register.
+ *	circular buffer queues.
  *
- *	The mailboxes provide a method for sending control requests to the
- *	card. The transmit mail box is used to update the transmit ring 
- *	pointers and the receive mail box to update the receive ring
- *	pointers. The exec mailbox allows a variety of commands to be
- *	executed. Each command must complete before the next is executed.
- *	Primarily we use the exec mailbox for controlling the multicast lists.
- *	We have to do a certain amount of interesting hoop jumping as the 
- *	multicast list changes can occur in interrupt state when the card
- *	has an exec command pending. We defer such events until the command
- *	completion interrupt.
- *
- *	The control register is used to pass status information. It tells us
- *	the transmit and receive status for packets and allows us to control
- *	the card operation mode. You must stop the card when emptying the
- *	receive ring, or you will race with the ring buffer and lose packets.
- */
+ *	The mailboxes can be used for controlling how the card traverses
+ *	its buffer rings, but are used only for inital setup in this
+ *	implementation.  The exec mailbox allows a variety of commands to
+ *	be executed. Each command must complete before the next is
+ *	executed. Primarily we use the exec mailbox for controlling the
+ *	multicast lists.  We have to do a certain amount of interesting
+ *	hoop jumping as the multicast list changes can occur in interrupt
+ *	state when the card has an exec command pending. We defer such
+ *	events until the command completion interrupt.
+ *
+ *	A copy break scheme (taken from 3c59x.c) is employed whereby
+ *	received frames exceeding a configurable length are passed
+ *	directly to the higher networking layers without incuring a copy,
+ *	in what amounts to a time/space trade-off.
+ *	 
+ *	The card also keeps a large amount of statistical information
+ *	on-board. In a perfect world, these could be used safely at no
+ *	cost. However, lacking information to the contrary, processing
+ *	them without races would involve so much extra complexity as to
+ *	make it unworthwhile to do so. In the end, a hybrid SW/HW
+ *	implementation was made necessary --- see mc32_update_stats().  
+ *
+ * DOC: Notes
+ *	
+ *	It should be possible to use two or more cards, but at this stage
+ *	only by loading two copies of the same module.
+ *
+ *	The on-board 82586 NIC has trouble receiving multiple
+ *	back-to-back frames and so is likely to drop packets from fast
+ *	senders.
+**/
 
 #include <linux/module.h>
 
@@ -78,6 +100,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/if_ether.h>
 
 #include "3c527.h"
 
@@ -91,23 +114,37 @@
 #ifndef NET_DEBUG
 #define NET_DEBUG 2
 #endif
+
+#undef DEBUG_IRQ
+
 static unsigned int mc32_debug = NET_DEBUG;
 
 /* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT	8
+#define MC32_IO_EXTENT	8
+
+/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ 
+#define TX_RING_LEN     32       /* Typically the card supports 37  */
+#define RX_RING_LEN     8        /*     "       "        "          */
+
+/* Copy break point, see above for details. 
+ * Setting to > 1512 effectively disables this feature.	*/	    
+#define RX_COPYBREAK    200      /* Value from 3c59x.c */
+
+/* Issue the 82586 workaround command - this is for "busy lans", but
+ * basically means for all lans now days - has a performance (latency) 
+ * cost, but best set. */ 
+static const int WORKAROUND_82586=1;
 
+/* Pointers to buffers and their on-card records */
 
-struct mc32_mailbox
+struct mc32_ring_desc 
 {
-	u16	mbox __attribute((packed));
-	u16	data[1] __attribute((packed));
+	volatile struct skb_header *p;                    
+	struct sk_buff *skb;          
 };
 
-/* Information that need to be kept for each board. */
-
-#define TX_RING_MAX	16	/* Typically the card supports 37 */
-#define RX_RING_MAX	32	/*        "     "       "         */
 
+/* Information that needs to be kept for each board. */
 struct mc32_local 
 {
 	struct net_device_stats net_stats;
@@ -115,25 +152,28 @@
 	volatile struct mc32_mailbox *rx_box;
 	volatile struct mc32_mailbox *tx_box;
 	volatile struct mc32_mailbox *exec_box;
-	volatile u16 *stats;
-	u16 tx_chain;
-	u16 rx_chain;
-	u16 tx_len;
-	u16 rx_len;
+        volatile struct mc32_stats *stats;    /* Start of on-card statistics */
+        u16 tx_chain;           /* Transmit list start offset */
+	u16 rx_chain;           /* Receive list start offset */
+        u16 tx_len;             /* Transmit list count */ 
+        u16 rx_len;             /* Receive list count */
+
 	u32 base;
-	u16 rx_halted;
-	u16 tx_halted;
-	u16 rx_pending;
 	u16 exec_pending;
 	u16 mc_reload_wait;	/* a multicast load request is pending */
-	atomic_t tx_count;		/* buffers left */
+	u32 mc_list_valid;	/* True when the mclist is set */
+	u16 xceiver_state;      /* Current transceiver state. bitmapped */ 
+	u16 desired_state;      /* The state we want the transceiver to be in */ 
+	atomic_t tx_count;	/* buffers left */
 	wait_queue_head_t event;
-	struct sk_buff *tx_skb[TX_RING_MAX];	/* Transmit ring */
-	u16 tx_skb_top;
-	u16 tx_skb_end;
-	struct sk_buff *rx_skb[RX_RING_MAX];	/* Receive ring */
-	void *rx_ptr[RX_RING_MAX];		/* Data pointers */
-	u32 mc_list_valid;			/* True when the mclist is set */
+
+	struct mc32_ring_desc tx_ring[TX_RING_LEN];	/* Host Transmit ring */
+	struct mc32_ring_desc rx_ring[RX_RING_LEN];	/* Host Receive ring */
+
+	u16 tx_ring_tail;       /* index to tx de-queue end */
+	u16 tx_ring_head;       /* index to tx en-queue end */
+
+	u16 rx_ring_tail;       /* index to rx de-queue end */ 
 };
 
 /* The station (ethernet) address prefix, used for a sanity check. */
@@ -146,18 +186,25 @@
 	char		*name;
 };
 
-static struct mca_adapters_t mc32_adapters[] __initdata = {
+const struct mca_adapters_t mc32_adapters[] = {
 	{ 0x0041, "3COM EtherLink MC/32" },
 	{ 0x8EF5, "IBM High Performance Lan Adapter" },
 	{ 0x0000, NULL }
 };
 
 
-/* Index to functions, as function prototypes. */
+/* Macros for ring index manipulations */ 
+static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
 
+static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
+
+
+/* Index to functions, as function prototypes. */
 extern int mc32_probe(struct net_device *dev);
 
 static int	mc32_probe1(struct net_device *dev, int ioaddr);
+static int      mc32_command(struct net_device *dev, u16 cmd, void *data, int len);
 static int	mc32_open(struct net_device *dev);
 static void	mc32_timeout(struct net_device *dev);
 static int	mc32_send_packet(struct sk_buff *skb, struct net_device *dev);
@@ -167,9 +214,8 @@
 static void	mc32_set_multicast_list(struct net_device *dev);
 static void	mc32_reset_multicast_list(struct net_device *dev);
 
-
 /**
- * mc32_probe:
+ * mc32_probe 	-	Search for supported boards
  * @dev: device to probe
  *
  * Because MCA bus is a real bus and we can scan for cards we could do a
@@ -212,7 +258,7 @@
 }
 
 /**
- * mc32_probe1:
+ * mc32_probe1	-	Check a given slot for a board and test the card
  * @dev:  Device structure to fill in
  * @slot: The MCA bus slot being used by this card
  *
@@ -221,11 +267,11 @@
  * in firmware so we have to wait for it to return and post us either a 
  * failure case or some addresses we use to find the board internals.
  */
- 
+
 static int __init mc32_probe1(struct net_device *dev, int slot)
 {
 	static unsigned version_printed = 0;
-	int i;
+	int i, err;
 	u8 POS;
 	u32 base;
 	struct mc32_local *lp;
@@ -258,7 +304,7 @@
 		"82586 initialisation failure",
 		"Adapter list configuration error"
 	};
-	
+
 	/* Time to play MCA games */
 
 	if (mc32_debug  &&  version_printed++ == 0)
@@ -301,6 +347,12 @@
 	
 	dev->irq = ((POS>>2)&3)+9;
 	
+	if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
+	{
+		printk("io 0x%3lX, which is busy.\n", dev->base_addr);
+		return -EBUSY;
+	}
+
 	printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
 		dev->base_addr, dev->irq, dev->mem_start, i/1024);
 	
@@ -349,18 +401,20 @@
 	 *	Grab the IRQ
 	 */
 
-	i = request_irq(dev->irq, &mc32_interrupt, 0, dev->name, dev);
+	i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev);
 	if (i) {
-		printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		release_region(dev->base_addr, MC32_IO_EXTENT);
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
 		return i;
 	}
 
+
 	/* Initialize the device structure. */
 	dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
 	if (dev->priv == NULL)
 	{
-		free_irq(dev->irq, dev);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto err_exit_irq; 
 	}
 
 	memset(dev->priv, 0, sizeof(struct mc32_local));
@@ -371,14 +425,14 @@
 
 	base = inb(dev->base_addr);
 	
-	while(base==0xFF)
+	while(base == 0xFF)
 	{
 		i++;
-		if(i==1000)
+		if(i == 1000)
 		{
-			printk("%s: failed to boot adapter.\n", dev->name);
-			free_irq(dev->irq, dev);
-			return -ENODEV;
+			printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name);
+			err = -ENODEV; 
+			goto err_exit_free;
 		}
 		udelay(1000);
 		if(inb(dev->base_addr+2)&(1<<5))
@@ -388,12 +442,12 @@
 	if(base>0)
 	{
 		if(base < 0x0C)
-			printk("%s: %s%s.\n", dev->name, failures[base-1],
+			printk(KERN_ERR "%s: %s%s.\n", dev->name, failures[base-1],
 				base<0x0A?" test failure":"");
 		else
-			printk("%s: unknown failure %d.\n", dev->name, base);
-		free_irq(dev->irq, dev);
-		return -ENODEV;
+			printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);
+		err = -ENODEV; 
+		goto err_exit_free;
 	}
 	
 	base=0;
@@ -408,8 +462,8 @@
 			if(n>100)
 			{
 				printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i);
-				free_irq(dev->irq, dev);
-				return -ENODEV;
+				err = -ENODEV;
+				goto err_exit_free;
 			}
 		}
 
@@ -418,11 +472,11 @@
 	
 	lp->exec_box=bus_to_virt(dev->mem_start+base);
 	
-	base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
+	base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];  
 	
 	lp->base = dev->mem_start+base;
 	
-	lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]);
+	lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); 
 	lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]);
 	
 	lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]);
@@ -431,18 +485,16 @@
 	 *	Descriptor chains (card relative)
 	 */
 	 
-	lp->tx_chain 		= lp->exec_box->data[8];
-	lp->rx_chain 		= lp->exec_box->data[10];
-	lp->tx_len 		= lp->exec_box->data[9];
-	lp->rx_len 		= lp->exec_box->data[11];
+	lp->tx_chain 		= lp->exec_box->data[8];   /* Transmit list start offset */
+	lp->rx_chain 		= lp->exec_box->data[10];  /* Receive list start offset */
+	lp->tx_len 		= lp->exec_box->data[9];   /* Transmit list count */ 
+	lp->rx_len 		= lp->exec_box->data[11];  /* Receive list count */
+
 	init_waitqueue_head(&lp->event);
 	
-	printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
-		dev->name, lp->rx_len, lp->tx_len, lp->base);
-		
-	if(lp->tx_len > TX_RING_MAX)
-		lp->tx_len = TX_RING_MAX;
-	
+	printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
+		dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
+
 	dev->open		= mc32_open;
 	dev->stop		= mc32_close;
 	dev->hard_start_xmit	= mc32_send_packet;
@@ -450,57 +502,65 @@
 	dev->set_multicast_list = mc32_set_multicast_list;
 	dev->tx_timeout		= mc32_timeout;
 	dev->watchdog_timeo	= HZ*5;	/* Board does all the work */
+
 	
-	lp->rx_halted		= 1;
-	lp->tx_halted		= 1;
-	lp->rx_pending		= 0;
+	lp->xceiver_state = HALTED; 
+	
+	lp->tx_ring_tail=lp->tx_ring_head=0;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
+	
 	return 0;
+
+err_exit_free:
+	kfree(dev->priv);
+err_exit_irq:
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, MC32_IO_EXTENT);
+	return err;
 }
 
 
 /**
- *	mc32_ring_poll:
+ *	mc32_ready_poll		-	wait until we can feed it a command
  *	@dev:	The device to wait for
  *	
- *	Wait until a command we issues to the control register is completed.
- *	This actually takes very little time at all, which is fortunate as
- *	we often have to busy wait it.
+ *	Wait until the card becomes ready to accept a command via the
+ *	command register. This tells us nothing about the completion
+ *	status of any pending commands and takes very little time at all.
  */
  
-static void mc32_ring_poll(struct net_device *dev)
+static void mc32_ready_poll(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 }
 
 
-
 /**
- *	mc32_command_nowait:
+ *	mc32_command_nowait	-	send a command non blocking
  *	@dev: The 3c527 to issue the command to
  *	@cmd: The command word to write to the mailbox
  *	@data: A data block if the command expects one
  *	@len: Length of the data block
  *
- *	Send a command from interrupt state. If there is a command currently
- *	being executed then we return an error of -1. It simply isnt viable
- *	to wait around as commands may be slow. Providing we get in then
- *	we send the command and busy wait for the board to acknowledge that
- *	a command request is pending. We do not wait for the command to 
- *	complete, just for the card to admit to noticing it.  
+ *	Send a command from interrupt state. If there is a command
+ *	currently being executed then we return an error of -1. It simply
+ *	isn't viable to wait around as commands may be slow. Providing we
+ *	get in, we busy wait for the board to become ready to accept the
+ *	command and issue it. We do not wait for the command to complete
+ *	--- the card will interrupt us when it's done.
  */
 
 static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
+
 	if(lp->exec_pending)
 		return -1;
-		
+	
 	lp->exec_pending=3;
 	lp->exec_box->mbox=0;
 	lp->exec_box->mbox=cmd;
@@ -515,7 +575,7 @@
 
 
 /**
- *	mc32_command: 
+ *	mc32_command	-	send a command and sleep until completion
  *	@dev: The 3c527 card to issue the command to
  *	@cmd: The command word to write to the mailbox
  *	@data: A data block if the command expects one
@@ -543,8 +603,6 @@
  *	3	- command issued, trash reply. In which case the irq
  *		  takes it back to state 0
  *
- *	Send command and block for results. On completion spot and reissue
- *	multicasts
  */
   
 static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
@@ -580,251 +638,287 @@
 	/* Send the command */
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 	outb(1<<6, ioaddr+HOST_CMD);	
-	
+
 	save_flags(flags);
 	cli();
+
 	while(lp->exec_pending!=2)
 		sleep_on(&lp->event);
 	lp->exec_pending=0;
 	restore_flags(flags);
 	
-	 
-	if(lp->exec_box->data[0]&(1<<13))
+	if(lp->exec_box->mbox&(1<<13))
 		ret = -1;
+
 	/*
 	 *	A multicast set got blocked - do it now
 	 */
 		
 	if(lp->mc_reload_wait)
+	{
 		mc32_reset_multicast_list(dev);
+	}
 
 	return ret;
 }
 
 
 /**
- *	mc32_rx_abort:
- *	@dev: 3c527 to abort
+ *	mc32_start_transceiver	-	tell board to restart tx/rx
+ *	@dev: The 3c527 card to issue the command to
  *
- *	Peforms a receive abort sequence on the card. In fact after some
- *	experimenting we now simply tell the card to suspend reception. When
- *	issuing aborts occasionally odd things happened.
- */
- 
-static void mc32_rx_abort(struct net_device *dev)
-{
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
+ *	This may be called from the interrupt state, where it is used
+ *	to restart the rx ring if the card runs out of rx buffers. 
+ *	
+ * 	First, we check if it's ok to start the transceiver. We then show
+ * 	the card where to start in the rx ring and issue the
+ * 	commands to start reception and transmission. We don't wait
+ * 	around for these to complete.
+ */ 
 
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
-	lp->rx_box->mbox=0;
-	outb(3<<3, ioaddr+HOST_CMD);	/* Suspend reception */
-}
+static void mc32_start_transceiver(struct net_device *dev) {
 
- 
-/**
- *	mc32_rx_begin:
- *	@dev: 3c527 to enable
- *
- *	We wait for any pending command to complete and then issue 
- *	a start reception command to the board itself. At this point 
- *	receive handling continues as it was before.
- */
- 
-static void mc32_rx_begin(struct net_device *dev)
-{
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
-	lp->rx_box->mbox=0;
-	outb(1<<3, ioaddr+HOST_CMD);	/* GO */
-	mc32_ring_poll(dev);	
-	
-	lp->rx_halted=0;
-	lp->rx_pending=0;
-}
 
-/**
- *	mc32_tx_abort:
- *	@dev: 3c527 to abort
- *
- *	Peforms a receive abort sequence on the card. In fact after some
- *	experimenting we now simply tell the card to suspend transmits . When
- *	issuing aborts occasionally odd things happened. In theory we want
- *	an abort to be sure we can recycle our buffers. As it happens we
- *	just have to be careful to shut the card down on close, and
- *	boot it carefully from scratch on setup.
- */
- 
-static void mc32_tx_abort(struct net_device *dev)
-{
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
+	/* Ignore RX overflow on device closure */ 
+	if (lp->desired_state==HALTED)  
+		return; 
+
+	mc32_ready_poll(dev); 
+
 	lp->tx_box->mbox=0;
-	outb(3, ioaddr+HOST_CMD);	/* Suspend */
-	
-	/* Ring empty */
-	
-	atomic_set(&lp->tx_count, lp->tx_len);
+	lp->rx_box->mbox=0;
+
+	/* Give the card the offset to the post-EOL-bit RX descriptor */ 
+	lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; 
+
+	outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);      
+
+	mc32_ready_poll(dev); 
+	outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */ 
 	
-	/* Flush */
-	if(lp->tx_skb_top!=lp->tx_skb_end)
-	{
-		int i;
-		if(lp->tx_skb_top<=lp->tx_skb_end)
-		{
-			for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++)
-			{
-				dev_kfree_skb(lp->tx_skb[i]);
-				lp->tx_skb[i]=NULL;
-			}
-		}
-		else
-		{
-			for(i=lp->tx_skb_end;i<TX_RING_MAX;i++)
-			{
-				dev_kfree_skb(lp->tx_skb[i]);
-				lp->tx_skb[i]=NULL;
-			}
-			for(i=0;i<lp->tx_skb_top;i++)
-			{
-				dev_kfree_skb(lp->tx_skb[i]);
-				lp->tx_skb[i]=NULL;
-			}
-		}
-	}
-	lp->tx_skb_top=lp->tx_skb_end=0;
+	/* We are not interrupted on start completion */ 
+	lp->xceiver_state=RUNNING; 
 }
 
+
 /**
- *	mc32_tx_begin:
- *	@dev: 3c527 to enable
+ *	mc32_halt_transceiver	-	tell board to stop tx/rx
+ *	@dev: The 3c527 card to issue the command to
  *
- *	We wait for any pending command to complete and then issue 
- *	a start transmit command to the board itself. At this point 
- *	transmit handling continues as it was before. The ring must
- *	be setup before you do this and must have an end marker in it.
- *	It turns out we can avoid issuing this specific command when
- *	doing our setup so we avoid it.
- */
- 
-static void mc32_tx_begin(struct net_device *dev)
+ *	We issue the commands to halt the card's transceiver. In fact,
+ *	after some experimenting we now simply tell the card to
+ *	suspend. When issuing aborts occasionally odd things happened.
+ *
+ *	We then sleep until the card has notified us that both rx and
+ *	tx have been suspended.
+ */ 
+
+static void mc32_halt_transceiver(struct net_device *dev) 
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
+	unsigned long flags;
+
+	mc32_ready_poll(dev);	
+
 	lp->tx_box->mbox=0;
-#if 0	
-	outb(5, ioaddr+HOST_CMD);	/* GO */
-	printk("TX=>5\n");
-	mc32_ring_poll(dev);	
-	if(lp->tx_box->mbox&(1<<13))
-		printk("TX begin error!\n");
-#endif		
-	lp->tx_halted=0;
-}
+	lp->rx_box->mbox=0;
+
+	outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);			
+	mc32_ready_poll(dev); 
+	outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);	
+		
+	save_flags(flags);
+	cli();
+		
+	while(lp->xceiver_state!=HALTED) 
+		sleep_on(&lp->event); 
+		
+	restore_flags(flags);	
+} 
+
 
-	
 /**
- *	mc32_load_rx_ring:
+ *	mc32_load_rx_ring	-	load the ring of receive buffers
  *	@dev: 3c527 to build the ring for
  *
- *	The card setups up the receive ring for us. We are required to
- *	use the ring it provides although we can change the size of the
- *	ring.
- *
- *	We allocate an sk_buff for each ring entry in turn and set the entry
- *	up for a single non s/g buffer. The first buffer we mark with the
- *	end marker bits. Finally we clear the rx mailbox.
+ *	This initalises the on-card and driver datastructures to
+ *	the point where mc32_start_transceiver() can be called.
+ *
+ *	The card sets up the receive ring for us. We are required to use the
+ *	ring it provides although we can change the size of the ring.
+ *
+ * 	We allocate an sk_buff for each ring entry in turn and
+ * 	initalise its house-keeping info. At the same time, we read
+ * 	each 'next' pointer in our rx_ring array. This reduces slow
+ * 	shared-memory reads and makes it easy to access predecessor
+ * 	descriptors.
+ *
+ *	We then set the end-of-list bit for the last entry so that the
+ * 	card will know when it has run out of buffers.
  */
- 
+	 
 static int mc32_load_rx_ring(struct net_device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int i;
-	u16 base;
+	u16 rx_base;
 	volatile struct skb_header *p;
 	
-	base = lp->rx_box->data[0];
-	
-	/* Fix me - should use card size - also fix flush ! */ 
+	rx_base=lp->rx_chain;
 
-	for(i=0;i<RX_RING_MAX;i++)
+	for(i=0;i<RX_RING_LEN;i++)
 	{
-		lp->rx_skb[i]=alloc_skb(1532, GFP_KERNEL);
-		if(lp->rx_skb[i]==NULL)
+		lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);
+		skb_reserve(lp->rx_ring[i].skb, 18);  
+
+		if(lp->rx_ring[i].skb==NULL)
 		{
 			for(;i>=0;i--)
-				kfree_skb(lp->rx_skb[i]);
+				kfree_skb(lp->rx_ring[i].skb);
 			return -ENOBUFS;
 		}
-		lp->rx_ptr[i]=lp->rx_skb[i]->data+18;
 		
-		p=bus_to_virt(lp->base+base);
+		p=bus_to_virt(lp->base+rx_base);
+				
 		p->control=0;
-		p->data = virt_to_bus(lp->rx_ptr[i]);
+		p->data=virt_to_bus(lp->rx_ring[i].skb->data);
 		p->status=0;
-		p->length = 1532;
-		base = p->next;
+		p->length=1532;
+	
+		lp->rx_ring[i].p=p; 
+		rx_base=p->next; 
 	}
-	p->control = (1<<6);
-	lp->rx_box->mbox = 0;
+
+	lp->rx_ring[i-1].p->control |= CONTROL_EOL;
+
+	lp->rx_ring_tail=0;
+
 	return 0;
 }	
 
+
 /**
- *	mc32_flush_rx_ring:
+ *	mc32_flush_rx_ring	-	free the ring of receive buffers
  *	@lp: Local data of 3c527 to flush the rx ring of
  *
- *	Free the buffer for each ring slot. Because of the receive 
- *	algorithm we use the ring will always be loaded will a full set
- *	of buffers.
+ *	Free the buffer for each ring slot. This may be called 
+ *      before mc32_load_rx_ring(), eg. on error in mc32_open().
  */
 
-static void mc32_flush_rx_ring(struct mc32_local *lp)
+static void mc32_flush_rx_ring(struct net_device *dev)
 {
-	int i;
-	for(i=0;i<RX_RING_MAX;i++)
-		kfree_skb(lp->rx_skb[i]);
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	
+	struct sk_buff *skb;
+	int i; 
+
+	for(i=0; i < RX_RING_LEN; i++) 
+	{ 
+		skb = lp->rx_ring[i].skb;
+		if (skb!=NULL) {
+			kfree_skb(skb);
+			skb=NULL; 
+		}
+		lp->rx_ring[i].p=NULL; 
+	} 
 }
 
+
 /**
- *	mc32_flush_tx_ring:
+ *	mc32_load_tx_ring	-	load transmit ring
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	This sets up the host transmit data-structures. 
+ *
+ *	First, we obtain from the card it's current postion in the tx
+ *	ring, so that we will know where to begin transmitting
+ *	packets.
+ * 	
+ * 	Then, we read the 'next' pointers from the on-card tx ring into
+ *  	our tx_ring array to reduce slow shared-mem reads. Finally, we
+ * 	intitalise the tx house keeping variables.
+ * 
+ */ 
+
+static void mc32_load_tx_ring(struct net_device *dev)
+{ 
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	volatile struct skb_header *p;
+	int i; 
+	u16 tx_base;
+
+	tx_base=lp->tx_box->data[0]; 
+
+	for(i=0;i<lp->tx_len;i++) 
+	{
+		p=bus_to_virt(lp->base+tx_base);
+		lp->tx_ring[i].p=p; 
+		lp->tx_ring[i].skb=NULL;
+
+		tx_base=p->next;
+	}
+
+	/* -1 so that tx_ring_head cannot "lap" tx_ring_tail,           */
+	/* which would be bad news for mc32_tx_ring as cur. implemented */ 
+
+	atomic_set(&lp->tx_count, TX_RING_LEN-1); 
+	lp->tx_ring_head=lp->tx_ring_tail=0; 
+} 
+
+
+/**
+ *	mc32_flush_tx_ring 	-	free transmit ring
  *	@lp: Local data of 3c527 to flush the tx ring of
  *
  *	We have to consider two cases here. We want to free the pending
  *	buffers only. If the ring buffer head is past the start then the
- *	ring segment we wish to free wraps through zero.
+ *	ring segment we wish to free wraps through zero. The tx ring 
+ *	house-keeping variables are then reset.
  */
 
-static void mc32_flush_tx_ring(struct mc32_local *lp)
+static void mc32_flush_tx_ring(struct net_device *dev)
 {
-	int i;
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	
-	if(lp->tx_skb_top <= lp->tx_skb_end)
-	{
-		for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++)
-			dev_kfree_skb(lp->tx_skb[i]);
-	}
-	else
+	if(lp->tx_ring_tail!=lp->tx_ring_head)
 	{
-		for(i=0;i<lp->tx_skb_end;i++)
-			dev_kfree_skb(lp->tx_skb[i]);
-		for(i=lp->tx_skb_top;i<TX_RING_MAX;i++)
-			dev_kfree_skb(lp->tx_skb[i]);
+		int i;	
+		if(lp->tx_ring_tail < lp->tx_ring_head)
+		{
+			for(i=lp->tx_ring_tail;i<lp->tx_ring_head;i++)
+			{
+				dev_kfree_skb(lp->tx_ring[i].skb);
+				lp->tx_ring[i].skb=NULL;
+				lp->tx_ring[i].p=NULL; 
+			}
+		}
+		else
+		{
+			for(i=lp->tx_ring_tail; i<TX_RING_LEN; i++) 
+			{
+				dev_kfree_skb(lp->tx_ring[i].skb);
+				lp->tx_ring[i].skb=NULL;
+				lp->tx_ring[i].p=NULL; 
+			}
+			for(i=0; i<lp->tx_ring_head; i++) 
+			{
+				dev_kfree_skb(lp->tx_ring[i].skb);
+				lp->tx_ring[i].skb=NULL;
+				lp->tx_ring[i].p=NULL; 
+			}
+		}
 	}
+	
+	atomic_set(&lp->tx_count, 0); 
+	lp->tx_ring_tail=lp->tx_ring_head=0;
 }
  	
+
 /**
- *	mc32_open
+ *	mc32_open	-	handle 'up' of card
  *	@dev: device to open
  *
  *	The user is trying to bring the card into ready state. This requires
@@ -832,9 +926,10 @@
  *	'indications'. Without these enabled the card doesn't bother telling
  *	us what it has done. This had me puzzled for a week.
  *
- *	We then load the network address and multicast filters. Turn on the
- *	workaround mode. This works around a bug in the 82586 - it asks the
- *	firmware to do so. It has a performance hit but is needed on busy
+ *	We configure the number of card descriptors, then load the network
+ *	address and multicast filters. Turn on the workaround mode. This
+ *	works around a bug in the 82586 - it asks the firmware to do
+ *	so. It has a performance (latency) hit but is needed on busy
  *	[read most] lans. We load the ring with buffers then we kick it
  *	all off.
  */
@@ -842,10 +937,11 @@
 static int mc32_open(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
-	u16 zero_word=0;
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	u8 one=1;
 	u8 regs;
-	
+	u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
+
 	/*
 	 *	Interrupts enabled
 	 */
@@ -861,46 +957,64 @@
 
 	mc32_command(dev, 4, &one, 2);
 
-	 	
 	/*
-	 *	Send the command sequence "abort, resume" for RX and TX.
-	 *	The abort cleans up the buffer chains if needed.
+	 *	Poke it to make sure it's really dead. 
 	 */
 
-	mc32_rx_abort(dev);
-	mc32_tx_abort(dev);
-	
+	mc32_halt_transceiver(dev); 
+	mc32_flush_tx_ring(dev); 
+
+	/* 
+	 *	Ask card to set up on-card descriptors to our spec 
+	 */ 
+
+	if(mc32_command(dev, 8, descnumbuffs, 4)) { 
+		printk("%s: %s rejected our buffer configuration!\n",
+	 	       dev->name, cardname);
+		mc32_close(dev); 
+		return -ENOBUFS; 
+	}
+	
+	/* Report new configuration */ 
+	mc32_command(dev, 6, NULL, 0); 
+
+	lp->tx_chain 		= lp->exec_box->data[8];   /* Transmit list start offset */
+	lp->rx_chain 		= lp->exec_box->data[10];  /* Receive list start offset */
+	lp->tx_len 		= lp->exec_box->data[9];   /* Transmit list count */ 
+	lp->rx_len 		= lp->exec_box->data[11];  /* Receive list count */
+ 
 	/* Set Network Address */
 	mc32_command(dev, 1, dev->dev_addr, 6);
 	
 	/* Set the filters */
 	mc32_set_multicast_list(dev);
+		   
+	if (WORKAROUND_82586) { 
+		u16 zero_word=0;
+		mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */
+	}
+
+	mc32_load_tx_ring(dev);
 	
-	/* Issue the 82586 workaround command - this is for "busy lans",
-	   but basically means for all lans now days - has a performance
-	   cost but best set */
-	   
-	mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
-	
-	/* Load the ring we just initialised */
-	
-	if(mc32_load_rx_ring(dev))
+	if(mc32_load_rx_ring(dev)) 
 	{
 		mc32_close(dev);
 		return -ENOBUFS;
 	}
+
+	lp->desired_state = RUNNING; 
 	
-	/* And the resume command goes last */
-	
-	mc32_rx_begin(dev);
-	mc32_tx_begin(dev);
+	/* And finally, set the ball rolling... */
+	mc32_start_transceiver(dev);
+
+	netif_start_queue(dev);
 
-	netif_start_queue(dev);	
 	return 0;
 }
 
+
 /**
- *	mc32_timeout:
+ *	mc32_timeout	-	handle a timeout from the network layer
  *	@dev: 3c527 that timed out
  *
  *	Handle a timeout on transmit from the 3c527. This normally means
@@ -915,9 +1029,10 @@
 	/* Try to restart the adaptor. */
 	netif_wake_queue(dev);
 }
- 
+
+
 /**
- *	mc32_send_packet:
+ *	mc32_send_packet	-	queue a frame for transmit
  *	@skb: buffer to transmit
  *	@dev: 3c527 to send it out of
  *
@@ -931,18 +1046,16 @@
  *	MCA machine I don't plan to change it. It is probably the top 
  *	performance hit for this driver on SMP however.
  */
- 
+
 static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
 	unsigned long flags;
-		
-	u16 tx_head;
+
 	volatile struct skb_header *p, *np;
 
 	netif_stop_queue(dev);
-	
+
 	save_flags(flags);
 	cli();
 		
@@ -952,204 +1065,303 @@
 		return 1;
 	}
 
-	tx_head = lp->tx_box->data[0];
-	atomic_dec(&lp->tx_count);
-	/* We will need this to flush the buffer out */
-	
-	lp->tx_skb[lp->tx_skb_end] = skb;
-	lp->tx_skb_end++;
-	lp->tx_skb_end&=(TX_RING_MAX-1);
-
-	/* TX suspend - shouldnt be needed but apparently is.
-	   This is a research item ... */
-		   
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	lp->tx_box->mbox=0;
-	outb(3, ioaddr+HOST_CMD);
-	
-	/* Transmit now stopped */
+	atomic_dec(&lp->tx_count); 
 
 	/* P is the last sending/sent buffer as a pointer */
-	p=(struct skb_header *)bus_to_virt(lp->base+tx_head);
-	
-	/* NP is the buffer we will be loading */
-	np=(struct skb_header *)bus_to_virt(lp->base+p->next);
-		
-	np->control	|= (1<<6);	/* EOL */
-	wmb();
+	p=lp->tx_ring[lp->tx_ring_head].p; 
 		
-	np->length	= skb->len;
-		
-	if(np->length < 60)
-		np->length = 60;
+	lp->tx_ring_head=next_tx(lp->tx_ring_head); 
+
+	/* NP is the buffer we will be loading */
+	np=lp->tx_ring[lp->tx_ring_head].p; 
+
+	/* We will need this to flush the buffer out */
+	lp->tx_ring[lp->tx_ring_head].skb=skb;
+   	   
+	np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; 
 			
 	np->data	= virt_to_bus(skb->data);
 	np->status	= 0;
-	np->control	= (1<<7)|(1<<6);	/* EOP EOL */
+	np->control     = CONTROL_EOP | CONTROL_EOL;     
 	wmb();
 		
-	p->status	= 0;
-	p->control	&= ~(1<<6);
+	p->control     &= ~CONTROL_EOL;     /* Clear EOL on p */ 
 	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	lp->tx_box->mbox=0;
-	outb(5, ioaddr+HOST_CMD);		/* Restart TX */
 	restore_flags(flags);
-	
+
 	netif_wake_queue(dev);
 	return 0;
 }
 
+
 /**
- *	mc32_update_stats:
+ *	mc32_update_stats	-	pull off the on board statistics
  *	@dev: 3c527 to service
  *
- *	When the board signals us that its statistics need attention we
- *	should query the table and clear it. In actual fact we currently
- *	track all our statistics in software and I haven't implemented it yet.
+ * 
+ *	Query and reset the on-card stats. There's the small possibility
+ *	of a race here, which would result in an underestimation of
+ *	actual errors. As such, we'd prefer to keep all our stats
+ *	collection in software. As a rule, we do. However it can't be
+ *	used for rx errors and collisions as, by default, the card discards
+ *	bad rx packets. 
+ *
+ *	Setting the SAV BP in the rx filter command supposedly
+ *	stops this behaviour. However, testing shows that it only seems to
+ *	enable the collation of on-card rx statistics --- the driver
+ *	never sees an RX descriptor with an error status set.
+ *
  */
- 
+
 static void mc32_update_stats(struct net_device *dev)
 {
-}
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	volatile struct mc32_stats *st = lp->stats; 
+
+	u32 rx_errors=0; 
+      
+	rx_errors+=lp->net_stats.rx_crc_errors   +=st->rx_crc_errors;         
+	                                           st->rx_crc_errors=0;
+	rx_errors+=lp->net_stats.rx_fifo_errors  +=st->rx_overrun_errors;   
+	                                           st->rx_overrun_errors=0; 
+	rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; 
+ 	                                           st->rx_alignment_errors=0;
+	rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; 
+	                                           st->rx_tooshort_errors=0;
+	rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
+	                                           st->rx_outofresource_errors=0; 
+        lp->net_stats.rx_errors=rx_errors; 
+						   
+	/* Number of packets which saw one collision */
+	lp->net_stats.collisions+=st->dataC[10];
+	st->dataC[10]=0; 
+
+	/* Number of packets which saw 2--15 collisions */ 
+	lp->net_stats.collisions+=st->dataC[11]; 
+	st->dataC[11]=0; 
+}	
+
 
 /**
- *	mc32_rx_ring:
+ *	mc32_rx_ring	-	process the receive ring
  *	@dev: 3c527 that needs its receive ring processing
  *
- *	We have received one or more indications from the card that
- *	a receive has completed. The ring buffer thus contains dirty
- *	entries. Firstly we tell the card to stop receiving, then We walk 
- *	the ring from the first filled entry, which is pointed to by the 
- *	card rx mailbox and for each completed packet we will either copy 
- *	it and pass it up the stack or if the packet is near MTU sized we 
- *	allocate another buffer and flip the old one up the stack.
  *
+ *	We have received one or more indications from the card that a
+ *	receive has completed. The buffer ring thus contains dirty
+ *	entries. We walk the ring by iterating over the circular rx_ring
+ *	array, starting at the next dirty buffer (which happens to be the
+ *	one we finished up at last time around).
+ *
+ *	For each completed packet, we will either copy it and pass it up
+ * 	the stack or, if the packet is near MTU sized, we allocate
+ *	another buffer and flip the old one up the stack.
+ * 
  *	We must succeed in keeping a buffer on the ring. If neccessary we
- *	will toss a received packet rather than lose a ring entry. Once the
- *	first packet that is unused is found we reload the mailbox with the
- *	buffer so that the card knows it can use the buffers again. Finally
- *	we set it receiving again. 
- *
- *	We must stop reception during the ring walk. I thought it would be
- *	neat to avoid it by clever tricks, but it turns out the event order
- *	on the card means you have to play by the manual.
+ *	will toss a received packet rather than lose a ring entry. Once
+ *	the first uncompleted descriptor is found, we move the
+ *	End-Of-List bit to include the buffers just processed.
+ *
  */
- 
+
 static void mc32_rx_ring(struct net_device *dev)
 {
-	struct mc32_local *lp=dev->priv;
-	int ioaddr = dev->base_addr;
-	int x=0;
+	struct mc32_local *lp=dev->priv;		
 	volatile struct skb_header *p;
-	u16 base;
-	u16 top;
+	u16 rx_ring_tail = lp->rx_ring_tail;
+	u16 rx_old_tail = rx_ring_tail; 
 
-	/* Halt RX before walking the ring */
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	outb(3<<3, ioaddr+HOST_CMD);
-	while(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR);
+	int x=0;
 	
-	top = base = lp->rx_box->data[0];
 	do
-	{
-		p=(struct skb_header *)bus_to_virt(base+lp->base);
-		if(!(p->status & (1<<7)))
+	{ 
+		p=lp->rx_ring[rx_ring_tail].p; 
+
+		if(!(p->status & (1<<7))) { /* Not COMPLETED */ 
 			break;
-		if(p->status & (1<<6))
-		{
-			u16 length = p->length;
-			struct sk_buff *skb=dev_alloc_skb(length+2);
-			if(skb!=NULL)
+		} 
+		if(p->status & (1<<6)) /* COMPLETED_OK */
+		{		        
+
+			u16 length=p->length;
+			struct sk_buff *skb; 
+			struct sk_buff *newskb; 
+
+			/* Try to save time by avoiding a copy on big frames */
+
+			if ((length > RX_COPYBREAK) 
+			    && ((newskb=dev_alloc_skb(1532)) != NULL)) 
+			{ 
+				skb=lp->rx_ring[rx_ring_tail].skb;
+				skb_put(skb, length);
+				
+				skb_reserve(newskb,18); 
+				lp->rx_ring[rx_ring_tail].skb=newskb;  
+				p->data=virt_to_bus(newskb->data);  
+			} 
+			else 
 			{
+				skb=dev_alloc_skb(length+2);  
+
+				if(skb==NULL) {
+					lp->net_stats.rx_dropped++; 
+					goto dropped; 
+				}
+
 				skb_reserve(skb,2);
-				/*printk("Frame at %p\n", bus_to_virt(p->data)); */
 				memcpy(skb_put(skb, length),
-					bus_to_virt(p->data), length);
-				skb->protocol=eth_type_trans(skb,dev);
-				skb->dev=dev;
-				netif_rx(skb);
-				dev->last_rx = jiffies;
-				lp->net_stats.rx_packets++;
-				lp->net_stats.rx_bytes += length;
+				       lp->rx_ring[rx_ring_tail].skb->data, length);
 			}
-			else
-				lp->net_stats.rx_dropped++;
+			
+			skb->protocol=eth_type_trans(skb,dev); 
+			skb->dev=dev; 
+			dev->last_rx = jiffies;
+ 			lp->net_stats.rx_packets++; 
+ 			lp->net_stats.rx_bytes += length; 
+			netif_rx(skb);
 		}
-		else
+
+	dropped:
+		p->length = 1532; 
+		p->status = 0;
+		
+		rx_ring_tail=next_rx(rx_ring_tail); 
+	}
+        while(x++<48);  
+
+	/* If there was actually a frame to be processed, place the EOL bit */ 
+	/* at the descriptor prior to the one to be filled next */ 
+
+	if (rx_ring_tail != rx_old_tail) 
+	{ 
+		lp->rx_ring[prev_rx(rx_ring_tail)].p->control |=  CONTROL_EOL; 
+		lp->rx_ring[prev_rx(rx_old_tail)].p->control  &= ~CONTROL_EOL; 
+
+		lp->rx_ring_tail=rx_ring_tail; 
+	}
+}
+
+
+/**
+ *	mc32_tx_ring	-	process completed transmits
+ *	@dev: 3c527 that needs its transmit ring processing
+ *
+ *
+ *	This operates in a similar fashion to mc32_rx_ring. We iterate
+ *	over the transmit ring. For each descriptor which has been
+ *	processed by the card, we free its associated buffer and note
+ *	any errors. This continues until the transmit ring is emptied
+ *	or we reach a descriptor that hasn't yet been processed by the
+ *	card.
+ * 
+ */
+
+static void mc32_tx_ring(struct net_device *dev) 
+{
+	struct mc32_local *lp=(struct mc32_local *)dev->priv;
+	volatile struct skb_header *np;
+
+	/* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */
+
+	while (lp->tx_ring_tail != lp->tx_ring_head)  
+	{   
+		u16 t; 
+
+		t=next_tx(lp->tx_ring_tail); 
+		np=lp->tx_ring[t].p; 
+
+		if(!(np->status & (1<<7))) 
+		{
+			/* Not COMPLETED */ 
+			break; 
+		} 
+		lp->net_stats.tx_packets++;
+		if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
 		{
-			lp->net_stats.rx_errors++;
-			switch(p->status&0x0F)
+			lp->net_stats.tx_errors++;   
+
+			switch(np->status&0x0F)
 			{
 				case 1:
-					lp->net_stats.rx_crc_errors++;break;
+					lp->net_stats.tx_aborted_errors++;
+					break; /* Max collisions */ 
 				case 2:
-					lp->net_stats.rx_fifo_errors++;break;
+					lp->net_stats.tx_fifo_errors++;
+					break;
 				case 3:
-					lp->net_stats.rx_frame_errors++;break;
+					lp->net_stats.tx_carrier_errors++;
+					break;
 				case 4:
-					lp->net_stats.rx_missed_errors++;break;
+					lp->net_stats.tx_window_errors++;
+					break;  /* CTS Lost */ 
 				case 5:
-					lp->net_stats.rx_length_errors++;break;
+					lp->net_stats.tx_aborted_errors++;
+					break; /* Transmit timeout */ 
 			}
 		}
-		p->length = 1532;
-		p->control &= ~(1<<6);
-		p->status = 0;
-		base = p->next;
+		/* Packets are sent in order - this is
+		    basically a FIFO queue of buffers matching
+		    the card ring */
+		lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len;
+		dev_kfree_skb_irq(lp->tx_ring[t].skb);
+		lp->tx_ring[t].skb=NULL;
+		atomic_inc(&lp->tx_count);
+		netif_wake_queue(dev);
+
+		lp->tx_ring_tail=t; 
 	}
-	while(x++<48);
 
-	/*
-	 *	Restart ring processing
-	 */	
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	lp->rx_box->mbox=0;
-	lp->rx_box->data[0] = top;
-	outb(1<<3, ioaddr+HOST_CMD);	
-	lp->rx_halted=0;
-}
+} 
 
 
 /**
- *	mc32_interrupt:
+ *	mc32_interrupt		-	handle an interrupt from a 3c527
  *	@irq: Interrupt number
  *	@dev_id: 3c527 that requires servicing
  *	@regs: Registers (unused)
  *
- *	The 3c527 interrupts us for four reasons. The command register 
- *	contains the message it wishes to send us packed into a single
- *	byte field. We keep reading status entries until we have processed
- *	all the transmit and control items, but simply count receive
- *	reports. When the receive reports are in we can call the mc32_rx_ring
- *	and empty the ring. This saves the overhead of multiple command requests
+ *
+ *	An interrupt is raised whenever the 3c527 writes to the command
+ *	register. This register contains the message it wishes to send us
+ *	packed into a single byte field. We keep reading status entries
+ *	until we have processed all the control items, but simply count
+ *	transmit and receive reports. When all reports are in we empty the
+ *	transceiver rings as appropriate. This saves the overhead of
+ *	multiple command requests.
+ *
+ *	Because MCA is level-triggered, we shouldn't miss indications.
+ *	Therefore, we needn't ask the card to suspend interrupts within
+ *	this handler. The card receives an implicit acknowledgment of the
+ *	current interrupt when we read the command register.
+ *
  */
- 
+
 static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
 	struct mc32_local *lp;
 	int ioaddr, status, boguscount = 0;
+	int rx_event = 0;
+	int tx_event = 0; 
 	
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
 		return;
 	}
+ 
 	ioaddr = dev->base_addr;
 	lp = (struct mc32_local *)dev->priv;
 
 	/* See whats cooking */
-	
-	while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000)
+
+	while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000)
 	{
 		status=inb(ioaddr+HOST_CMD);
 
 #ifdef DEBUG_IRQ		
-		printk("Status TX%d RX%d EX%d OV%d\n",
+		printk("Status TX%d RX%d EX%d OV%d BC%d\n",
 			(status&7), (status>>3)&7, (status>>6)&1,
-			(status>>7)&1);
+			(status>>7)&1, boguscount);
 #endif
 			
 		switch(status&7)
@@ -1157,32 +1369,16 @@
 			case 0:
 				break;
 			case 6: /* TX fail */
-				lp->net_stats.tx_errors++;
 			case 2:	/* TX ok */
-				lp->net_stats.tx_packets++;
-				/* Packets are sent in order - this is
-				   basically a FIFO queue of buffers matching
-				   the card ring */
-				lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len;
-				dev_kfree_skb_irq(lp->tx_skb[lp->tx_skb_top]);
-				lp->tx_skb[lp->tx_skb_top]=NULL;
-				lp->tx_skb_top++;
-				lp->tx_skb_top&=(TX_RING_MAX-1);
-				atomic_inc(&lp->tx_count);
-				netif_wake_queue(dev);
+				tx_event = 1; 
 				break;
 			case 3: /* Halt */
 			case 4: /* Abort */
-				lp->tx_halted=1;
-				wake_up(&lp->event);
-				break;
-			case 5:
-				lp->tx_halted=0;
+				lp->xceiver_state |= TX_HALTED; 
 				wake_up(&lp->event);
 				break;
 			default:
-				printk("%s: strange tx ack %d\n", 
-					dev->name, status&7);
+				printk("%s: strange tx ack %d\n", dev->name, status&7);
 		}
 		status>>=3;
 		switch(status&7)
@@ -1190,87 +1386,87 @@
 			case 0:
 				break;
 			case 2:	/* RX */
-				lp->rx_pending=1;
-				if(!lp->rx_halted)
-				{
-					/*
-					 *	Halt ring receive
-					 */
-					while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-					outb(3<<3, ioaddr+HOST_CMD);
-				}
+				rx_event=1; 
 				break;
-			case 3:
-			case 4:
-				lp->rx_halted=1;
-				wake_up(&lp->event);
-				break;
-			case 5:
-				lp->rx_halted=0;
+			case 3: /* Halt */
+			case 4: /* Abort */
+				lp->xceiver_state |= RX_HALTED;
 				wake_up(&lp->event);
 				break;
 			case 6:
 				/* Out of RX buffers stat */
+				/* Must restart rx */
 				lp->net_stats.rx_dropped++;
-				lp->rx_pending=1;
-				/* Must restart */
-				lp->rx_halted=1;
+				mc32_rx_ring(dev); 
+				mc32_start_transceiver(dev); 
 				break;
 			default:
 				printk("%s: strange rx ack %d\n", 
-					dev->name, status&7);
-			
+					dev->name, status&7);			
 		}
 		status>>=3;
 		if(status&1)
 		{
+
 			/* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */
-			if(lp->exec_pending!=3)
+			
+			if(lp->exec_pending!=3) {
 				lp->exec_pending=2;
-			else
-				lp->exec_pending=0;
-			wake_up(&lp->event);
+				wake_up(&lp->event);
+			}
+			else 
+			{				
+			  	lp->exec_pending=0;
+
+				/* A new multicast set may have been
+				   blocked while the old one was
+				   running. If so, do it now. */
+				   
+				if (lp->mc_reload_wait) 
+					mc32_reset_multicast_list(dev);
+				else 
+					wake_up(&lp->event);			       
+			}
 		}
 		if(status&2)
 		{
 			/*
-			 *	Update the stats as soon as
-			 *	we have it flagged and can 
-			 *	send an immediate reply (CRR set)
+			 *	We get interrupted once per
+			 *	counter that is about to overflow. 
 			 */
-			 
-			if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)
-			{
-				mc32_update_stats(dev);
-				outb(0, ioaddr+HOST_CMD);
-			}
+
+			mc32_update_stats(dev);			
 		}
 	}
-	
+
+
 	/*
-	 *	Process and restart the receive ring. This has some state
-	 *	as we must halt the ring to process it and halting the ring
-	 *	might not occur in the same IRQ handling loop as we issue
-	 *	the halt.
-	 */
+	 *	Process the transmit and receive rings 
+         */
+
+	if(tx_event) 
+		mc32_tx_ring(dev);
 	 
-	if(lp->rx_pending && lp->rx_halted)
-	{
+	if(rx_event) 
 		mc32_rx_ring(dev);
-		lp->rx_pending = 0;
-	}
+
 	return;
 }
 
 
 /**
- *	mc32_close:
+ *	mc32_close	-	user configuring the 3c527 down
  *	@dev: 3c527 card to shut down
  *
  *	The 3c527 is a bus mastering device. We must be careful how we
  *	shut it down. It may also be running shared interrupt so we have
  *	to be sure to silence it properly
  *
+ *	We indicate that the card is closing to the rest of the
+ *	driver.  Otherwise, it is possible that the card may run out
+ *	of receive buffers and restart the transceiver while we're
+ *	trying to close it.
+ * 
  *	We abort any receive and transmits going on and then wait until
  *	any pending exec commands have completed in other code threads.
  *	In theory we can't get here while that is true, in practice I am
@@ -1279,93 +1475,104 @@
  *	We turn off the interrupt enable for the board to be sure it can't
  *	intefere with other devices.
  */
- 
+
 static int mc32_close(struct net_device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+
 	int ioaddr = dev->base_addr;
 	u8 regs;
 	u16 one=1;
-
-	netif_stop_queue(dev);
 	
+	lp->desired_state = HALTED;
+	netif_stop_queue(dev);
+
 	/*
 	 *	Send the indications on command (handy debug check)
 	 */
 
 	mc32_command(dev, 4, &one, 2);
 
-	/* Abort RX and Abort TX */
-	
-	mc32_rx_abort(dev);	
-	mc32_tx_abort(dev);
+	/* Shut down the transceiver */
+
+	mc32_halt_transceiver(dev); 
 	
 	/* Catch any waiting commands */
 	
 	while(lp->exec_pending==1)
 		sleep_on(&lp->event);
-		
+	       
 	/* Ok the card is now stopping */	
 	
 	regs=inb(ioaddr+HOST_CTRL);
 	regs&=~HOST_CTRL_INTE;
 	outb(regs, ioaddr+HOST_CTRL);
 
-	mc32_flush_rx_ring(lp);
-	mc32_flush_tx_ring(lp);
-	
-	/* Update the statistics here. */
+	mc32_flush_rx_ring(dev);
+	mc32_flush_tx_ring(dev);
+		
+	mc32_update_stats(dev); 
 
 	return 0;
-
 }
 
+
 /**
- *	mc32_get_stats:
+ *	mc32_get_stats		-	hand back stats to network layer
  *	@dev: The 3c527 card to handle
  *
- *	As we currently handle our statistics in software this one is
- *	easy to handle. With hardware statistics it will get messy
- *	as the get_stats call will need to send exec mailbox messages and
- *	need to lock out the multicast reloads.
+ *	We've collected all the stats we can in software already. Now
+ *	it's time to update those kept on-card and return the lot. 
+ * 
  */
 
 static struct net_device_stats *mc32_get_stats(struct net_device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp;
+	
+	mc32_update_stats(dev); 
+
+	lp = (struct mc32_local *)dev->priv;
+
 	return &lp->net_stats;
 }
 
+
 /**
- *	do_mc32_set_multicast_list:
+ *	do_mc32_set_multicast_list	-	attempt to update multicasts
  *	@dev: 3c527 device to load the list on
  *	@retry: indicates this is not the first call. 
  *
- * Actually set or clear the multicast filter for this adaptor. The locking
- * issues are handled by this routine. We have to track state as it may take
- * multiple calls to get the command sequence completed. We just keep trying
- * to schedule the loads until we manage to process them all.
  *
- * num_addrs == -1	Promiscuous mode, receive all packets
+ * 	Actually set or clear the multicast filter for this adaptor. The
+ *	locking issues are handled by this routine. We have to track
+ *	state as it may take multiple calls to get the command sequence
+ *	completed. We just keep trying to schedule the loads until we
+ *	manage to process them all.
+ * 
+ *	num_addrs == -1	Promiscuous mode, receive all packets
+ * 
+ *	num_addrs == 0	Normal mode, clear multicast list
+ * 
+ *	num_addrs > 0	Multicast mode, receive normal and MC packets, 
+ *			and do best-effort filtering. 
  *
- * num_addrs == 0	Normal mode, clear multicast list
+ *	See mc32_update_stats() regards setting the SAV BP bit. 
  *
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
  */
 
 static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	u16 filt;
+	u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ 
 
 	if (dev->flags&IFF_PROMISC)
 		/* Enable promiscuous mode */
-		filt = 1;
+		filt |= 1;
 	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)
 	{
 		dev->flags|=IFF_PROMISC;
-		filt = 1;
+		filt |= 1;
 	}
 	else if(dev->mc_count)
 	{
@@ -1374,9 +1581,7 @@
 		struct dev_mc_list *dmc=dev->mc_list;
 		
 		int i;
-		
-		filt = 0;
-		
+	       
 		if(retry==0)
 			lp->mc_list_valid = 0;
 		if(!lp->mc_list_valid)
@@ -1399,39 +1604,40 @@
 			lp->mc_list_valid=1;
 		}
 	}
-	else 
-	{
-		filt = 0;
-	}
-	if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+	
+	if(mc32_command_nowait(dev, 0, &filt, 2)==-1) 
 	{
 		lp->mc_reload_wait = 1;
+	} 
+	else { 
+		lp->mc_reload_wait = 0;
 	}
 }
 
+
 /**
- *	mc32_set_multicast_list:
+ *	mc32_set_multicast_list	-	queue multicast list update
  *	@dev: The 3c527 to use
  *
  *	Commence loading the multicast list. This is called when the kernel
  *	changes the lists. It will override any pending list we are trying to
  *	load.
  */
- 
+
 static void mc32_set_multicast_list(struct net_device *dev)
 {
 	do_mc32_set_multicast_list(dev,0);
 }
 
+
 /**
- *	mc32_reset_multicast_list:
+ *	mc32_reset_multicast_list	-	reset multicast list
  *	@dev: The 3c527 to use
  *
  *	Attempt the next step in loading the multicast lists. If this attempt
  *	fails to complete then it will be scheduled and this function called
  *	again later from elsewhere.
  */
- 
 
 static void mc32_reset_multicast_list(struct net_device *dev)
 {
@@ -1442,19 +1648,18 @@
 
 static struct net_device this_device;
 
-
 /**
- *	init_module:
+ *	init_module		-	entry point
  *
  *	Probe and locate a 3c527 card. This really should probe and locate
  *	all the 3c527 cards in the machine not just one of them. Yes you can
- *	insmod multiple modules for now but its a hack.
+ *	insmod multiple modules for now but it's a hack.
  */
- 
+
 int init_module(void)
 {
 	int result;
-
+	
 	this_device.init = mc32_probe;
 	if ((result = register_netdev(&this_device)) != 0)
 		return result;
@@ -1463,7 +1668,7 @@
 }
 
 /**
- *	cleanup_module:
+ *	cleanup_module	-	free resources for an unload
  *
  *	Unloading time. We release the MCA bus resources and the interrupt
  *	at which point everything is ready to unload. The card must be stopped
@@ -1472,7 +1677,7 @@
  *	initialized it must be rebooted or the rings reloaded before any
  *	transmit operations are allowed to start scribbling into memory.
  */
- 
+
 void cleanup_module(void)
 {
 	int slot;
@@ -1493,6 +1698,7 @@
 		kfree(this_device.priv);
 	}
 	free_irq(this_device.irq, &this_device);
+	release_region(this_device.base_addr, MC32_IO_EXTENT);
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c527.h linux/drivers/net/3c527.h
--- v2.4.2/linux/drivers/net/3c527.h	Sun Mar 21 07:11:36 1999
+++ linux/drivers/net/3c527.h	Sun Mar  4 14:05:04 2001
@@ -7,11 +7,19 @@
  */
   
 #define HOST_CMD		0
+#define         HOST_CMD_START_RX   (1<<3)
+#define         HOST_CMD_SUSPND_RX  (3<<3)
+#define         HOST_CMD_RESTRT_RX  (5<<3)
+
+#define         HOST_CMD_SUSPND_TX  3
+#define         HOST_CMD_RESTRT_TX  5
+
 
 #define HOST_STATUS		2
 #define		HOST_STATUS_CRR	(1<<6)
 #define		HOST_STATUS_CWR	(1<<5)
 
+
 #define HOST_CTRL		6
 #define		HOST_CTRL_ATTN	(1<<7)
 #define 	HOST_CTRL_RESET	(1<<6)
@@ -19,6 +27,17 @@
 
 #define HOST_RAMPAGE		8
 
+#define RX_HALTED (1<<0)
+#define TX_HALTED (1<<1)  
+#define HALTED (RX_HALTED | TX_HALTED)
+#define RUNNING 0
+
+struct mc32_mailbox
+{
+	u16	mbox __attribute((packed));
+	u16	data[1] __attribute((packed));
+};
+
 struct skb_header
 {
 	u8	status __attribute((packed));
@@ -28,13 +47,37 @@
 	u32	data __attribute((packed));
 };
 
-#define STATUS_MASK	0x0F
-#define COMPLETED	0x80
-#define COMPLETED_OK	0x40
-#define BUFFER_BUSY	0x20
+struct mc32_stats
+{
+	/* RX Errors */
+	u32     rx_crc_errors       __attribute((packed)); 	
+	u32     rx_alignment_errors  __attribute((packed)); 	
+	u32     rx_overrun_errors    __attribute((packed));
+	u32     rx_tooshort_errors  __attribute((packed));
+	u32     rx_toolong_errors   __attribute((packed));
+	u32     rx_outofresource_errors  __attribute((packed)); 
+
+	u32     rx_discarded   __attribute((packed));  /* via card pattern match filter */ 
+
+	/* TX Errors */
+	u32     tx_max_collisions __attribute((packed)); 
+	u32     tx_carrier_errors __attribute((packed)); 
+	u32     tx_underrun_errors __attribute((packed)); 
+	u32     tx_cts_errors     __attribute((packed)); 
+	u32     tx_timeout_errors __attribute((packed)) ;
+	
+	/* various cruft */
+	u32     dataA[6] __attribute((packed));   
+        u16	dataB[5] __attribute((packed));   
+  	u32     dataC[14] __attribute((packed)); 	
+};
 
-#define CONTROL_EOP	0x80	/* End Of Packet */
-#define CONTROL_EL	0x40	/* End of List */
+#define STATUS_MASK	0x0F
+#define COMPLETED	(1<<7)
+#define COMPLETED_OK	(1<<6)
+#define BUFFER_BUSY	(1<<5)
 
+#define CONTROL_EOP	(1<<7)	/* End Of Packet */
+#define CONTROL_EOL	(1<<6)	/* End of List */
 
-#define MCA_MC32_ID	0x0041	/* Our MCA ident */
\ No newline at end of file
+#define MCA_MC32_ID	0x0041	/* Our MCA ident */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.4.2/linux/drivers/net/3c59x.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/3c59x.c	Tue Mar  6 19:28:33 2001
@@ -118,7 +118,7 @@
    LK1.1.11 13 Nov 2000 andrewm
     - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER
 
-   LK1.1.12 1 Jan 2001 andrewm
+   LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1)
     - Call pci_enable_device before we request our IRQ (Tobias Ringstrom)
     - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra)
     - Added extended wait_for_completion for the 3c905CX.
@@ -126,12 +126,28 @@
     - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger)
     - Don't free skbs we don't own on oom path in vortex_open().
 
+   LK1.1.13 27 Jan 2001
+    - Added explicit `medialock' flag so we can truly
+      lock the media type down with `options'.
+    - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo <acme@conectiva.com.br>)
+    - Added and used EEPROM_NORESET for 3c556B PM resumes.
+    - Fixed leakage of vp->rx_ring.
+    - Break out separate HAS_HWCKSM device capability flag.
+    - Kill vp->tx_full (ANK)
+    - Merge zerocopy fragment handling (ANK?)
+
+   LK1.1.14 15 Feb 2001
+    - Enable WOL.  Can be turned on with `enable_wol' module option.
+    - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul)
+    - If a device's internalconfig register reports it has NWAY,
+      use it, even if autoselect is enabled.
+
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
     - Also see Documentation/networking/vortex.txt
 */
 
 /*
- * FIXME: This driver _could_ support MTU changing, but doesn't.  See Don's hamaci.c implementation
+ * FIXME: This driver _could_ support MTU changing, but doesn't.  See Don's hamachi.c implementation
  * as well as other drivers
  *
  * NOTE: If you make 'vortex_debug' a constant (#define vortex_debug 0) the driver shrinks by 2k
@@ -154,15 +170,11 @@
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 32;
 /* Tx timeout interval (millisecs) */
-static int watchdog = 400;
+static int watchdog = 5000;
 
 /* Allow aggregation of Tx interrupts.  Saves CPU load at the cost
  * of possible Tx stalls if the system is blocking interrupts
  * somewhere else.  Undefine this to disable.
- * AKPM 26 April 2000: enabling this still gets vestigial Tx timeouts
- * in a heavily loaded (collision-prone) 10BaseT LAN.  Should be OK with
- * switched Ethernet.
- * AKPM 24May00: vestigial timeouts have been removed by later fixes.
  */
 #define tx_interrupt_mitigation 1
 
@@ -174,10 +186,6 @@
 static int vortex_debug = 1;
 #endif
 
-/* Some values here only for performance evaluation and path-coverage
-   debugging. */
-static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
-
 #ifndef __OPTIMIZE__
 #error You must compile this file with the correct options!
 #error See the last lines of the source file.
@@ -211,14 +219,16 @@
 #include <linux/delay.h>
 
 static char version[] __devinitdata =
-"3c59x.c:LK1.1.12 06 Jan 2000  Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.46 $\n";
+"3c59x.c:LK1.1.13 27 Jan 2001  Donald Becker and others. http://www.scyld.com/network/vortex.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(hw_checksums, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(flow_ctrl, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(compaq_ioaddr, "i");
@@ -332,7 +342,7 @@
 	EEPROM_8BIT=0x10,	/* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
 	HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
 	INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
-	EEPROM_OFFSET=0x1000 };
+	EEPROM_OFFSET=0x1000, EEPROM_NORESET=0x2000, HAS_HWCKSM=0x4000 };
 
 enum vortex_chips {
 	CH_3C590 = 0,
@@ -405,58 +415,65 @@
 	{"3c900 Boomerang 10Mbps Combo",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, },
 	{"3c900 Cyclone 10Mbps TPO",						/* AKPM: from Don's 0.99M */
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
 	{"3c900 Cyclone 10Mbps Combo",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 
 	{"3c900 Cyclone 10Mbps TPC",						/* AKPM: from Don's 0.99M */
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 	{"3c900B-FL Cyclone 10base-FL",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 	{"3c905 Boomerang 100baseTx",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
 	{"3c905 Boomerang 100baseT4",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, },
 	{"3c905B Cyclone 100baseTx",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
 
 	{"3c905B Cyclone 10/100/BNC",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
 	{"3c905B-FX Cyclone 100baseFx",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 	{"3c905C Tornado",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 	{"3c980 Cyclone",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 	{"3c980 10/100 Base-TX NIC(Python-T)",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 
 	{"3cSOHO100-TX Hurricane",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
 	{"3c555 Laptop Hurricane",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
 	{"3c556 Laptop Tornado",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
+									HAS_HWCKSM, 128, },
 	{"3c556B Laptop Hurricane",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
+									EEPROM_NORESET|HAS_HWCKSM, 128, },
 	{"3c575 [Megahertz] 10/100 LAN 	CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+	PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
 
 	{"3c575 Boomerang CardBus",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
 	{"3CCFE575BT Cyclone CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
+									INVERT_LED_PWR|HAS_HWCKSM, 128, },
 	{"3CCFE575CT Tornado CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
 	{"3CCFE656 Cyclone CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+									INVERT_LED_PWR|HAS_HWCKSM, 128, },
 	{"3CCFEM656B Cyclone+Winmodem CardBus",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+									INVERT_LED_PWR|HAS_HWCKSM, 128, },
 
 	{"3CXFEM656C Tornado+Winmodem CardBus",			/* From pcmcia-cs-3.1.5 */
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
 	{"3c450 HomePNA Tornado",						/* AKPM: from Don's 0.99Q */
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, },
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 	{0,}, /* 0 terminated list. */
 };
 
@@ -631,11 +648,24 @@
 	IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
 };
 
+#ifdef MAX_SKB_FRAGS
+#define DO_ZEROCOPY 1
+#else
+#define DO_ZEROCOPY 0
+#endif
+
 struct boom_tx_desc {
 	u32 next;					/* Last entry points to 0.   */
 	s32 status;					/* bits 0:12 length, others see below.  */
-	u32 addr;
-	s32 length;
+#if DO_ZEROCOPY
+	struct {
+		u32 addr;
+		s32 length;
+	} frag[1+MAX_SKB_FRAGS];
+#else
+		u32 addr;
+		s32 length;
+#endif
 };
 
 /* Values for the Tx status entry. */
@@ -668,6 +698,10 @@
 	struct pci_dev *pdev;
 	char *cb_fn_base;					/* CardBus function status addr space. */
 
+	/* Some values here only for performance evaluation and path-coverage */
+	int rx_nocopy, rx_copy, queued_packet, rx_csumhits;
+	int card_idx;
+
 	/* The remainder are related to chip state, mostly media selection. */
 	struct timer_list timer;			/* Media selection timer. */
 	struct timer_list rx_oom_timer;		/* Rx skb allocation retry timer */
@@ -679,9 +713,10 @@
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
 		flow_ctrl:1,					/* Use 802.3x flow control (PAUSE only) */
 		partner_flow_ctrl:1,			/* Partner supports flow control */
-		tx_full:1,
 		has_nway:1,
+		enable_wol:1,					/* Wake-on-LAN is enabled */
 		open:1,
+		medialock:1,
 		must_free_region:1;				/* Flag: if zero, Cardbus owns the I/O region */
 	int drv_flags;
 	u16 status_enable;
@@ -755,7 +790,9 @@
 #define MAX_UNITS 8
 static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int hw_checksums[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 static int flow_ctrl[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 /* #define dev_alloc_skb dev_alloc_skb_debug */
 
@@ -828,8 +865,7 @@
 		}
 
 		rc = vortex_probe1(NULL, ioaddr, inw(ioaddr + 0xC88) >> 12,
-				   EISA_TBL_OFFSET,
-				   vortex_cards_found);
+				   EISA_TBL_OFFSET, vortex_cards_found);
 		if (rc == 0)
 			vortex_cards_found++;
 		else
@@ -889,9 +925,9 @@
 	}
 
 	dev = init_etherdev(NULL, sizeof(*vp));
+	retval = -ENOMEM;
 	if (!dev) {
 		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
-		retval = -ENOMEM;
 		goto out;
 	}
 	SET_MODULE_OWNER(dev);
@@ -909,6 +945,7 @@
 	vp->drv_flags = vci->drv_flags;
 	vp->has_nway = (vci->drv_flags & HAS_NWAY) ? 1 : 0;
 	vp->io_size = vci->io_size;
+	vp->card_idx = card_idx;
 
 	/* module list only for EISA devices */
 	if (pdev == NULL) {
@@ -953,10 +990,9 @@
 	vp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE
 					   + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
 					   &vp->rx_ring_dma);
-	if (vp->rx_ring == 0) {
-		retval = -ENOMEM;
+	retval = -ENOMEM;
+	if (vp->rx_ring == 0)
 		goto free_region;
-	}
 
 	vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
 	vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
@@ -964,7 +1000,7 @@
 	/* if we are a PCI driver, we store info in pdev->driver_data
 	 * instead of a module list */	
 	if (pdev)
-		pdev->driver_data = dev;
+		pci_set_drvdata(pdev, dev);
 
 	/* The lower four bits are the media type. */
 	if (dev->mem_start) {
@@ -982,6 +1018,8 @@
 	vp->media_override = 7;
 	if (option >= 0) {
 		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
+		if (vp->media_override != 7)
+			vp->medialock = 1;
 		vp->full_duplex = (option & 0x200) ? 1 : 0;
 		vp->bus_master = (option & 16) ? 1 : 0;
 	}
@@ -991,6 +1029,8 @@
 			vp->full_duplex = 1;
 		if (flow_ctrl[card_idx] > 0)
 			vp->flow_ctrl = 1;
+		if (enable_wol[card_idx] > 0)
+			vp->enable_wol = 1;
 	}
 
 	vp->force_fd = vp->full_duplex;
@@ -1049,7 +1089,7 @@
 
 	EL3WINDOW(4);
 	step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1;
-	printk(KERN_INFO "  product code '%c%c' rev %02x.%d date %02d-"
+	printk(KERN_INFO "  product code %02x%02x rev %02x.%d date %02d-"
 		   "%02d-%02d\n", eeprom[6]&0xff, eeprom[6]>>8, eeprom[0x14],
 		   step, (eeprom[4]>>5) & 15, eeprom[4] & 31, eeprom[4]>>9);
 
@@ -1059,8 +1099,12 @@
 		unsigned short n;
 
 		fn_st_addr = pci_resource_start (pdev, 2);
-		if (fn_st_addr)
+		if (fn_st_addr) {
 			vp->cb_fn_base = ioremap(fn_st_addr, 128);
+			retval = -ENOMEM;
+			if (!vp->cb_fn_base)
+				goto free_ring;
+		}
 		printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
 			   dev->name, fn_st_addr, vp->cb_fn_base);
 		EL3WINDOW(2);
@@ -1102,6 +1146,8 @@
 			   XCVR(config) > XCVR_ExtMII ? "<invalid transceiver>" :
 			   media_tbl[XCVR(config)].name);
 		vp->default_media = XCVR(config);
+		if (vp->default_media == XCVR_NWAY)
+			vp->has_nway = 1;
 		vp->autoselect = AUTOSELECT(config);
 	}
 
@@ -1154,7 +1200,7 @@
 		}
 	}
 
-	if (vp->capabilities & CapPwrMgmt)
+	if (pdev && vp->enable_wol && (vp->capabilities & CapPwrMgmt))
 		acpi_set_WOL(dev);
 
 	if (vp->capabilities & CapBusMaster) {
@@ -1167,21 +1213,44 @@
 
 	/* The 3c59x-specific entries in the device structure. */
 	dev->open = vortex_open;
-	dev->hard_start_xmit = vp->full_bus_master_tx ?
-					boomerang_start_xmit : vortex_start_xmit;
+	if (vp->full_bus_master_tx) {
+		dev->hard_start_xmit = boomerang_start_xmit;
+#ifndef CONFIG_HIGHMEM
+		/* Actually, it still should work with iommu. */
+		dev->features |= NETIF_F_SG;
+#endif
+		if (((hw_checksums[card_idx] == -1) && (vp->drv_flags & HAS_HWCKSM)) ||
+					(hw_checksums[card_idx] == 1)) {
+				dev->features |= NETIF_F_IP_CSUM;
+		}
+	} else {
+		dev->hard_start_xmit = vortex_start_xmit;
+	}
+
+	if (vortex_debug > 0) {
+		printk(KERN_INFO "%s: scatter/gather %sabled. h/w checksums %sabled\n",
+				dev->name,
+				(dev->features & NETIF_F_SG) ? "en":"dis",
+				(dev->features & NETIF_F_IP_CSUM) ? "en":"dis");
+	}
+
 	dev->stop = vortex_close;
 	dev->get_stats = vortex_get_stats;
 	dev->do_ioctl = vortex_ioctl;
 	dev->set_multicast_list = set_rx_mode;
 	dev->tx_timeout = vortex_tx_timeout;
 	dev->watchdog_timeo = (watchdog * HZ) / 1000;
-//	publish_netdev(dev);
 	return 0;
 
+free_ring:
+	pci_free_consistent(pdev,
+						sizeof(struct boom_rx_desc) * RX_RING_SIZE
+							+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
+						vp->rx_ring,
+						vp->rx_ring_dma);
 free_region:
 	if (vp->must_free_region)
 		release_region(ioaddr, vci->io_size);
-//	withdraw_netdev(dev);
 	unregister_netdev(dev);
 	kfree (dev);
 	printk(KERN_ERR PFX "vortex_probe1 fails.  Returns %d\n", retval);
@@ -1189,7 +1258,8 @@
 	return retval;
 }
 
-static void wait_for_completion(struct net_device *dev, int cmd)
+static void
+wait_for_completion(struct net_device *dev, int cmd)
 {
 	int i;
 
@@ -1202,7 +1272,8 @@
 	/* OK, that didn't work.  Do it the slow way.  One second */
 	for (i = 0; i < 100000; i++) {
 		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) {
-			printk(KERN_INFO "%s: command 0x%04x took %d usecs! Please tell andrewm@uow.edu.au\n",
+			if (vortex_debug > 1)
+				printk(KERN_INFO "%s: command 0x%04x took %d usecs\n",
 					   dev->name, cmd, i * 10);
 			return;
 		}
@@ -1218,26 +1289,23 @@
 	long ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	unsigned int config;
-	int i, device_id;
+	int i;
+
+	if (vp->pdev && vp->enable_wol)			/* AKPM: test not needed? */
+		pci_set_power_state(vp->pdev, 0);	/* Go active */
 
-	if (vp->pdev)
-		device_id = vp->pdev->device;
-	else
-		device_id = 0x5900; /* EISA */
-	
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
 	config = inl(ioaddr + Wn3_Config);
 
 	if (vp->media_override != 7) {
-		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
-				   dev->name, vp->media_override,
-				   media_tbl[vp->media_override].name);
+		printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
+			   dev->name, vp->media_override,
+			   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
 	} else if (vp->autoselect) {
 		if (vp->has_nway) {
-			printk(KERN_INFO "%s: using NWAY autonegotiation\n", dev->name);
+			printk(KERN_INFO "%s: using NWAY device table, not %d\n", dev->name, dev->if_port);
 			dev->if_port = XCVR_NWAY;
 		} else {
 			/* Find first available media type, starting with 100baseTx. */
@@ -1245,8 +1313,7 @@
 			while (! (vp->available_media & media_tbl[dev->if_port].mask))
 				dev->if_port = media_tbl[dev->if_port].next;
 			printk(KERN_INFO "%s: first available media type: %s\n",
-					dev->name,
-					media_tbl[dev->if_port].name);
+					dev->name, media_tbl[dev->if_port].name);
 		}
 	} else {
 		dev->if_port = vp->default_media;
@@ -1270,13 +1337,9 @@
 
 	vp->full_duplex = vp->force_fd;
 	config = BFINS(config, dev->if_port, 20, 4);
-//AKPM	if (!vp->has_nway)
-	{
-		if (vortex_debug > 6)
-			printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n",
-				config);
-		outl(config, ioaddr + Wn3_Config);
-	}
+	if (vortex_debug > 6)
+		printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config);
+	outl(config, ioaddr + Wn3_Config);
 
 	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
 		int mii_reg1, mii_reg5;
@@ -1292,8 +1355,10 @@
 		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
 		if (vortex_debug > 1)
 			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-				   " setting %s-duplex.\n", dev->name, vp->phys[0],
-				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
+				   " info1 %04x, setting %s-duplex.\n",
+					dev->name, vp->phys[0],
+					mii_reg1, mii_reg5,
+					vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half");
 		EL3WINDOW(3);
 	}
 
@@ -1411,6 +1476,9 @@
 	int i;
 	int retval;
 
+	if (vp->pdev && vp->enable_wol)				/* AKPM: test not needed? */
+		pci_set_power_state(vp->pdev, 0);		/* Go active */
+
 	/* Use the now-standard shared IRQ implementation. */
 	if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
 				&boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) {
@@ -1452,7 +1520,6 @@
 
 	vortex_up(dev);
 	vp->open = 1;
-	vp->tx_full = 0;
 	return 0;
 
 out_free_irq:
@@ -1463,7 +1530,8 @@
 	return retval;
 }
 
-static void vortex_timer(unsigned long data)
+static void
+vortex_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
@@ -1478,6 +1546,8 @@
 		printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
 	}
 
+	if (vp->medialock)
+		goto leave_media_alone;
 	disable_irq(dev->irq);
 	old_window = inw(ioaddr + EL3_CMD) >> 13;
 	EL3WINDOW(4);
@@ -1512,7 +1582,7 @@
 							dev->name, vp->full_duplex ? "full" : "half",
 							vp->phys[0], mii_reg5);
 						/* Set the full-duplex bit. */
-						EL3WINDOW(3);	/* AKPM: this was missing from 2.3.99 3c59x.c! */
+						EL3WINDOW(3);
 						outw(	(vp->full_duplex ? 0x20 : 0) |
 								(dev->mtu > 1500 ? 0x40 : 0) |
 								((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0),
@@ -1567,6 +1637,7 @@
 	EL3WINDOW(old_window);
 	enable_irq(dev->irq);
 
+leave_media_alone:
 	if (vortex_debug > 2)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
@@ -1599,8 +1670,7 @@
 		/* Bad idea here.. but we might as well handle a few events. */
 		{
 			/*
-			 * AKPM: block interrupts because vortex_interrupt
-			 * does a bare spin_lock()
+			 * Block interrupts because vortex_interrupt does a bare spin_lock()
 			 */
 			unsigned long flags;
 			local_irq_save(flags);
@@ -1619,18 +1689,12 @@
 
 	vp->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
-		if (vortex_debug > 0)
-			printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n",
-				   dev->name);
+		printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n", dev->name);
 		if (vp->cur_tx - vp->dirty_tx > 0  &&  inl(ioaddr + DownListPtr) == 0)
 			outl(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc),
 				 ioaddr + DownListPtr);
-		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
-			vp->tx_full = 0;
+		if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE)
 			netif_wake_queue (dev);
-		}
-		if (vp->tx_full)
-			netif_stop_queue (dev);
 		if (vp->drv_flags & IS_BOOMERANG)
 			outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
 		outw(DownUnstall, ioaddr + EL3_CMD);
@@ -1820,17 +1884,53 @@
 				   dev->name, vp->cur_tx);
 	}
 
-	if (vp->tx_full) {
+	if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
 		if (vortex_debug > 0)
-			printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
+			printk(KERN_WARNING "%s: BUG! Tx Ring full, refusing to send buffer.\n",
 				   dev->name);
+		netif_stop_queue(dev);
 		return 1;
 	}
+
 	vp->tx_skbuff[entry] = skb;
+
 	vp->tx_ring[entry].next = 0;
+#if DO_ZEROCOPY
+	if (skb->ip_summed != CHECKSUM_HW)
+			vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
+	else
+			vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum);
+
+	if (!skb_shinfo(skb)->nr_frags) {
+		vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data,
+										skb->len, PCI_DMA_TODEVICE));
+		vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len | LAST_FRAG);
+	} else {
+		int i;
+
+		vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data,
+										skb->len-skb->data_len, PCI_DMA_TODEVICE));
+		vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len-skb->data_len);
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			vp->tx_ring[entry].frag[i+1].addr =
+					cpu_to_le32(pci_map_single(vp->pdev,
+											   (void*)page_address(frag->page) + frag->page_offset,
+											   frag->size, PCI_DMA_TODEVICE));
+
+			if (i == skb_shinfo(skb)->nr_frags-1)
+					vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size|LAST_FRAG);
+			else
+					vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(frag->size);
+		}
+	}
+#else
 	vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE));
 	vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
 	vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
+#endif
 
 	spin_lock_irqsave(&vp->lock, flags);
 	/* Wait for the stall to complete. */
@@ -1838,18 +1938,19 @@
 	prev_entry->next = cpu_to_le32(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc));
 	if (inl(ioaddr + DownListPtr) == 0) {
 		outl(vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);
-		queued_packet++;
+		vp->queued_packet++;
 	}
 
 	vp->cur_tx++;
 	if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) {
-		vp->tx_full = 1;
 		netif_stop_queue (dev);
 	} else {					/* Clear previous interrupt enable. */
 #if defined(tx_interrupt_mitigation)
+		/* Dubious. If in boomeang_interrupt "faster" cyclone ifdef
+		 * were selected, this would corrupt DN_COMPLETE. No?
+		 */
 		prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
 #endif
-		/* netif_start_queue (dev); */		/* AKPM: redundant? */
 	}
 	outw(DownUnstall, ioaddr + EL3_CMD);
 	spin_unlock_irqrestore(&vp->lock, flags);
@@ -1889,7 +1990,7 @@
 		vp->deferred = 0;
 	}
 
-	if (status == 0xffff)		/* AKPM: h/w no longer present (hotplug)? */
+	if (status == 0xffff)		/* h/w no longer present (hotplug)? */
 		goto handler_exit;
 
 	if (vortex_debug > 4)
@@ -1925,7 +2026,7 @@
 					netif_wake_queue(dev);
 				} else { /* Interrupt when FIFO has room for max-sized packet. */
 					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
-					netif_stop_queue(dev);		/* AKPM: This is new */
+					netif_stop_queue(dev);
 				}
 			}
 		}
@@ -1990,7 +2091,7 @@
 	if ((status & IntLatch) == 0)
 		goto handler_exit;		/* No interrupt: shared IRQs can cause this */
 
-	if (status == 0xffff) {		/* AKPM: h/w no longer present (hotplug)? */
+	if (status == 0xffff) {		/* h/w no longer present (hotplug)? */
 		if (vortex_debug > 1)
 			printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
 		goto handler_exit;
@@ -2032,9 +2133,17 @@
 					
 				if (vp->tx_skbuff[entry]) {
 					struct sk_buff *skb = vp->tx_skbuff[entry];
-					
+#if DO_ZEROCOPY					
+					int i;
+					for (i=0; i<=skb_shinfo(skb)->nr_frags; i++)
+							pci_unmap_single(vp->pdev,
+											 le32_to_cpu(vp->tx_ring[entry].frag[i].addr),
+											 le32_to_cpu(vp->tx_ring[entry].frag[i].length)&0xFFF,
+											 PCI_DMA_TODEVICE);
+#else
 					pci_unmap_single(vp->pdev,
 						le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE);
+#endif
 					dev_kfree_skb_irq(skb);
 					vp->tx_skbuff[entry] = 0;
 				} else {
@@ -2044,10 +2153,9 @@
 				dirty_tx++;
 			}
 			vp->dirty_tx = dirty_tx;
-			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+			if (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1) {
 				if (vortex_debug > 6)
-					printk(KERN_DEBUG "boomerang_interrupt: clearing tx_full\n");
-				vp->tx_full = 0;
+					printk(KERN_DEBUG "boomerang_interrupt: wake queue\n");
 				netif_wake_queue (dev);
 			}
 		}
@@ -2199,14 +2307,14 @@
 				memcpy(skb_put(skb, pkt_len),
 					   vp->rx_skbuff[entry]->tail,
 					   pkt_len);
-				rx_copy++;
+				vp->rx_copy++;
 			} else {
 				/* Pass up the skbuff already on the Rx ring. */
 				skb = vp->rx_skbuff[entry];
 				vp->rx_skbuff[entry] = NULL;
 				skb_put(skb, pkt_len);
 				pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
-				rx_nocopy++;
+				vp->rx_nocopy++;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			{					/* Use hardware checksum info. */
@@ -2215,7 +2323,7 @@
 					(csum_bits == (IPChksumValid | TCPChksumValid) ||
 					 csum_bits == (IPChksumValid | UDPChksumValid))) {
 					skb->ip_summed = CHECKSUM_UNNECESSARY;
-					rx_csumhits++;
+					vp->rx_csumhits++;
 				}
 			}
 			netif_rx(skb);
@@ -2301,7 +2409,7 @@
 	if (vp->full_bus_master_tx)
 		outl(0, ioaddr + DownListPtr);
 
-	if (vp->capabilities & CapPwrMgmt)
+	if (vp->pdev && vp->enable_wol && (vp->capabilities & CapPwrMgmt))
 		acpi_set_WOL(dev);
 }
 
@@ -2320,9 +2428,18 @@
 			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
 		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
 			   " tx_queued %d Rx pre-checksummed %d.\n",
-			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
+			   dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits);
 	}
 
+#if DO_ZEROCOPY
+	if (	vp->rx_csumhits &&
+			((vp->drv_flags & HAS_HWCKSM) == 0) &&
+			(hw_checksums[vp->card_idx] == -1)) {
+		printk(KERN_WARNING "%s supports hardware checksums, and we're not using them!\n", dev->name);
+		printk(KERN_WARNING "Please see http://www.uow.edu.au/~andrewm/zerocopy.html\n");
+	}
+#endif
+		
 	free_irq(dev->irq, dev);
 
 	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
@@ -2335,14 +2452,24 @@
 			}
 	}
 	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
-		for (i = 0; i < TX_RING_SIZE; i++)
+		for (i = 0; i < TX_RING_SIZE; i++) {
 			if (vp->tx_skbuff[i]) {
 				struct sk_buff *skb = vp->tx_skbuff[i];
+#if DO_ZEROCOPY
+				int k;
 
+				for (k=0; k<=skb_shinfo(skb)->nr_frags; k++)
+						pci_unmap_single(vp->pdev,
+										 le32_to_cpu(vp->tx_ring[i].frag[k].addr),
+										 le32_to_cpu(vp->tx_ring[i].frag[k].length)&0xFFF,
+										 PCI_DMA_TODEVICE);
+#else
 				pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE);
+#endif
 				dev_kfree_skb(skb);
 				vp->tx_skbuff[i] = 0;
 			}
+		}
 	}
 
 	vp->open = 0;
@@ -2360,19 +2487,22 @@
 			int i;
 			int stalled = inl(ioaddr + PktStatus) & 0x04;	/* Possible racy. But it's only debug stuff */
 
-			wait_for_completion(dev, DownStall);
-			printk(KERN_ERR "  Flags; bus-master %d, full %d; dirty %d(%d) "
-					"current %d(%d).\n",
-					vp->full_bus_master_tx, vp->tx_full,
+			printk(KERN_ERR "  Flags; bus-master %d, dirty %d(%d) current %d(%d)\n",
+					vp->full_bus_master_tx,
 					vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
 					vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
 			printk(KERN_ERR "  Transmit list %8.8x vs. %p.\n",
 				   inl(ioaddr + DownListPtr),
 				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+			wait_for_completion(dev, DownStall);
 			for (i = 0; i < TX_RING_SIZE; i++) {
 				printk(KERN_ERR "  %d: @%p  length %8.8x status %8.8x\n", i,
 					   &vp->tx_ring[i],
+#if DO_ZEROCOPY
+					   le32_to_cpu(vp->tx_ring[i].frag[0].length),
+#else
 					   le32_to_cpu(vp->tx_ring[i].length),
+#endif
 					   le32_to_cpu(vp->tx_ring[i].status));
 			}
 			if (!stalled)
@@ -2436,8 +2566,6 @@
 		vp->stats.tx_bytes += (up & 0xf0) << 12;
 	}
 
-	/* We change back to window 7 (not 1) with the Vortex. */
-	/* AKPM: the previous comment is obsolete - we switch back to the old window */
 	EL3WINDOW(old_window >> 13);
 	return;
 }
@@ -2600,12 +2728,6 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 
-	/* AKPM: This kills the 905 */
-	if (vortex_debug > 1) {
-		printk(KERN_INFO PFX "Wake-on-LAN functions disabled\n");
-	}
-	return;
-
 	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
 	EL3WINDOW(7);
 	outw(2, ioaddr + 0x0c);
@@ -2613,13 +2735,13 @@
 	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
 	outw(RxEnable, ioaddr + EL3_CMD);
 	/* Change the power state to D3; RxEnable doesn't take effect. */
-	pci_write_config_word(vp->pdev, 0xe0, 0x8103);
+	pci_set_power_state(vp->pdev, 0x8103);
 }
 
 
 static void __devexit vortex_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct vortex_private *vp;
 
 	if (!dev) {
@@ -2627,14 +2749,20 @@
 		BUG();
 	}
 
-	vp = (void *)(dev->priv);
+	vp = dev->priv;
 
 	/* AKPM: FIXME: we should have
 	 *	if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
 	 * here
 	 */
 	unregister_netdev(dev);
-	outw(TotalReset, dev->base_addr + EL3_CMD);
+	/* Should really use wait_for_completion() here */
+	outw((vp->drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset, dev->base_addr + EL3_CMD);
+	pci_free_consistent(pdev,
+						sizeof(struct boom_rx_desc) * RX_RING_SIZE
+							+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
+						vp->rx_ring,
+						vp->rx_ring_dma);
 	if (vp->must_free_region)
 		release_region(dev->base_addr, vp->io_size);
 	kfree(dev);
@@ -2642,7 +2770,7 @@
 
 
 static struct pci_driver vortex_driver = {
-	name:		"3c575_cb",
+	name:		"3c59x",
 	probe:		vortex_init_one,
 	remove:		vortex_remove_one,
 	suspend:	vortex_suspend,
@@ -2657,18 +2785,17 @@
 
 static int __init vortex_init (void)
 {
-	int rc;
-	
-	rc = pci_module_init(&vortex_driver);
-	if (rc < 0) {
-		rc = vortex_eisa_init();
-		if (rc > 0)
-			vortex_have_eisa = 1;
-	} else {
+	int pci_rc, eisa_rc;
+
+	pci_rc = pci_module_init(&vortex_driver);
+	eisa_rc = vortex_eisa_init();
+
+	if (pci_rc == 0)
 		vortex_have_pci = 1;
-	}
+	if (eisa_rc > 0)
+		vortex_have_eisa = 1;
 
-	return rc;
+	return (vortex_have_pci + vortex_have_eisa) ? 0 : -ENODEV;
 }
 
 
@@ -2707,7 +2834,6 @@
 
 module_init(vortex_init);
 module_exit(vortex_cleanup);
-
 
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/8139too.c linux/drivers/net/8139too.c
--- v2.4.2/linux/drivers/net/8139too.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/8139too.c	Tue Mar  6 19:28:33 2001
@@ -3,14 +3,15 @@
 	8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux.
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2000,2001 Jeff Garzik
 
 	Much code comes from Donald Becker's rtl8139.c driver,
-	versions 1.11 and older.  This driver was originally based
-	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.11:
+	versions 1.13 and older.  This driver was originally based
+	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.13:
 
 	-----<snip>-----
 
-        	Written 1997-2000 by Donald Becker.
+        	Written 1997-2001 by Donald Becker.
 		This software may be used and distributed according to the
 		terms of the GNU General Public License (GPL), incorporated
 		herein by reference.  Drivers based on or derived from this
@@ -74,7 +75,7 @@
 		
 		Tobias Ringström - Rx interrupt status checking suggestion
 
-		Andrew Morton - (v0.9.13): clear blocked signals, avoid
+		Andrew Morton - Clear blocked signals, avoid
 		buffer overrun setting current->comm.
 
 	Submitting bug reports:
@@ -150,7 +151,7 @@
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.13"
+#define RTL8139_VERSION "0.9.15"
 #define MODNAME "8139too"
 #define RTL8139_DRIVER_NAME   MODNAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX MODNAME ": "
@@ -188,7 +189,9 @@
 
 /* A few user-configurable values. */
 /* media options */
-static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[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;
@@ -230,6 +233,7 @@
 
 
 enum {
+	HAS_MII_XCVR = 0x010000,
 	HAS_CHIP_XCVR = 0x020000,
 	HAS_LNK_CHNG = 0x040000,
 };
@@ -237,6 +241,7 @@
 #define RTL_MIN_IO_SIZE 0x80
 #define RTL8139B_IO_SIZE 256
 
+#define RTL8129_CAPS	HAS_MII_XCVR
 #define RTL8139_CAPS	HAS_CHIP_XCVR|HAS_LNK_CHNG
 
 typedef enum {
@@ -246,19 +251,24 @@
 	/*MPX5030,*/
 	DELTA8139,
 	ADDTRON8139,
+	DFE538TX,
+	RTL8129,
 } board_t;
 
 
 /* indexed by board_t, above */
 static struct {
 	const char *name;
+	u32 hw_flags;
 } board_info[] __devinitdata = {
-	{ "RealTek RTL8139 Fast Ethernet" },
-	{ "RealTek RTL8139B PCI/CardBus" },
-	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
-/*	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/
-	{ "Delta Electronics 8139 10/100BaseTX" },
-	{ "Addtron Technolgy 8139 10/100BaseTX" },
+	{ "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS },
+	{ "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS },
+	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS },
+/*	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/
+	{ "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
+	{ "RealTek RTL8129", RTL8129_CAPS },
 };
 
 
@@ -269,6 +279,15 @@
 /*	{0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/
 	{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
 	{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
+	{0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX },
+	{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
+
+	/* some crazy cards report invalid vendor ids like
+	 * 0x0001 here.  The other ids are valid and constant,
+	 * so we simply don't match on the main vendor id.
+	 */
+	{PCI_ANY_ID, 0x8139, 0x10ec, 0x8139, 0, 0, RTL8139 },
+
 	{0,}
 };
 MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
@@ -504,7 +523,6 @@
 
 
 struct rtl8139_private {
-	board_t board;
 	void *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
@@ -512,15 +530,16 @@
 	unsigned char *rx_ring;
 	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
 	unsigned int tx_flag;
-	unsigned int cur_tx;
-	unsigned int dirty_tx;
+	unsigned long cur_tx;
+	unsigned long dirty_tx;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct ring_info tx_info[NUM_TX_DESC];
 	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
 	unsigned char *tx_bufs;	/* Tx bounce buffer region. */
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_bufs_dma;
-	char phys[4];		/* MII device addresses. */
+	signed char phys[4];		/* MII device addresses. */
+	u16 advertising;		/* NWay media advertisement */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
@@ -539,7 +558,8 @@
 MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
-MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
 static int read_eeprom (void *ioaddr, int location, int addr_len);
 static int rtl8139_open (struct net_device *dev);
@@ -658,6 +678,11 @@
 	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;
+
 	pio_start = pci_resource_start (pdev, 0);
 	pio_end = pci_resource_end (pdev, 0);
 	pio_flags = pci_resource_flags (pdev, 0);
@@ -697,25 +722,11 @@
 		goto err_out;
 	}
 
-	/* make sure our PIO region in PCI space is available */
-	if (!request_region (pio_start, pio_len, dev->name)) {
-		printk (KERN_ERR PFX "no I/O resource available, aborting\n");
-		rc = -EBUSY;
-		goto err_out;
-	}
-
-	/* make sure our MMIO region in PCI space is available */
-	if (!request_mem_region (mmio_start, mmio_len, dev->name)) {
-		printk (KERN_ERR PFX "no mem resource available, aborting\n");
-		rc = -EBUSY;
-		goto err_out_free_pio;
-	}
-
-	/* enable device (incl. PCI PM wakeup), and bus-mastering */
-	rc = pci_enable_device (pdev);
+	rc = pci_request_regions (pdev, dev->name);
 	if (rc)
-		goto err_out_free_mmio;
+		goto err_out;
 
+	/* enable PCI bus-mastering */
 	pci_set_master (pdev);
 
 #ifdef USE_IO_OPS
@@ -726,7 +737,7 @@
 	if (ioaddr == NULL) {
 		printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
 		rc = -EIO;
-		goto err_out_free_mmio;
+		goto err_out_free_res;
 	}
 #endif /* USE_IO_OPS */
 
@@ -792,11 +803,9 @@
 	assert (ioaddr > 0);
 #ifndef USE_IO_OPS
 	iounmap (ioaddr);
+err_out_free_res:
 #endif /* !USE_IO_OPS */
-err_out_free_mmio:
-	release_mem_region (mmio_start, mmio_len);
-err_out_free_pio:
-	release_region (pio_start, pio_len);
+	pci_release_regions (pdev);
 err_out:
 	unregister_netdev (dev);
 	kfree (dev);
@@ -813,7 +822,7 @@
 	int i, addr_len, option;
 	void *ioaddr = NULL;
 	static int board_idx = -1;
-	static int printed_version = 0;
+	static int printed_version;
 	u8 tmp;
 
 	DPRINTK ("ENTER\n");
@@ -862,18 +871,14 @@
 	tp = dev->priv;
 
 	/* note: tp->chipset set in rtl8139_init_board */
-	tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER | RTL8139_CAPS;
+	tp->drv_flags = board_info[ent->driver_data].hw_flags;
 	tp->pci_dev = pdev;
-	tp->board = ent->driver_data;
 	tp->mmio_addr = ioaddr;
 	spin_lock_init (&tp->lock);
 	init_waitqueue_head (&tp->thr_wait);
 	init_MUTEX_LOCKED (&tp->thr_exited);
 
-	pdev->driver_data = dev;
-
-	tp->phys[0] = 32;
+	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, "
@@ -889,6 +894,30 @@
 	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
 		dev->name, rtl_chip_info[tp->chipset].name);
 
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	if (tp->drv_flags & HAS_MII_XCVR) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				tp->advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
+					   "advertising %4.4x.\n",
+					   dev->name, phy, mii_status, tp->advertising);
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
+				   "transceiver.\n",
+				   dev->name);
+			tp->phys[0] = 32;
+		}
+	} else
+		tp->phys[0] = 32;
+
 	/* Put the chip into low-power mode. */
 	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 
@@ -899,21 +928,29 @@
 	RTL_W8_F (HltClk, 'H');	/* 'R' would leave the clock running. */
 
 	/* The lower four bits are the media type. */
-	option = (board_idx >= ARRAY_SIZE(media)) ? 0 : media[board_idx];
+	option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
 	if (option > 0) {
-		tp->full_duplex = (option & 0x200) ? 1 : 0;
-		tp->default_port = option & 15;
+		tp->full_duplex = (option & 0x210) ? 1 : 0;
+		tp->default_port = option & 0xFF;
 		if (tp->default_port)
 			tp->medialock = 1;
 	}
-
+	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
+		tp->full_duplex = full_duplex[board_idx];
 	if (tp->full_duplex) {
-		printk (KERN_INFO
-			"%s: Media type forced to Full Duplex.\n",
-			dev->name);
-		mdio_write (dev, tp->phys[0], 4, 0x141);
+		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+		/* Changing the MII-advertised media because might prevent
+		   re-connection. */
 		tp->duplex_lock = 1;
 	}
+	if (tp->default_port) {
+		printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
+			   (option & 0x20 ? 100 : 10),
+			   (option & 0x10 ? "full" : "half"));
+		mdio_write(dev, tp->phys[0], 0,
+				   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+				   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+	}
 
 	DPRINTK ("EXIT - returning 0\n");
 	return 0;
@@ -922,7 +959,7 @@
 
 static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata (pdev);
 	struct rtl8139_private *np;
 
 	DPRINTK ("ENTER\n");
@@ -938,10 +975,7 @@
 	iounmap (np->mmio_addr);
 #endif /* !USE_IO_OPS */
 
-	release_region (pci_resource_start (pdev, 0),
-			pci_resource_len (pdev, 0));
-	release_mem_region (pci_resource_start (pdev, 1),
-			    pci_resource_len (pdev, 1));
+	pci_release_regions (pdev);
 
 #ifndef RTL8139_NDEBUG
 	/* poison memory before freeing */
@@ -952,7 +986,7 @@
 
 	kfree (dev);
 
-	pdev->driver_data = NULL;
+	pci_set_drvdata (pdev, NULL);
 
 	DPRINTK ("EXIT\n");
 }
@@ -1035,7 +1069,7 @@
 #define MDIO_WRITE0 (MDIO_DIR)
 #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
 
-#define mdio_delay()	readb(mdio_addr)
+#define mdio_delay(mdio_addr)	readb(mdio_addr)
 
 
 static char mii_2_8139_map[8] = {
@@ -1059,9 +1093,9 @@
 
 	for (i = 32; i >= 0; i--) {
 		writeb (MDIO_WRITE1, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -1089,20 +1123,18 @@
 		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
 
 		writeb (MDIO_DIR | dataval, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	/* Read the two transition, 16 data, and wire-idle bits. */
 	for (i = 19; i > 0; i--) {
 		writeb (0, mdio_addr);
-		mdio_delay ();
-		retval =
-		    (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1
-				     : 0);
+		mdio_delay (mdio_addr);
+		retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
 		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff);
@@ -1115,19 +1147,19 @@
 {
 	struct rtl8139_private *tp = dev->priv;
 	void *mdio_addr = tp->mmio_addr + Config4;
-	int mii_cmd =
-	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
 	int i;
 
 	DPRINTK ("ENTER\n");
 
 	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		if (location < 8 && mii_2_8139_map[location]) {
-			writew (value,
-				tp->mmio_addr + mii_2_8139_map[location]);
-			readw (tp->mmio_addr + mii_2_8139_map[location]);
-		}
-		DPRINTK ("EXIT after directly using 8139 internal regs\n");
+		void *ioaddr = tp->mmio_addr;
+		if (location == 0) {
+			RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+			RTL_W16_F (BasicModeCtrl, value);
+			RTL_W8_F (Cfg9346, Cfg9346_Lock);
+		} else if (location < 8 && mii_2_8139_map[location])
+			RTL_W16_F (mii_2_8139_map[location], value);
 		return;
 	}
 	mdio_sync (mdio_addr);
@@ -1137,20 +1169,18 @@
 		int dataval =
 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
 		writeb (dataval, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (dataval | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
-
 	/* Clear out extra bits. */
 	for (i = 2; i > 0; i--) {
 		writeb (0, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
-
-	DPRINTK ("EXIT\n");
+	return;
 }
 
 
@@ -1231,6 +1261,8 @@
 		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
 			break;
 
+	/* unlock Config[01234] and BMCR register writes */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 	/* Restore our idea of the MAC address. */
 	RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
 	RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
@@ -1246,12 +1278,23 @@
 	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
 
-	/* unlock Config[01234] and BMCR register writes */
-	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
-	udelay (10);
-
 	tp->cur_rx = 0;
 
+	/* This is check_duplex() */
+	if (tp->phys[0] >= 0  ||  (tp->drv_flags & HAS_MII_XCVR)) {
+		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+		if (mii_reg5 == 0xffff)
+			;					/* Not there */
+		else if ((mii_reg5 & 0x0100) == 0x0100
+				 || (mii_reg5 & 0x00C0) == 0x0040)
+			tp->full_duplex = 1;
+		printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+			   " auto-negotiated partner ability %4.4x.\n", dev->name,
+			   mii_reg5 == 0 ? "" :
+			   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
+			   tp->full_duplex ? "full" : "half", mii_reg5);
+	}
+
 	if (tp->chipset >= CH_8139A) {
 		tmp = RTL_R8 (Config1) & Config1Clear;
 		tmp |= Cfg1_Driver_Load;
@@ -1544,7 +1587,7 @@
 	RTL_W16 (IntrMask, 0x0000);
 
 	/* Emit info to figure out what went wrong. */
-	printk (KERN_DEBUG "%s: Tx queue start entry %d  dirty entry %d.\n",
+	printk (KERN_DEBUG "%s: Tx queue start entry %ld  dirty entry %ld.\n",
 		dev->name, tp->cur_tx, tp->dirty_tx);
 	for (i = 0; i < NUM_TX_DESC; i++)
 		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8lx.%s\n",
@@ -1559,6 +1602,8 @@
 
 	/* ...and finally, reset everything */
 	rtl8139_hw_start (dev);
+
+	netif_wake_queue (dev);
 }
 
 
@@ -1593,11 +1638,15 @@
 		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	dev->trans_start = jiffies;
+
+	spin_lock_irq (&tp->lock);
+
 	tp->cur_tx++;
-	mb();
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
 
+	spin_unlock_irq (&tp->lock);
+
 	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
 		 dev->name, skb->data, skb->len, entry);
 
@@ -1609,7 +1658,7 @@
 				  struct rtl8139_private *tp,
 				  void *ioaddr)
 {
-	unsigned int dirty_tx, tx_left;
+	unsigned long dirty_tx, tx_left;
 
 	assert (dev != NULL);
 	assert (tp != NULL);
@@ -1673,9 +1722,8 @@
 
 #ifndef RTL8139_NDEBUG
 	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-		printk (KERN_ERR
-		  "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
-		     dev->name, dirty_tx, tp->cur_tx);
+		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+		        dev->name, dirty_tx, tp->cur_tx);
 		dirty_tx += NUM_TX_DESC;
 	}
 #endif /* RTL8139_NDEBUG */
@@ -1683,7 +1731,6 @@
 	/* only wake the queue if we did work, and the queue is stopped */
 	if (tp->dirty_tx != dirty_tx) {
 		tp->dirty_tx = dirty_tx;
-		mb();
 		if (netif_queue_stopped (dev))
 			netif_wake_queue (dev);
 	}
@@ -1856,8 +1903,8 @@
 				     void *ioaddr,
 				     int status, int link_changed)
 {
-	printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n",
-		dev->name, status);
+	DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
+		 dev->name, status);
 
 	assert (dev != NULL);
 	assert (tp != NULL);
@@ -1917,8 +1964,6 @@
 	void *ioaddr = tp->mmio_addr;
 	int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
 
-	spin_lock (&tp->lock);
-
 	do {
 		status = RTL_R16 (IntrStatus);
 
@@ -1949,7 +1994,7 @@
 		   RxFIFOOver error (I got the feeling this depends on the
 		   CPU speed, lower CPU speed --> more errors).
 		   After clearing the RxOverflow bit the transfer of the
-		   packet was repeated and all data are error free transfered */
+		   packet was repeated and all data are error free transferred */
 		RTL_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
 
 		DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
@@ -1970,8 +2015,11 @@
 		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
 			rtl8139_rx_interrupt (dev, tp, ioaddr);
 
-		if (status & (TxOK | TxErr))
+		if (status & (TxOK | TxErr)) {
+			spin_lock (&tp->lock);
 			rtl8139_tx_interrupt (dev, tp, ioaddr);
+			spin_unlock (&tp->lock);
+		}
 
 		boguscnt--;
 	} while (boguscnt > 0);
@@ -1986,8 +2034,6 @@
 		RTL_W16 (IntrStatus, 0xffff);
 	}
 
-	spin_unlock (&tp->lock);
-
 	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
 }
@@ -2074,7 +2120,19 @@
 			break;
 		}
 
-		mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
+		if (data[0] == tp->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				/* Check for autonegotiation on or reset. */
+				tp->medialock = (value & 0x9000) ? 0 : 1;
+				if (tp->medialock)
+					tp->full_duplex = (value & 0x0100) ? 1 : 0;
+				break;
+			case 4: tp->advertising = value; break;
+			}
+		}
+		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
 		break;
 
 	default:
@@ -2095,8 +2153,10 @@
 	DPRINTK ("ENTER\n");
 
 	if (netif_running(dev)) {
+		spin_lock_irq (&tp->lock);
 		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 		RTL_W32 (RxMissed, 0);
+		spin_unlock_irq (&tp->lock);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -2117,12 +2177,11 @@
 		unsigned char current_octet = *data++;
 		int bit;
 		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ?
+			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
 			     ethernet_polynomial : 0);
 	}
 
-	DPRINTK ("EXIT\n");
+	DPRINTK ("EXIT, returning %u\n", crc);
 	return crc;
 }
 
@@ -2131,6 +2190,7 @@
 {
 	struct rtl8139_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;
@@ -2164,9 +2224,7 @@
 				 mc_filter);
 	}
 
-	/* if called from irq handler, lock already acquired */
-	if (!in_irq ())
-		spin_lock_irq (&tp->lock);
+	spin_lock_irqsave (&tp->lock, flags);
 
 	/* We can safely update without stopping the chip. */
 	tmp = rtl8139_rx_config | rx_mode |
@@ -2175,8 +2233,7 @@
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
 	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
-	if (!in_irq ())
-		spin_unlock_irq (&tp->lock);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
 	DPRINTK ("EXIT\n");
 }
@@ -2184,7 +2241,7 @@
 
 static void rtl8139_suspend (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata (pdev);
 	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
@@ -2207,7 +2264,7 @@
 
 static void rtl8139_resume (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata (pdev);
 
 	netif_device_attach (dev);
 	rtl8139_hw_start (dev);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/82596.c linux/drivers/net/82596.c
--- v2.4.2/linux/drivers/net/82596.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/82596.c	Tue Mar  6 19:28:33 2001
@@ -40,8 +40,6 @@
 
  */
 
-static const char *version = "82596.c $Revision: 1.4 $\n";
-
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -65,6 +63,9 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 
+static char version[] __initdata =
+	"82596.c $Revision: 1.4 $\n";
+
 /* DEBUG flags
  */
 
@@ -333,7 +334,7 @@
 	spinlock_t lock;
 };
 
-char init_setup[] =
+static char init_setup[] =
 {
 	0x8E,			/* length, prefetch on */
 	0xC8,			/* fifo to 8, monitor off */
@@ -1132,9 +1133,9 @@
 		/* this is easy the ethernet interface can only be at 0x300 */
 		/* first check nothing is already registered here */
 
-		if (check_region(ioaddr, I596_TOTAL_SIZE)) {
+		if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) {
 			printk("82596: IO address 0x%04x in use\n", ioaddr);
-			return -ENODEV;
+			return -EBUSY;
 		}
 
 		for (i = 0; i < 8; i++) {
@@ -1144,19 +1145,15 @@
 
 		/* checksum is a multiple of 0x100, got this wrong first time
 		   some machines have 0x100, some 0x200. The DOS driver doesn't
-		   even bother with the checksum */
-
-		if (checksum % 0x100)
-			return -ENODEV;
-
-		/* Some other boards trip the checksum.. but then appear as
-		 * ether address 0. Trap these - AC */
-
-		if (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)
-			return -ENODEV;
-
-		if (!request_region(ioaddr, I596_TOTAL_SIZE, "i596"))
+		   even bother with the checksum.
+		   Some other boards trip the checksum.. but then appear as
+		   ether address 0. Trap these - AC */
+
+		if ((checksum % 0x100) || 
+		    (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
+			release_region(ioaddr, I596_TOTAL_SIZE);
 			return -ENODEV;
+		}
 
 		dev->base_addr = ioaddr;
 		dev->irq = 10;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.4.2/linux/drivers/net/Config.in	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/Config.in	Tue Mar  6 19:28:33 2001
@@ -114,9 +114,11 @@
       tristate '    ICL EtherTeam 16i/32 support' CONFIG_ETH16I
       tristate '    NE2000/NE1000 support' CONFIG_NE2000
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-	 tristate '    SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
+	 dep_tristate '    SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005 $CONFIG_EXPERIMENTAL
+      fi
+      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+         tristate '    SK_G16 support' CONFIG_SK_G16
       fi
-      tristate '    SK_G16 support' CONFIG_SK_G16
    fi
    if [ "$CONFIG_MCA" = "y" ]; then
       tristate '  SKnet MCA support' CONFIG_SKMC
@@ -142,12 +144,11 @@
       dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
       dep_mbool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
-      dep_tristate '    National Semiconductor DP83810 series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
+      dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
       dep_tristate '    PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
       dep_tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
-      dep_tristate '    RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI $CONFIG_EXPERIMENTAL
       dep_tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
       dep_tristate '    SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
       dep_tristate '    Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
@@ -192,14 +193,16 @@
 
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
-   dep_tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_PCI
+   if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+      tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+   fi
    tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    if [ "$CONFIG_INET" = "y" ]; then
       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
-      if [ "$CONFIG_HIPPI" = "y" ]; then
+      if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then
          tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
          if [ "$CONFIG_ROADRUNNER" != "n" ]; then
    	    bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
@@ -260,7 +263,7 @@
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI
+   dep_tristate 'Red Creek Hardware VPN (EXPERIMENTAL)' CONFIG_RCPCI $CONFIG_PCI
    tristate 'Traffic Shaper (EXPERIMENTAL)' CONFIG_SHAPER
 fi
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.4.2/linux/drivers/net/Makefile	Sat Feb  3 19:51:28 2001
+++ linux/drivers/net/Makefile	Fri Mar  2 11:02:14 2001
@@ -163,7 +163,6 @@
 obj-$(CONFIG_3C515) += 3c515.o
 obj-$(CONFIG_EEXPRESS) += eexpress.o
 obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
-obj-$(CONFIG_RTL8129) += rtl8129.o
 obj-$(CONFIG_8139TOO) += 8139too.o
 obj-$(CONFIG_WAVELAN) += wavelan.o
 obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
diff -u --recursive --new-file v2.4.2/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h
--- v2.4.2/linux/drivers/net/acenic_firmware.h	Sat Dec 30 11:23:13 2000
+++ linux/drivers/net/acenic_firmware.h	Tue Mar  6 19:28:33 2001
@@ -23,7 +23,7 @@
 #define tigonFwRodata 0
 #else
 /* Generated by genfw.c */
-u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
+static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x10000003, 
 0x0, 0xd, 0xd, 0x3c1d0001, 
 0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000, 
@@ -4397,7 +4397,7 @@
 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 
 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
-u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
+static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 
@@ -4571,7 +4571,7 @@
 0x0, 0x14c38, 0x14c38, 0x14b80, 
 0x14bc4, 0x14c38, 0x14c38, 0x0, 
 0x0, 0x0 };
-u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
+static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, 
@@ -4612,7 +4612,7 @@
 #define tigon2FwSbssLen 0xcc
 #define tigon2FwBssAddr 0x00016f50
 #define tigon2FwBssLen 0x20c0
-u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
+static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x0, 
 0x10000003, 0x0, 0xd, 0xd, 
 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, 
@@ -9154,7 +9154,7 @@
 0x24020001, 0x8f430328, 0x1021, 0x24630001, 
 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 
 0x0, 0x0, 0x0, 0x0 };
-u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
+static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
@@ -9425,7 +9425,7 @@
 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 
 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 
 0x0, 0x0 };
-u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
+static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
 0x1, 
 0x1, 0x1, 0xc001fc, 0x3ffc, 
 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/appletalk/cops.c linux/drivers/net/appletalk/cops.c
--- v2.4.2/linux/drivers/net/appletalk/cops.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/appletalk/cops.c	Tue Mar 20 12:05:00 2001
@@ -181,7 +181,7 @@
         int board;			/* Holds what board type is. */
 	int nodeid;			/* Set to 1 once have nodeid. */
         unsigned char node_acquire;	/* Node ID when acquired. */
-        struct at_addr node_addr;	/* Full node addres */
+        struct at_addr node_addr;	/* Full node address */
 };
 
 /* Index to functions, as function prototypes. */
@@ -752,8 +752,8 @@
 {
         int pkt_len = 0;
         int rsp_type = 0;
-        struct sk_buff *skb;
-        struct cops_local *lp = (struct cops_local *)dev->priv;
+        struct sk_buff *skb = NULL;
+        struct cops_local *lp = dev->priv;
         int ioaddr = dev->base_addr;
         int boguscount = 0;
         unsigned long flags;
@@ -771,6 +771,7 @@
                 /* Wait for DMA to turn around. */
                 while(++boguscount<1000000)
                 {
+			barrier();
                         if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_READY)
                                 break;
                 }
@@ -801,6 +802,7 @@
                 lp->stats.rx_dropped++;
                 while(pkt_len--)        /* Discard packet */
                         inb(ioaddr);
+		restore_flags(flags);
                 return;
         }
         skb->dev = dev;
@@ -820,7 +822,7 @@
 		printk(KERN_WARNING "%s: Bad packet length of %d bytes.\n", 
 			dev->name, pkt_len);
                 lp->stats.tx_errors++;
-                kfree_skb(skb);
+                dev_kfree_skb_any(skb);
                 return;
         }
 
@@ -828,7 +830,7 @@
         if(rsp_type == LAP_INIT_RSP)
         {	/* Nodeid taken from received packet. */
                 lp->node_acquire = skb->data[0];
-                kfree_skb(skb);
+                dev_kfree_skb_any(skb);
                 return;
         }
 
@@ -837,7 +839,7 @@
         {
                 printk(KERN_WARNING "%s: Bad packet type %d.\n", dev->name, rsp_type);
                 lp->stats.tx_errors++;
-                kfree_skb(skb);
+                dev_kfree_skb_any(skb);
                 return;
         }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/arcnet/Config.in linux/drivers/net/arcnet/Config.in
--- v2.4.2/linux/drivers/net/arcnet/Config.in	Thu Dec 30 11:51:26 1999
+++ linux/drivers/net/arcnet/Config.in	Tue Mar  6 19:28:35 2001
@@ -14,10 +14,8 @@
    dep_tristate 'ARCnet COM90xx (IO mapped) chipset driver' CONFIG_ARCNET_COM90xxIO $CONFIG_ARCNET
    dep_tristate 'ARCnet COM90xx (RIM I) chipset driver' CONFIG_ARCNET_RIM_I $CONFIG_ARCNET
    dep_tristate 'ARCnet COM20020 chipset driver' CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
-   if [ "$CONFIG_ARCNET_COM20020" != "n" ]; then
-      dep_tristate '  Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
-      dep_tristate '  Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_ARCNET
-   fi
+   dep_tristate '  Support for COM20020 on ISA' CONFIG_ARCNET_COM20020_ISA $CONFIG_ARCNET_COM20020 $CONFIG_ISA
+   dep_tristate '  Support for COM20020 on PCI' CONFIG_ARCNET_COM20020_PCI $CONFIG_ARCNET_COM20020 $CONFIG_PCI
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.2/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c
--- v2.4.2/linux/drivers/net/arcnet/arcnet.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/arcnet/arcnet.c	Sat Mar  3 10:55:48 2001
@@ -696,6 +696,9 @@
 		       msg, status, lp->intmask, lp->lasttrans_dest);
 		lp->last_timeout = jiffies;
 	}
+
+	if (lp->cur_tx == -1)
+		netif_wake_queue(dev);
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c
--- v2.4.2/linux/drivers/net/arcnet/com20020-pci.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/arcnet/com20020-pci.c	Tue Mar  6 19:28:35 2001
@@ -78,8 +78,10 @@
 	if (!dev)
 		return err;
 	lp = dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
-	if (!lp)
-		return -ENOMEM;
+	if (!lp) {
+		err = -ENOMEM;
+		goto out_dev;
+	}
 	memset(lp, 0, sizeof(struct arcnet_local));
 	pdev->driver_data = dev;
 
@@ -98,17 +100,30 @@
 	if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) {
 		BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n",
 		       ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out_priv;
 	}
 	if (ASTATUS() == 0xFF) {
 		BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, "
 		       "but seems empty!\n", ioaddr);
-		return -EIO;
+		err = -EIO;
+		goto out_priv;
+	}
+	if (com20020_check(dev)) {
+		err = -EIO;
+		goto out_priv;
 	}
-	if (com20020_check(dev))
-		return -EIO;
 
-	return com20020_found(dev, SA_SHIRQ);
+	if ((err = com20020_found(dev, SA_SHIRQ)) != 0)
+	        goto out_priv;
+
+	return 0;
+
+out_priv:
+	kfree(dev->priv);
+out_dev:
+	kfree(dev);
+	return err;
 }
 
 static void __devexit com20020pci_remove(struct pci_dev *pdev)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/arlan-proc.c linux/drivers/net/arlan-proc.c
--- v2.4.2/linux/drivers/net/arlan-proc.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/arlan-proc.c	Tue Mar  6 19:28:33 2001
@@ -185,7 +185,7 @@
 			return "type A672T";
 	}
 }
-#ifdef ARLAN_DEBUGING
+#ifdef ARLAN_DEBUGGING
 static void arlan_print_diagnostic_info(struct net_device *dev)
 {
 	int i;
@@ -341,7 +341,7 @@
 	DEBUGSHM(4, "arlan configuredStatus = %d \n", arlan->configuredStatusFlag, u_char);
 	DEBUGSHM(4, "arlan driver diagnostic: 0x%2x\n", arlan->diagnosticInfo, u_char);
 
-	/* issue nop command - no interupt */
+	/* issue nop command - no interrupt */
 	arlan_command(dev, ARLAN_COMMAND_NOOP);
 	if (arlan_command(dev, ARLAN_COMMAND_WAIT_NOW) != 0)
 		return -1;
@@ -818,7 +818,7 @@
 #define CTBLN(num,card,nam) \
         {num , #nam, &(arlan_conf[card].nam), \
          sizeof(int), 0600, NULL, &proc_dointvec}
-#ifdef ARLAN_DEBUGING
+#ifdef ARLAN_DEBUGGING
 
 #define ARLAN_PROC_DEBUG_ENTRIES	{48, "entry_exit_debug", &arlan_entry_and_exit_debug, \
                 sizeof(int), 0600, NULL, &proc_dointvec},\
diff -u --recursive --new-file v2.4.2/linux/drivers/net/arlan.c linux/drivers/net/arlan.c
--- v2.4.2/linux/drivers/net/arlan.c	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/arlan.c	Tue Mar  6 19:28:33 2001
@@ -32,9 +32,8 @@
 static int async = 1;
 static int tx_queue_len = 1;
 static int arlan_EEPROM_bad;
-static int arlan_entry_and_exit_debug;
 
-#ifdef ARLAN_DEBUGING
+#ifdef ARLAN_DEBUGGING
 
 static int arlan_entry_debug;
 static int arlan_exit_debug;
@@ -71,6 +70,7 @@
 MODULE_PARM(arlan_EEPROM_bad, "i");
 
 EXPORT_SYMBOL(arlan_device);
+EXPORT_SYMBOL(arlan_conf);
 EXPORT_SYMBOL(last_arlan);
 
 
@@ -114,7 +114,7 @@
 	return ((long long) timev.tv_sec * 1000000 + timev.tv_usec);
 };
 
-#ifdef ARLAN_ENTRY_EXIT_DEBUGING
+#ifdef ARLAN_ENTRY_EXIT_DEBUGGING
 #define ARLAN_DEBUG_ENTRY(name) \
 	{\
 	struct timeval timev;\
@@ -694,7 +694,7 @@
 }
 
 
-#ifdef ARLAN_DEBUGING
+#ifdef ARLAN_DEBUGGING
 
 static void arlan_print_registers(struct net_device *dev, int line)
 {
@@ -1671,7 +1671,7 @@
 					}
 					/* we reach here if multicast filtering is on and packet 
 					 * is multicast and not for receive */
-					goto end_of_interupt;
+					goto end_of_interrupt;
 				}
 			}
 #endif				// ARLAN_MULTICAST
@@ -1728,7 +1728,7 @@
 		break;
 		
 		default:
-			printk(KERN_ERR "arlan intr: recieved unknown status\n");
+			printk(KERN_ERR "arlan intr: received unknown status\n");
 			priv->stats.rx_crc_errors++;
 			break;
 	}
@@ -1896,7 +1896,7 @@
 	return 0;
 }
 
-#ifdef ARLAN_DEBUGING
+#ifdef ARLAN_DEBUGGING
 static long alignLong(volatile u_char * ptr)
 {
 	long ret;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/arlan.h linux/drivers/net/arlan.h
--- v2.4.2/linux/drivers/net/arlan.h	Wed Feb 21 18:20:25 2001
+++ linux/drivers/net/arlan.h	Tue Mar  6 19:28:33 2001
@@ -29,7 +29,7 @@
 #include <linux/etherdevice.h>
 
 
-//#define ARLAN_DEBUGING 1
+//#define ARLAN_DEBUGGING 1
 
 #define ARLAN_PROC_INTERFACE
 #define MAX_ARLANS 4 /* not more than 4 ! */
@@ -50,7 +50,6 @@
 extern char *	siteName;
 extern int	arlan_entry_debug;
 extern int	arlan_exit_debug;
-extern int	arlan_entry_and_exit_debug;
 extern int	testMemory;
 extern const char* arlan_version;
 extern int     arlan_command(struct net_device * dev, int command);
@@ -76,9 +75,9 @@
 #define IFDEBUG( L ) if ( (L) & arlan_debug ) 
 #define ARLAN_FAKE_HDR_LEN 12 
 
-#ifdef ARLAN_DEBUGING
+#ifdef ARLAN_DEBUGGING
 	#define DEBUG 1
-	#define ARLAN_ENTRY_EXIT_DEBUGING 1
+	#define ARLAN_ENTRY_EXIT_DEBUGGING 1
 	#define ARLAN_DEBUG(a,b) printk(KERN_DEBUG a, b)
 #else
 	#define ARLAN_DEBUG(a,b) 
@@ -321,7 +320,7 @@
       int tx_queue_len;
 };
 
-struct arlan_conf_stru arlan_conf[MAX_ARLANS];
+extern struct arlan_conf_stru arlan_conf[MAX_ARLANS];
 
 struct TxParam
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v2.4.2/linux/drivers/net/atp.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/atp.c	Tue Mar  6 19:28:33 2001
@@ -536,7 +536,6 @@
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
 	np->stats.tx_errors++;
-	return;
 }
 
 static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/bonding.c linux/drivers/net/bonding.c
--- v2.4.2/linux/drivers/net/bonding.c	Fri Sep 22 14:21:16 2000
+++ linux/drivers/net/bonding.c	Tue Mar  6 22:44:15 2001
@@ -60,12 +60,6 @@
 
 static struct net_device *this_bond;
 
-static int bond_open(struct net_device *dev)
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
 static void release_one_slave(struct net_device *master, slave_t *slave)
 {
 	bonding_t *bond = master->priv;
@@ -81,7 +75,6 @@
 
 	dev_put(slave->dev);
 	kfree(slave);
-	MOD_DEC_USE_COUNT;
 }
 
 static int bond_close(struct net_device *master)
@@ -92,21 +85,11 @@
 	while ((slave = bond->next) != (slave_t*)bond)
 		release_one_slave(master, slave);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static void bond_set_multicast_list(struct net_device *master)
 {
-	bonding_t *bond = master->priv;
-	slave_t *slave;
-
-	for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
-		slave->dev->mc_list = master->mc_list;
-		slave->dev->mc_count = master->mc_count;
-		slave->dev->flags = master->flags;
-		slave->dev->set_multicast_list(slave->dev);
-	}
 }
 
 static int bond_enslave(struct net_device *master, struct net_device *dev)
@@ -142,7 +125,6 @@
 
 	spin_unlock_bh(&master->xmit_lock);
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -210,9 +192,7 @@
 }
 
 static struct notifier_block bond_netdev_notifier={
-	bond_event,
-	NULL,
-	0
+	notifier_call: bond_event 
 };
 
 static int __init bond_init(struct net_device *dev)
@@ -233,7 +213,6 @@
 	/* Initialize the device structure. */
 	dev->hard_start_xmit = bond_xmit;
 	dev->get_stats	= bond_get_stats;
-	dev->open = bond_open;
 	dev->stop = bond_close;
 	dev->set_multicast_list = bond_set_multicast_list;
 	dev->do_ioctl = bond_ioctl;
@@ -289,20 +268,20 @@
 	return &bond->stats;
 }
 
-static struct net_device dev_bond = {
-		"",
-		0, 0, 0, 0,
-	 	0x0, 0,
-	 	0, 0, 0, NULL, bond_init };
+static struct net_device dev_bond;
 
 static int __init bonding_init(void)
 {
 	/* Find a name for this unit */
-	int err=dev_alloc_name(&dev_bond,"bond%d");
+	int err;
+	
+	dev_bond.init = bond_init;
 
+	err = dev_alloc_name(&dev_bond,"bond%d");
 	if (err<0)
 		return err;
 
+	SET_MODULE_OWNER(&dev_bond);
 	if (register_netdev(&dev_bond) != 0)
 		return -EIO;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c
--- v2.4.2/linux/drivers/net/cs89x0.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/cs89x0.c	Tue Mar  6 19:28:34 2001
@@ -74,13 +74,14 @@
                     : Use SET_MODULE_OWNER()
                     : Tidied up strange request_irq() abuse in net_open().
 
-*/
-
-static char version[] =
-"cs89x0.c: v2.4.0-test11-pre4 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
-
-/* ======================= end of configuration ======================= */
+  Andrew Morton     : Kernel 2.4.3-pre1
+                    : Request correct number of pages for DMA (Hugh Dickens)
+                    : Select PP_ChipID _after_ unregister_netdev in cleanup_module()
+                    :  because unregister_netdev() calls get_stats.
+                    : Make `version[]' __initdata
+                    : Uninlined the read/write reg/word functions.
 
+*/
 
 /* Always include 'config.h' first in case the user wants to turn on
    or override something. */
@@ -121,6 +122,7 @@
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/init.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -137,6 +139,9 @@
 
 #include "cs89x0.h"
 
+static char version[] __initdata =
+"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+
 /* First, a few definitions that the brave might change.
    A zero-terminated list of I/O addresses to be probed. Some special flags..
       Addr & 1 = Read back the address port, look for signature and reset
@@ -260,7 +265,7 @@
 	SET_MODULE_OWNER(dev);
 
 	if (net_debug)
-		printk("cs89x0:cs89x0_probe()\n");
+		printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr);
 
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return cs89x0_probe1(dev, base_addr);
@@ -275,27 +280,27 @@
 	return -ENODEV;
 }
 
-extern int inline
+static int
 readreg(struct net_device *dev, int portno)
 {
 	outw(portno, dev->base_addr + ADD_PORT);
 	return inw(dev->base_addr + DATA_PORT);
 }
 
-extern void inline
+static void
 writereg(struct net_device *dev, int portno, int value)
 {
 	outw(portno, dev->base_addr + ADD_PORT);
 	outw(value, dev->base_addr + DATA_PORT);
 }
 
-extern int inline
+static int
 readword(struct net_device *dev, int portno)
 {
 	return inw(dev->base_addr + portno);
 }
 
-extern void inline
+static void
 writeword(struct net_device *dev, int portno, int value)
 {
 	outw(value, dev->base_addr + portno);
@@ -383,7 +388,9 @@
 	lp = (struct net_local *)dev->priv;
 
 	/* Grab the region so we can find another board if autoIRQ fails. */
-	if (!request_region(ioaddr, NETCARD_IO_EXTENT, dev->name)) {
+	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) {
+		printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n",
+				dev->name, ioaddr, NETCARD_IO_EXTENT);
 		retval = -EBUSY;
 		goto out1;
 	}
@@ -393,16 +400,23 @@
            expect to find the EISA signature word. An IO with a base of 0x3
 	   will skip the test for the ADD_PORT. */
 	if (ioaddr & 1) {
+		if (net_debug > 1)
+			printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
 	        if ((ioaddr & 2) != 2)
 	        	if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) {
+				printk(KERN_ERR "%s: bad signature 0x%x\n",
+					dev->name, inw((ioaddr & ~3)+ ADD_PORT));
 		        	retval = -ENODEV;
 				goto out2;
 			}
 		ioaddr &= ~3;
 		outw(PP_ChipID, ioaddr + ADD_PORT);
 	}
+printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
 
         if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) {
+		printk(KERN_ERR "%s: incorrect signature 0x%x\n",
+			dev->name, inw(ioaddr + DATA_PORT));
   		retval = -ENODEV;
   		goto out2;
 	}
@@ -480,6 +494,10 @@
 			lp->adapter_cnf |=  A_CNF_AUI | A_CNF_10B_T | 
 			A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
 		
+		if (net_debug > 1)
+			printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
+					dev->name, i, lp->adapter_cnf);
+
 		/* IRQ. Other chips already probe, see below. */
 		if (lp->chip_type == CS8900) 
 			lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
@@ -519,6 +537,9 @@
                         dev->dev_addr[i*2] = eeprom_buff[i];
                         dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8;
                 }
+		if (net_debug > 1)
+			printk(KERN_DEBUG "%s: new adapter_cnf: 0%x\n",
+				dev->name, lp->adapter_cnf);
         }
 
         /* allow them to force multiple transceivers.  If they force multiple, autosense */
@@ -533,6 +554,10 @@
 		else if (lp->force & FORCE_BNC)	{lp->adapter_cnf |= A_CNF_MEDIA_10B_2; }
         }
 
+	if (net_debug > 1)
+		printk(KERN_DEBUG "%s: after force 0x%x, adapter_cnf=0x%x\n",
+			dev->name, lp->force, lp->adapter_cnf);
+
         /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */
 
         /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */
@@ -615,7 +640,7 @@
 		printk("cs89x0_probe1() successful\n");
 	return 0;
 out2:
-	release_region(ioaddr, NETCARD_IO_EXTENT);
+	release_region(ioaddr & ~3, NETCARD_IO_EXTENT);
 out1:
 	kfree(dev->priv);
 	dev->priv = 0;
@@ -1075,7 +1100,7 @@
 		if (lp->isa_config & ANY_ISA_DMA) {
 			unsigned long flags;
 			lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL,
-							(lp->dmasize * 1024) / PAGE_SIZE);
+							get_order(lp->dmasize * 1024));
 
 			if (!lp->dma_buff) {
 				printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize);
@@ -1456,7 +1481,7 @@
 static void release_dma_buff(struct net_local *lp)
 {
 	if (lp->dma_buff) {
-		free_pages((unsigned long)(lp->dma_buff), (lp->dmasize * 1024) / PAGE_SIZE);
+		free_pages((unsigned long)(lp->dma_buff), get_order(lp->dmasize * 1024));
 		lp->dma_buff = 0;
 	}
 }
@@ -1690,10 +1715,10 @@
 void
 cleanup_module(void)
 {
-	outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT);
         if (dev_cs89x0.priv != NULL) {
                 /* Free up the private structure, or leak memory :-)  */
                 unregister_netdev(&dev_cs89x0);
+		outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT);
                 kfree(dev_cs89x0.priv);
                 dev_cs89x0.priv = NULL;	/* gets re-allocated by cs89x0_probe1 */
                 /* If we don't do this, we can't re-insmod it later. */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c
--- v2.4.2/linux/drivers/net/daynaport.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/daynaport.c	Sat Mar  3 10:55:47 2001
@@ -275,6 +275,9 @@
 		return -ENODEV;
 
 	dev = init_etherdev(dev, 0);
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
 
 	if (!version_printed) {
 		printk(KERN_INFO "%s", version);
@@ -445,7 +448,7 @@
 	}
 
 	/* We should hopefully not get here */
-	printk(KERN_ERR "Probe unsucessful.\n");
+	printk(KERN_ERR "Probe unsuccessful.\n");
 	return -ENODEV;
 
  membad:
@@ -630,7 +633,8 @@
 
 static int ns8390_open(struct net_device *dev)
 {
-	MOD_INC_USE_COUNT;
+	int ret;
+
 	ei_open(dev);
 
 	/* At least on my card (a Focus Enhancements PDS card) I start */
@@ -639,11 +643,10 @@
 	/*                             - funaho@jurai.org (1999-05-17) */
 
 	/* Non-slow interrupt, works around issues with the SONIC driver */
-	if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) 
-	{
+	ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev); 
+	if (ret) {
 		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
-		MOD_DEC_USE_COUNT;
-		return -EAGAIN;
+		return ret;
 	}
 	return 0;
 }
@@ -654,7 +657,6 @@
 		printk("Need to reset the NS8390 t=%lu...", jiffies);
 	ei_status.txing = 0;
 	if (ei_debug > 1) printk("reset not supported\n");
-	return;
 }
 
 static int ns8390_close_card(struct net_device *dev)
@@ -663,7 +665,6 @@
 		printk("%s: Shutting down ethercard.\n", dev->name);
 	free_irq(dev->irq, dev);
 	ei_close(dev);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.4.2/linux/drivers/net/de4x5.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/de4x5.c	Tue Mar  6 19:28:35 2001
@@ -929,8 +929,6 @@
 
 static int     autoconf_media(struct net_device *dev);
 static void    create_packet(struct net_device *dev, char *frame, int len);
-static void    de4x5_us_delay(u32 usec);
-static void    de4x5_ms_delay(u32 msec);
 static void    load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb);
 static int     dc21040_autoconf(struct net_device *dev);
 static int     dc21041_autoconf(struct net_device *dev);
@@ -1096,13 +1094,13 @@
 #define RESET_DE4X5 {\
     int i;\
     i=inl(DE4X5_BMR);\
-    de4x5_ms_delay(1);\
+    mdelay(1);\
     outl(i | BMR_SWR, DE4X5_BMR);\
-    de4x5_ms_delay(1);\
+    mdelay(1);\
     outl(i, DE4X5_BMR);\
-    de4x5_ms_delay(1);\
-    for (i=0;i<5;i++) {inl(DE4X5_BMR); de4x5_ms_delay(1);}\
-    de4x5_ms_delay(1);\
+    mdelay(1);\
+    for (i=0;i<5;i++) {inl(DE4X5_BMR); mdelay(1);}\
+    mdelay(1);\
 }
 
 #define PHY_HARD_RESET {\
@@ -1146,7 +1144,7 @@
 	pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
 				  PCI_CFDA_PSM, WAKEUP);
     }
-    de4x5_ms_delay(10);
+    mdelay(10);
 
     RESET_DE4X5;
     
@@ -1731,13 +1729,13 @@
 
 		    /* Push up the protocol stack */
 		    skb->protocol=eth_type_trans(skb,dev);
+		    de4x5_local_stats(dev, skb->data, pkt_len);
 		    netif_rx(skb);
 		    
 		    /* Update stats */
 		    dev->last_rx = jiffies;
 		    lp->stats.rx_packets++;
  		    lp->stats.rx_bytes += pkt_len;
-		    de4x5_local_stats(dev, skb->data, pkt_len);
 		}
 	    }
 	    
@@ -2303,6 +2301,9 @@
     for (walk = walk->next; walk != &dev->bus_list; walk = walk->next) {
 	struct pci_dev *this_dev = pci_dev_b(walk);
 
+	/* Skip the pci_bus list entry */
+	if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue;
+
 	pb = this_dev->bus->number;
 	vendor = this_dev->vendor;
 	device = this_dev->device << 8;
@@ -3921,7 +3922,7 @@
     outl(csr14, DE4X5_STRR);
     outl(csr13, DE4X5_SICR);
 
-    de4x5_ms_delay(10);
+    mdelay(10);
 
     return;
 }
@@ -3949,33 +3950,6 @@
 }
 
 /*
-** Known delay in microseconds
-*/
-static void
-de4x5_us_delay(u32 usec)
-{
-    udelay(usec);
-    
-    return;
-}
-
-/*
-** Known delay in milliseconds, in millisecond steps.
-*/
-static void
-de4x5_ms_delay(u32 msec)
-{
-    u_int i;
-    
-    for (i=0; i<msec; i++) {
-	de4x5_us_delay(1000);
-    }
-    
-    return;
-}
-
-
-/*
 ** Look for a particular board name in the EISA configuration space
 */
 static int
@@ -4367,7 +4341,7 @@
     for (i=0; i<6; i++, a <<= 1) {
 	srom_latch(command | ((a & 0x80) ? DT_IN : 0), addr);
     }
-    de4x5_us_delay(1);
+    udelay(1);
     
     i = (getfrom_srom(addr) >> 3) & 0x01;
     
@@ -4401,7 +4375,7 @@
    sendto_srom((command & 0x0000ff00) | DT_CS, addr);
    
    while (!((getfrom_srom(addr) >> 3) & 0x01)) {
-       de4x5_ms_delay(1);
+       mdelay(1);
    }
    
    sendto_srom(command & 0x0000ff00, addr);
@@ -5332,7 +5306,7 @@
 	switch(state) {
 	  case WAKEUP:
 	    outb(WAKEUP, PCI_CFPM);
-	    de4x5_ms_delay(10);
+	    mdelay(10);
 	    break;
 
 	  case SNOOZE:
@@ -5349,7 +5323,7 @@
 	  case WAKEUP:
 	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
 				      PCI_CFDA_PSM, WAKEUP);
-	    de4x5_ms_delay(10);
+	    mdelay(10);
 	    break;
 
 	  case SNOOZE:
diff -u --recursive --new-file v2.4.2/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.4.2/linux/drivers/net/de4x5.h	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/de4x5.h	Tue Mar  6 19:28:34 2001
@@ -287,7 +287,7 @@
 #define STS_LNF    0x00001000       /* Link Fail */
 #define STS_FD     0x00000800       /* Full-Duplex Short Frame Received */
 #define STS_TM     0x00000800       /* Timer Expired (DC21041) */
-#define STS_ETI    0x00000400       /* Early Transmit Interupt */
+#define STS_ETI    0x00000400       /* Early Transmit Interrupt */
 #define STS_AT     0x00000400       /* AUI/TP Pin */
 #define STS_RWT    0x00000200       /* Receive Watchdog Time-Out */
 #define STS_RPS    0x00000100       /* Receive Process Stopped */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v2.4.2/linux/drivers/net/de600.c	Thu Nov 16 12:51:28 2000
+++ linux/drivers/net/de600.c	Sat Mar  3 10:55:47 2001
@@ -616,11 +616,15 @@
 	for (i = size; i > 0; --i, ++buffer)
 		*buffer = de600_read_byte(READ_DATA, dev);
 
-	((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
-
 	skb->protocol=eth_type_trans(skb,dev);
 
 	netif_rx(skb);
+
+	/* update stats */
+	dev->last_rx = jiffies;
+	((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
+	((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */
+
 	/*
 	 * If any worth-while packets have been received, netif_rx()
 	 * has done a mark_bh(INET_BH) for us and will work on them
diff -u --recursive --new-file v2.4.2/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v2.4.2/linux/drivers/net/de620.c	Thu Nov 16 12:51:28 2000
+++ linux/drivers/net/de620.c	Tue Mar  6 19:28:34 2001
@@ -563,7 +563,6 @@
 		printk(KERN_WARNING "%s: No tx-buffer available!\n", dev->name);
 		restore_flags(flags);
 		return 1;
-		break;
 	}
 	de620_write_block(dev, buffer, len);
 
@@ -699,8 +698,10 @@
 			PRINTK(("Read %d bytes\n", size));
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb); /* deliver it "upstairs" */
+			dev->last_rx = jiffies;
 			/* count all receives */
 			((struct net_device_stats *)(dev->priv))->rx_packets++;
+			((struct net_device_stats *)(dev->priv))->rx_bytes += size;
 		}
 	}
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/declance.c linux/drivers/net/declance.c
--- v2.4.2/linux/drivers/net/declance.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/declance.c	Tue Mar 20 12:05:00 2001
@@ -554,6 +554,7 @@
 	ib = (struct lance_init_block *) (dev->mem_start);
 
 #ifdef TEST_HITS
+	{
 	int i;
 
 	printk("[");
@@ -566,8 +567,10 @@
 			       ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1");
 	}
 	printk("]");
+	}
 #endif
 
+
 	for (rd = &ib->brx_ring[lp->rx_new];
 	     !((bits = rd->rmd1_bits) & LE_R1_OWN);
 	     rd = &ib->brx_ring[lp->rx_new]) {
@@ -608,9 +611,11 @@
 			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte align */
 			skb_put(skb, len);	/* make room */
+
 			cp_from_buf(skb->data,
 				 (char *) lp->rx_buf_ptr_cpu[lp->rx_new],
 				    len);
+
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
@@ -656,7 +661,7 @@
 
 			if (status & LE_T3_CLOS) {
 				lp->stats.tx_carrier_errors++;
-				printk("%s: Carrier Lost", dev->name);
+				printk("%s: Carrier Lost\n", dev->name);
 				/* Stop the lance */
 				writereg(&ll->rap, LE_CSR0);
 				writereg(&ll->rdp, LE_C0_STOP);
@@ -741,7 +746,7 @@
 	if (csr0 & LE_C0_MERR) {
 		volatile unsigned long int_stat = *(unsigned long *) (system_base + IOCTL + SIR);
 
-		printk("%s: Memory error, status %04x", dev->name, csr0);
+		printk("%s: Memory error, status %04x\n", dev->name, csr0);
 
 		if (int_stat & LANCE_DMA_MEMRDERR) {
 			printk("%s: DMA error\n", dev->name);
@@ -759,6 +764,7 @@
 		init_restart_lance(lp);
 		netif_wake_queue(dev);
 	}
+
 	writereg(&ll->rdp, LE_C0_INEA);
 	writereg(&ll->rdp, LE_C0_INEA);
 }
@@ -774,11 +780,6 @@
 
 	last_dev = dev;
 
-	/* Associate IRQ with lance_interrupt */
-	if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
-		printk("Lance: Can't get irq %d\n", dev->irq);
-		return -EAGAIN;
-	}
 	/* Stop the Lance */
 	writereg(&ll->rap, LE_CSR0);
 	writereg(&ll->rdp, LE_C0_STOP);
@@ -798,6 +799,12 @@
 
 	netif_start_queue(dev);
 
+	/* Associate IRQ with lance_interrupt */
+	if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
+		printk("Lance: Can't get irq %d\n", dev->irq);
+		return -EAGAIN;
+	}
+
 	status = init_restart_lance(lp);
 
 	/*
@@ -999,7 +1006,7 @@
 	lance_set_multicast(dev);
 }
 
-static int __init dec_lance_init(struct net_device *dev, const int type)
+static int __init dec_lance_init(const int type)
 {
 	static unsigned version_printed;
 	struct net_device *dev;
@@ -1008,6 +1015,7 @@
 	int i, ret;
 	unsigned long esar_base;
 	unsigned char *esar;
+	struct net_device *dev;
 
 #ifndef CONFIG_TC
 	system_base = KN01_LANCE_BASE;
@@ -1018,12 +1026,12 @@
 	if (dec_lance_debug && version_printed++ == 0)
 		printk(version);
 
-	dev = init_etherdev(0, sizeof(struct lance_private));
+	dev = init_etherdev(NULL, sizeof(struct lance_private));
 	if (!dev)
 		return -ENOMEM;
 
 	/* init_etherdev ensures the data structures used by the LANCE are aligned. */
-	lp = (struct lance_private *) dev->priv;
+	lp = dev->priv;
 	spin_lock_init(&lp->lock);
 
 	switch (type) {
@@ -1035,10 +1043,13 @@
 		/*
 		 * FIXME: ugly hack!
 		 */
-		dev->mem_start = KSEG1ADDR(0x0020000);
+		dev->mem_start = KSEG1ADDR(0x00020000);
 		dev->mem_end = dev->mem_start + 0x00020000;
 		dev->irq = ETHER;
 		esar_base = system_base + ESAR;
+	
+		/* Workaround crash with booting KN04 2.1k from Disk */
+		memset(dev->mem_start, 0, dev->mem_end - dev->mem_start);
 
 		/*
 		 * setup the pointer arrays, this sucks [tm] :-(
@@ -1206,13 +1217,13 @@
 /* Find all the lance cards on the system and initialize them */
 static int __init dec_lance_probe(void)
 {
-	struct net_device *dev = NULL;
 	static int called = 0;
 
 #ifdef MODULE
 	root_lance_dev = NULL;
 #endif
 
+
 #ifdef CONFIG_TC
 	int slot = -1;
 
@@ -1244,7 +1255,7 @@
 	}
 #endif
 
-	return dec_lance_init(dev, type);
+	return dec_lance_init(type);
 }
 
 static void __exit dec_lance_cleanup(void)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.4.2/linux/drivers/net/defxx.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/defxx.c	Tue Mar 20 12:05:01 2001
@@ -195,6 +195,8 @@
  *		Jun 2000	jgarzik		PCI and resource alloc cleanups
  *		Jul 2000	tjeerd		Much cleanup and some bug fixes
  *		Sep 2000	tjeerd		Fix leak on unload, cosmetic code cleanup
+ *		Feb 2001			Skb allocation fixes
+ *		Feb 2001	davej		PCI enable cleanups.
  */
 
 /* Include files */
@@ -225,7 +227,7 @@
 /* Version information string - should be updated prior to each new release!!! */
 
 static char version[] __devinitdata =
-	"defxx.c:v1.05d 2000/09/05  Lawrence V. Stefani and others\n";
+	"defxx.c:v1.05e 2001/02/03  Lawrence V. Stefani and others\n";
 
 #define DYNAMIC_BUFFERS 1
 
@@ -242,7 +244,7 @@
 static void		dfx_bus_config_check(DFX_board_t *bp);
 
 static int		dfx_driver_init(struct net_device *dev);
-static int		dfx_adap_init(DFX_board_t *bp);
+static int		dfx_adap_init(DFX_board_t *bp, int get_buffers);
 
 static int		dfx_open(struct net_device *dev);
 static int		dfx_close(struct net_device *dev);
@@ -264,8 +266,9 @@
 static int		dfx_hw_adap_state_rd(DFX_board_t *bp);
 static int		dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type);
 
-static void		dfx_rcv_init(DFX_board_t *bp);
+static int		dfx_rcv_init(DFX_board_t *bp, int get_buffers);
 static void		dfx_rcv_queue_process(DFX_board_t *bp);
+static void		dfx_rcv_flush(DFX_board_t *bp);
 
 static int		dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev);
 static int		dfx_xmt_done(DFX_board_t *bp);
@@ -339,7 +342,6 @@
 	u16 port = bp->base_addr + offset;
 
 	outb(data, port);
-	return;
 	}
 
 static inline void dfx_port_read_byte(
@@ -352,7 +354,6 @@
 	u16 port = bp->base_addr + offset;
 
 	*data = inb(port);
-	return;
 	}
 
 static inline void dfx_port_write_long(
@@ -365,7 +366,6 @@
 	u16 port = bp->base_addr + offset;
 
 	outl(data, port);
-	return;
 	}
 
 static inline void dfx_port_read_long(
@@ -378,7 +378,6 @@
 	u16 port = bp->base_addr + offset;
 
 	*data = inl(port);
-	return;
 	}
 
 
@@ -395,6 +394,7 @@
  *       
  * Arguments:
  *   pdev - pointer to pci device information (NULL for EISA)
+ *   ioaddr - pointer to port (NULL for PCI)
  *
  * Functional Description:
  *
@@ -415,6 +415,7 @@
 	struct net_device *dev;
 	DFX_board_t	  *bp;			/* board pointer */
 	static int version_disp;
+	int err;
 
 	if (!version_disp)					/* display version info if adapter is found */
 	{
@@ -426,18 +427,27 @@
 	 * init_fddidev() allocates a device structure with private data, clears the device structure and private data,
 	 * and  calls fddi_setup() and register_netdev(). Not much left to do for us here.
 	 */
-	dev = init_fddidev( NULL, sizeof(*bp));
-
+	dev = init_fddidev(NULL, sizeof(*bp));
 	if (!dev) {
 		printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n");
 		return -ENOMEM;
 	}
 
-	bp = (DFX_board_t*)dev->priv;
+	/* Enable PCI device. */
+	if (pdev != NULL) {
+		err = pci_enable_device (pdev);
+		if (err) goto err_out;
+		ioaddr = pci_resource_start (pdev, 1);
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	bp = dev->priv;
 
 	if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, dev->name)) {
 		printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
 			dev->name, PFI_K_CSR_IO_LEN, ioaddr);
+		err = -EBUSY;
 		goto err_out;
 	}
 
@@ -461,14 +471,14 @@
 		/* PCI board */
 		bp->bus_type = DFX_BUS_TYPE_PCI;
 		bp->pci_dev = pdev;
-		pdev->driver_data = dev;
-		if (pci_enable_device (pdev))
-			goto err_out_region;
+		pci_set_drvdata (pdev, dev);
 		pci_set_master (pdev);
 	}
 
-	if (dfx_driver_init(dev) != DFX_K_SUCCESS)
+	if (dfx_driver_init(dev) != DFX_K_SUCCESS) {
+		err = -ENODEV;
 		goto err_out_region;
+	}
 
 	return 0;
 
@@ -477,12 +487,12 @@
 err_out:
 	unregister_netdev(dev);
 	kfree(dev);
-	return -ENODEV;
+	return err;
 }
 
 static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-	return  dfx_init_one_pci_or_eisa(pdev, pci_resource_start (pdev, 1));
+	return dfx_init_one_pci_or_eisa(pdev, 0);
 }
 
 static int __init dfx_eisa_init(void)
@@ -642,7 +652,6 @@
 
 		dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, (PFI_MODE_M_PDQ_INT_ENB | PFI_MODE_M_DMA_ENB));
 		}
-	return;
 	}
 
 
@@ -737,7 +746,6 @@
 				}
 			}
 		}
-	return;
 	}
 
 
@@ -977,6 +985,7 @@
  *       
  * Arguments:
  *   bp - pointer to board information
+ *   get_buffers - non-zero if buffers to be allocated
  *
  * Functional Description:
  *   Issues the low-level firmware/hardware calls necessary to bring
@@ -996,7 +1005,7 @@
  *   upon a successful return of this routine.
  */
 
-static int dfx_adap_init(DFX_board_t *bp)
+static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
 	{
 	DBG_printk("In dfx_adap_init...\n");
 
@@ -1131,9 +1140,23 @@
 		return(DFX_K_FAILURE);
 		}
 
+	/*
+	 * Remove any existing dynamic buffers (i.e. if the adapter is being
+	 * reinitialized)
+	 */
+
+	if (get_buffers)
+		dfx_rcv_flush(bp);
+
 	/* Initialize receive descriptor block and produce buffers */
 
-	dfx_rcv_init(bp);
+	if (dfx_rcv_init(bp, get_buffers))
+	        {
+		printk("%s: Receive buffer allocation failed\n", bp->dev->name);
+		if (get_buffers)
+			dfx_rcv_flush(bp);
+		return(DFX_K_FAILURE);
+		}
 
 	/* Issue START command and bring adapter to LINK_(UN)AVAILABLE state */
 
@@ -1141,6 +1164,8 @@
 	if (dfx_hw_dma_cmd_req(bp) != DFX_K_SUCCESS)
 		{
 		printk("%s: Start command failed\n", bp->dev->name);
+		if (get_buffers)
+			dfx_rcv_flush(bp);
 		return(DFX_K_FAILURE);
 		}
 
@@ -1183,19 +1208,17 @@
 
 static int dfx_open(struct net_device *dev)
 {
+	int ret;
 	DFX_board_t	*bp = (DFX_board_t *)dev->priv;
 
 	DBG_printk("In dfx_open...\n");
 	
-	MOD_INC_USE_COUNT;
-
 	/* Register IRQ - support shared interrupts by passing device ptr */
 
-	if (request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev))
-	{
+	ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev);
+	if (ret) {
 		printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
-		MOD_DEC_USE_COUNT;
-		return -EAGAIN;
+		return ret;
 	}
 
 	/*
@@ -1228,11 +1251,10 @@
 	/* Reset and initialize adapter */
 
 	bp->reset_type = PI_PDATA_A_RESET_M_SKIP_ST;	/* skip self-test */
-	if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+	if (dfx_adap_init(bp, 1) != DFX_K_SUCCESS)
 	{
 		printk(KERN_ERR "%s: Adapter open failed!\n", dev->name);
 		free_irq(dev->irq, dev);
-		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
 	}
 
@@ -1318,6 +1340,10 @@
 
 	memset(bp->cons_block_virt, 0, sizeof(PI_CONSUMER_BLOCK));
 
+	/* Release all dynamically allocate skb in the receive ring. */
+
+	dfx_rcv_flush(bp);
+
 	/* Clear device structure flags */
 
 	netif_stop_queue(dev);
@@ -1326,7 +1352,6 @@
 
 	free_irq(dev->irq, dev);
 	
-	MOD_DEC_USE_COUNT;
 	return(0);
 }
 
@@ -1412,7 +1437,6 @@
 			printk("%s: Halt ID: Unknown (code = %X)\n", bp->dev->name, halt_id);
 			break;
 		}
-	return;
 	}
 
 
@@ -1504,7 +1528,7 @@
 		bp->link_available = PI_K_FALSE;	/* link is no longer available */
 		bp->reset_type = 0;					/* rerun on-board diagnostics */
 		printk("%s: Resetting adapter...\n", bp->dev->name);
-		if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+		if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS)
 			{
 			printk("%s: Adapter reset failed!  Disabling adapter interrupts.\n", bp->dev->name);
 			dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
@@ -1552,7 +1576,7 @@
 			bp->link_available = PI_K_FALSE;	/* link is no longer available */
 			bp->reset_type = 0;					/* rerun on-board diagnostics */
 			printk("%s: Resetting adapter...\n", bp->dev->name);
-			if (dfx_adap_init(bp) != DFX_K_SUCCESS)
+			if (dfx_adap_init(bp, 0) != DFX_K_SUCCESS)
 				{
 				printk("%s: Adapter reset failed!  Disabling adapter interrupts.\n", bp->dev->name);
 				dfx_port_write_long(bp, PI_PDQ_K_REG_HOST_INT_ENB, PI_HOST_INT_K_DISABLE_ALL_INTS);
@@ -1565,7 +1589,6 @@
 			bp->link_available = PI_K_TRUE;		/* set link available flag */
 			}
 		}
-	return;
 	}
 
 
@@ -1640,7 +1663,6 @@
 
 	if (port_status & PI_PSTATUS_M_TYPE_0_PENDING)
 		dfx_int_type_0_process(bp);	/* process Type 0 interrupts */
-	return;
 	}
 
 
@@ -1732,7 +1754,6 @@
 		}
 
 	spin_unlock(&bp->lock);
-	return;
 	}
 
 
@@ -2039,7 +2060,6 @@
 		{
 		DBG_printk("%s: Adapter filters updated!\n", dev->name);
 		}
-	return;
 	}
 
 
@@ -2540,7 +2560,6 @@
 	/* Deassert reset */
 
 	dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0);
-	return;
 	}
 
 
@@ -2631,8 +2650,7 @@
 		return(DFX_K_HW_TIMEOUT);
 	return(DFX_K_SUCCESS);
 	}
-
-
+
 /*
  *	Align an sk_buff to a boundary power of 2
  *
@@ -2662,6 +2680,7 @@
  *       
  * Arguments:
  *   bp - pointer to board information
+ *   get_buffers - non-zero if buffers to be allocated
  *
  * Functional Description:
  *   This routine can be called during dfx_adap_init() or during an adapter
@@ -2669,7 +2688,10 @@
  *   LLC Host queue receive buffers.
  *
  * Return Codes:
- *   None
+ *   Return 0 on success or -ENOMEM if buffer allocation failed (when using
+ *   dynamic buffer allocation). If the buffer allocation failed, the
+ *   already allocated buffers will not be released and the caller should do
+ *   this.
  *
  * Assumptions:
  *   The PDQ has been reset and the adapter and driver maintained Type 2
@@ -2680,7 +2702,7 @@
  *   is notified.
  */
 
-static void dfx_rcv_init(DFX_board_t *bp)
+static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
 	{
 	int	i, j;					/* used in for loop */
 
@@ -2702,20 +2724,22 @@
 	 *		driver initialization when we allocated memory for the receive buffers.
 	 */
 
+	if (get_buffers) {
 #ifdef DYNAMIC_BUFFERS
 	for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
 		for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
 		{
-			struct sk_buff *newskb;
+			struct sk_buff *newskb = __dev_alloc_skb(NEW_SKB_SIZE, GFP_BUFFER);
+			if (!newskb)
+				return -ENOMEM;
 			bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
 				((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
-			newskb = dev_alloc_skb(NEW_SKB_SIZE);
 			/*
 			 * align to 128 bytes for compatibility with
 			 * the old EISA boards.
 			 */
 			 
-			my_skb_align(newskb,128);
+			my_skb_align(newskb, 128);
 			bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
 			/*
 			 * p_rcv_buff_va is only used inside the
@@ -2733,12 +2757,13 @@
 			bp->p_rcv_buff_va[i+j] = (char *) (bp->rcv_block_virt + (i * PI_RCV_DATA_K_SIZE_MAX));
 			}
 #endif
+	}
 
 	/* Update receive producer and Type 2 register */
 
 	bp->rcv_xmt_reg.index.rcv_prod = bp->rcv_bufs_to_post;
 	dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
-	return;
+	return 0;
 	}
 
 
@@ -2833,7 +2858,7 @@
 						bp->p_rcv_buff_va[entry] = (char *)newskb;
 						bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
 					} else
-						skb = 0;
+						skb = NULL;
 				} else
 #endif
 					skb = dev_alloc_skb(pkt_len+3);	/* alloc new buffer to pass up, add room for PRH */
@@ -2858,6 +2883,7 @@
 					skb->dev = bp->dev;		/* pass up device pointer */
 
 					skb->protocol = fddi_type_trans(skb, bp->dev);
+					bp->rcv_total_bytes += skb->len;
 					netif_rx(skb);
 
 					/* Update the rcv counters */
@@ -2865,8 +2891,6 @@
 					bp->rcv_total_frames++;
 					if (*(p_buff + RCV_BUFF_K_DA) & 0x01)
 						bp->rcv_multicast_frames++;
-				 
-					bp->rcv_total_bytes += skb->len;
 				}
 			}
 			}
@@ -2882,7 +2906,6 @@
 		bp->rcv_xmt_reg.index.rcv_prod += 1;
 		bp->rcv_xmt_reg.index.rcv_comp += 1;
 		}
-	return;
 	}
 
 
@@ -3183,6 +3206,54 @@
 
 /*
  * =================
+ * = dfx_rcv_flush =
+ * =================
+ *   
+ * Overview:
+ *   Remove all skb's in the receive ring.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   bp - pointer to board information
+ *
+ * Functional Description:
+ *   Free's all the dynamically allocated skb's that are
+ *   currently attached to the device receive ring. This
+ *   function is typically only used when the device is
+ *   initialized or reinitialized.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Side Effects:
+ *   None
+ */
+#ifdef DYNAMIC_BUFFERS
+static void dfx_rcv_flush( DFX_board_t *bp )
+	{
+	int i, j;
+
+	for (i = 0; i < (int)(bp->rcv_bufs_to_post); i++)
+		for (j = 0; (i + j) < (int)PI_RCV_DATA_K_NUM_ENTRIES; j += bp->rcv_bufs_to_post)
+		{
+			struct sk_buff *skb;
+			skb = (struct sk_buff *)bp->p_rcv_buff_va[i+j];
+			if (skb)
+				dev_kfree_skb(skb);
+			bp->p_rcv_buff_va[i+j] = NULL;
+		}
+
+	}
+#else
+static inline void dfx_rcv_flush( DFX_board_t *bp )
+{
+}
+#endif /* DYNAMIC_BUFFERS */
+
+/*
+ * =================
  * = dfx_xmt_flush =
  * =================
  *   
@@ -3257,7 +3328,6 @@
 	prod_cons = (u32)(bp->cons_block_virt->xmt_rcv_data & ~PI_CONS_M_XMT_INDEX);
 	prod_cons |= (u32)(bp->rcv_xmt_reg.index.xmt_prod << PI_CONS_V_XMT_INDEX);
 	bp->cons_block_virt->xmt_rcv_data = prod_cons;
-	return;
 	}
 
 static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
@@ -3272,9 +3342,10 @@
 
 static void __devexit dfx_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 
 	dfx_remove_one_pci_or_eisa(pdev, dev);
+	pci_set_drvdata(pdev, NULL);
 }
 
 static struct pci_device_id dfx_pci_tbl[] __devinitdata = {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.4.2/linux/drivers/net/depca.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/depca.c	Tue Mar  6 19:28:35 2001
@@ -226,12 +226,12 @@
       0.52    16-Oct-00   Fixes for 2.3 io memory accesses
                           Fix show-stopper (ints left masked) in depca_interrupt
 			   by <peterd@pnd-pc.demon.co.uk>
+      0.53    12-Jan-01	  Release resources on failure, bss tidbits
+      			   by acme@conectiva.com.br
 
     =========================================================================
 */
 
-static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com\n";
-
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -265,6 +265,9 @@
 
 #include "depca.h"
 
+static char version[] __initdata =
+	"depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
+
 #ifdef DEPCA_DEBUG
 static int depca_debug = DEPCA_DEBUG;
 #else
@@ -309,7 +312,7 @@
 #define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
 #define DEPCA_IO_PORTS {0x300, 0x200, 0}
 #define DEPCA_TOTAL_SIZE 0x10
-static short mem_chkd = 0;
+static short mem_chkd;
 
 /*
 ** Adapter ID for the MCA EtherWORKS DE210/212 adapter
@@ -480,8 +483,9 @@
 static int    num_depcas, num_eth;
 static int    mem;                       /* For loadable module assignment
                                               use insmod mem=0x????? .... */
-static char   *adapter_name = '\0';        /* If no PROM when loadable module
+static char   *adapter_name; /* = '\0';     If no PROM when loadable module
 					      use insmod adapter_name=DE??? ...
+					      bss initializes this to zero
 					   */
 /*
 ** Miscellaneous defines...
@@ -496,6 +500,8 @@
   int tmp = num_depcas, status = -ENODEV;
   u_long iobase = dev->base_addr;
 
+  SET_MODULE_OWNER(dev);
+
   if ((iobase == 0) && loading_module){
     printk("Autoprobing is not supported when loading a module based driver.\n");
     status = -EIO;
@@ -566,15 +572,14 @@
 
 	printk(", h/w address ");
 	status = get_hw_addr(dev);
-	for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
-		printk("%2.2x:", dev->dev_addr[i]);
-	}
-	printk("%2.2x", dev->dev_addr[i]);
-
 	if (status != 0) {
 		printk("      which has an Ethernet PROM CRC error.\n");
 		return -ENXIO;
 	}
+	for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
+		printk("%2.2x:", dev->dev_addr[i]);
+	}
+	printk("%2.2x", dev->dev_addr[i]);
 
 	/* Set up the maximum amount of network RAM(kB) */
 	netRAM = ((adapter != DEPCA) ? 64 : 48);
@@ -616,17 +621,19 @@
 	lp->mca_slot = mca_slot;
 	lp->lock = SPIN_LOCK_UNLOCKED;
  	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+	status = -EBUSY;
 	if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) {
 		printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n",
 		       DEPCA_TOTAL_SIZE, ioaddr);
-		return -EBUSY;
+		goto out_priv;
 	}
 
 	/* Initialisation Block */
 	lp->sh_mem = ioremap(mem_start, mem_len);
+	status = -EIO;
 	if (lp->sh_mem == NULL) {
 		printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
-		return -EIO;
+		goto out_region;
 	}
 	lp->device_ram_start = mem_start & LA_MASK;
 	
@@ -700,20 +707,21 @@
 		outw(INEA | INIT, DEPCA_DATA);
 	  
 		irqnum = autoirq_report(1);
+		status = -ENXIO;
 		if (!irqnum) {
 			printk(" and failed to detect IRQ line.\n");
-			status = -ENXIO;
+			goto out_region;
 		} else {
-			for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) {
+			for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++)
 				if (irqnum == depca_irq[i]) {
 					dev->irq = irqnum;
 					printk(" and uses IRQ%d.\n", dev->irq);
 				}
-			}
 	      
+			status = -ENXIO;
 			if (!dev->irq) {
 				printk(" but incorrect IRQ line detected.\n");
-				status = -ENXIO;
+				goto out_region;
 			}
 		}
 #endif /* MODULE */
@@ -721,33 +729,30 @@
 		printk(" and assigned IRQ%d.\n", dev->irq);
 	}
 
-	if (!status) {
-		if (depca_debug > 1) {
-			printk(version);
-		}
-
-		/* The DEPCA-specific entries in the device structure. */
-		dev->open = &depca_open;
-		dev->hard_start_xmit = &depca_start_xmit;
-		dev->stop = &depca_close;
-		dev->get_stats = &depca_get_stats;
-		dev->set_multicast_list = &set_multicast_list;
-		dev->do_ioctl = &depca_ioctl;
-		dev->tx_timeout = depca_tx_timeout;
-		dev->watchdog_timeo = TX_TIMEOUT;
-
-		dev->mem_start = 0;
-
-		/* Fill in the generic field of the device structure. */
-		ether_setup(dev);
-	} else {          /* Incorrectly initialised hardware */
-		release_region(ioaddr, DEPCA_TOTAL_SIZE);
-		if (dev->priv) {
-			kfree(dev->priv);
-			dev->priv = NULL;
-		}
+	if (depca_debug > 1) {
+		printk(version);
 	}
 
+	/* The DEPCA-specific entries in the device structure. */
+	dev->open = &depca_open;
+	dev->hard_start_xmit = &depca_start_xmit;
+	dev->stop = &depca_close;
+	dev->get_stats = &depca_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->do_ioctl = &depca_ioctl;
+	dev->tx_timeout = depca_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	dev->mem_start = 0;
+
+	/* Fill in the generic field of the device structure. */
+	ether_setup(dev);
+	return 0;
+out_region:
+	release_region(ioaddr, DEPCA_TOTAL_SIZE);
+out_priv:
+	kfree(dev->priv);
+	dev->priv = NULL;
 	return status;
 }
 
@@ -794,9 +799,6 @@
       printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR));
     }
   }
-
-  MOD_INC_USE_COUNT;
-  
   return status;
 }
 
@@ -1120,9 +1122,6 @@
   ** Free the associated irq
   */
   free_irq(dev->irq, dev);
-
-  MOD_DEC_USE_COUNT;
-
   return 0;
 }
 
@@ -1927,14 +1926,14 @@
       tmp.addr[i] = dev->dev_addr[i];
     }
     ioc->len = ETH_ALEN;
-    if (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT;
-    copy_to_user(ioc->data, tmp.addr, ioc->len);
+    if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+      return -EFAULT;
     break;
 
   case DEPCA_SET_HWADDR:             /* Set the hardware address */
     if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT;
-    copy_from_user(tmp.addr,ioc->data,ETH_ALEN);
+    if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
+      return -EFAULT;
     for (i=0; i<ETH_ALEN; i++) {
       dev->dev_addr[i] = tmp.addr[i];
     }
@@ -1982,14 +1981,14 @@
 
   case DEPCA_GET_MCA:                /* Get the multicast address table */
     ioc->len = (HASH_TABLE_LEN >> 3);
-    if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
-    copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); 
+    if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
+      return -EFAULT;
     break;
 
   case DEPCA_SET_MCA:                /* Set a multicast address */
     if (!capable(CAP_NET_ADMIN)) return -EPERM;
-    if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT;
-    copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+    if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
+      return -EFAULT;
     set_multicast_list(dev);
     break;
 
@@ -2006,11 +2005,8 @@
   case DEPCA_GET_STATS:              /* Get the driver statistics */
     cli();
     ioc->len = sizeof(lp->pktStats);
-    if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) {
-	status = -EFAULT;
-    } else {
-	copy_to_user(ioc->data, &lp->pktStats, ioc->len); 
-    }
+    if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
+      status = -EFAULT;
     sti();
     break;
 
@@ -2028,8 +2024,8 @@
     tmp.sval[i++] = inw(DEPCA_DATA);
     memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
     ioc->len = i+sizeof(struct depca_init);
-    if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT;
-    copy_to_user(ioc->data, tmp.addr, ioc->len);
+    if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+      return -EFAULT;
     break;
 
   default:
@@ -2040,13 +2036,7 @@
 }
 
 #ifdef MODULE
-static struct net_device thisDepca = {
-  "",  /* device name is inserted by /linux/drivers/net/net_init.c */
-  0, 0, 0, 0,
-  0x200, 7,    /* I/O address, IRQ */
-  0, 0, 0, NULL, depca_probe
-};
-
+static struct net_device thisDepca;
 static int irq=7;	/* EDIT THESE LINE FOR YOUR CONFIGURATION */
 static int io=0x200;    /* Or use the irq= io= options to insmod */
 MODULE_PARM(irq, "i");
@@ -2058,6 +2048,7 @@
 {
   thisDepca.irq=irq;
   thisDepca.base_addr=io;
+  thisDepca.init = depca_probe;
 
   if (register_netdev(&thisDepca) != 0)
     return -EIO;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c
--- v2.4.2/linux/drivers/net/dgrs.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/dgrs.c	Tue Mar  6 19:28:35 2001
@@ -71,49 +71,40 @@
  *	  into the kernel.
  *	- Better handling of multicast addresses.
  *
+ *	Fixes:
+ *	Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
+ *	- fix dgrs_found_device wrt checking kmalloc return and
+ *	rollbacking the partial steps of the whole process when
+ *	one of the devices can't be allocated. Fix SET_MODULE_OWNER
+ *	on the loop to use devN instead of repeated calls to dev.
+ *
+ *	davej <davej@suse.de> - 9/2/2001
+ *	- Enable PCI device before reading ioaddr/irq
+ *
  */
 
-static char *version = "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
-
-#include <linux/version.h>
 #include <linux/module.h>
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/byteorder.h>
-
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#include <linux/types.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
 
-/*
- *	API changed at linux version 2.1.0
- */
-#if LINUX_VERSION_CODE >= 0x20100
-	#include <asm/uaccess.h>
-	#define IOREMAP(ADDR, LEN)		ioremap(ADDR, LEN)
-	#define IOUNMAP(ADDR)			iounmap(ADDR)
-	#define COPY_FROM_USER(DST,SRC,LEN)	copy_from_user(DST,SRC,LEN)
-	#define COPY_TO_USER(DST,SRC,LEN)	copy_to_user(DST,SRC,LEN)
-#else
-	#include <linux/bios32.h>
-	#define IOREMAP(ADDR, LEN)		vremap(ADDR, LEN)
-	#define IOUNMAP(ADDR)			vfree(ADDR)
-	#define COPY_FROM_USER(DST,SRC,LEN)	memcpy_fromfs(DST,SRC,LEN)
-	#define COPY_TO_USER(DST,SRC,LEN)	memcpy_tofs(DST,SRC,LEN)
-#endif
+static char version[] __initdata =
+	"$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
 
 /*
  *	DGRS include files
@@ -130,13 +121,11 @@
 #include "dgrs_asstruct.h"
 #include "dgrs_bcomm.h"
 
-#if LINUX_VERSION_CODE >= 0x20400
 static struct pci_device_id dgrs_pci_tbl[] __initdata = {
 	{ SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
 	{ }			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
-#endif /* LINUX_VERSION_CODE >= 0x20400 */
 
 /*
  *	Firmware.  Compiled separately for local compilation,
@@ -178,19 +167,19 @@
  *	"Space.c" variables, now settable from module interface
  *	Use the name below, minus the "dgrs_" prefix.  See init_module().
  */
-int	dgrs_debug = 1;
-int	dgrs_dma = 1;
-int	dgrs_spantree = -1;
-int	dgrs_hashexpire = -1;
-uchar	dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
-uchar	dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
-__u32	dgrs_ipxnet = -1;
-int	dgrs_nicmode = 0;
+static int	dgrs_debug = 1;
+static int	dgrs_dma = 1;
+static int	dgrs_spantree = -1;
+static int	dgrs_hashexpire = -1;
+static uchar	dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
+static uchar	dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
+static __u32	dgrs_ipxnet = -1;
+static int	dgrs_nicmode = 0;
 
 /*
  *	Chain of device structures
  */
-static struct net_device *dgrs_root_dev = NULL;
+static struct net_device *dgrs_root_dev;
 
 /*
  *	Private per-board data structure (dev->priv)
@@ -316,7 +305,7 @@
 	/*
 	 *	Now map the DMA registers into our virtual space
 	 */
-	priv0->vplxdma = (ulong *) IOREMAP (priv0->plxdma, 256);
+	priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256);
 	if (!priv0->vplxdma)
 	{
 		printk("%s: can't *remap() the DMA regs\n", dev0->name);
@@ -843,7 +832,7 @@
 	if (cmd != DGRSIOCTL)
 		return -EINVAL;
 
-	if(COPY_FROM_USER(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
+	if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
 		return -EFAULT;
 
 	switch (ioc.cmd)
@@ -851,7 +840,7 @@
 		case DGRS_GETMEM:
 			if (ioc.len != sizeof(ulong))
 				return -EINVAL;
-			if(COPY_TO_USER(ioc.data, &devN->mem_start, ioc.len))
+			if(copy_to_user(ioc.data, &devN->mem_start, ioc.len))
 				return -EFAULT;
 			return (0);
 		case DGRS_SETFILTER:
@@ -880,7 +869,7 @@
 	
 			if (ioc.len)
 			{
-				if(COPY_FROM_USER(S2HN(privN->bcomm->bc_filter_area),
+				if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
 					ioc.data, ioc.len))
 					return -EFAULT;
 				privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
@@ -1003,7 +992,7 @@
 	/*
 	 * Map in the dual port memory
 	 */
-	priv0->vmem = IOREMAP(dev0->mem_start, 2048*1024);
+	priv0->vmem = ioremap(dev0->mem_start, 2048*1024);
 	if (!priv0->vmem)
 	{
 		printk("%s: cannot map in board memory\n", dev0->name);
@@ -1050,7 +1039,7 @@
 	memcpy(priv0->vmem, dgrs_code, dgrs_ncode);	/* Load code */
 	if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode))
 	{
-		IOUNMAP(priv0->vmem);
+		iounmap(priv0->vmem);
 		priv0->vmem = NULL;
 		printk("%s: download compare failed\n", dev0->name);
 		return -ENXIO;
@@ -1249,13 +1238,17 @@
 )
 {
 	DGRS_PRIV	*priv;
-	struct net_device *dev;
+	struct net_device *dev, *aux;
 
 	/* Allocate and fill new device structure. */
 	int dev_size = sizeof(struct net_device) + sizeof(DGRS_PRIV);
-	int i;
+	int i, ret;
 
 	dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL);
+
+	if (!dev)
+		return -ENOMEM;
+
 	memset(dev, 0, dev_size);
 	dev->priv = ((void *)dev) + sizeof(struct net_device);
 	priv = (DGRS_PRIV *)dev->priv;
@@ -1274,11 +1267,12 @@
 	dev->init = dgrs_probe1;
 	SET_MODULE_OWNER(dev);
 	ether_setup(dev);
-	priv->next_dev = dgrs_root_dev;
-	dgrs_root_dev = dev;
 	if (register_netdev(dev) != 0)
 		return -EIO;
 
+	priv->next_dev = dgrs_root_dev;
+	dgrs_root_dev = dev;
+
 	if ( !dgrs_nicmode )
 		return (0);	/* Switch mode, we are done */
 
@@ -1295,6 +1289,9 @@
 			/* Allocate new dev and priv structures */
 		devN = (struct net_device *) kmalloc(dev_size, GFP_KERNEL);
 			/* Make it an exact copy of dev[0]... */
+		ret = -ENOMEM;
+		if (!devN) 
+			goto fail;
 		memcpy(devN, dev, dev_size);
 		devN->priv = ((void *)devN) + sizeof(struct net_device);
 		privN = (DGRS_PRIV *)devN->priv;
@@ -1305,17 +1302,29 @@
 		devN->irq = 0;
 			/* ... and base MAC address off address of 1st port */
 		devN->dev_addr[5] += i;
-		privN->chan = i+1;
-		priv->devtbl[i] = devN;
 		devN->init = dgrs_initclone;
-		SET_MODULE_OWNER(dev);
+		SET_MODULE_OWNER(devN);
 		ether_setup(devN);
+		ret = -EIO;
+		if (register_netdev(devN)) {
+			kfree(devN);
+			goto fail;
+		}
+		privN->chan = i+1;
+		priv->devtbl[i] = devN;
 		privN->next_dev = dgrs_root_dev;
 		dgrs_root_dev = devN;
-		if (register_netdev(devN) != 0)
-			return -EIO;
 	}
-	return (0);
+	return 0;
+fail:	aux = priv->next_dev;
+	while (dgrs_root_dev != aux) {
+		struct net_device *d = dgrs_root_dev;
+		
+		dgrs_root_dev = ((DGRS_PRIV *)d->priv)->next_dev;
+		unregister_netdev(d);
+		kfree(d);
+	}
+	return ret;
 }
 
 /*
@@ -1341,6 +1350,17 @@
 
 		while ((pdev = pci_find_device(SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, pdev)) != NULL)
 		{
+			/*
+			 * Get and check the bus-master and latency values.
+			 * Some PCI BIOSes fail to set the master-enable bit,
+			 * and the latency timer must be set to the maximum
+			 * value to avoid data corruption that occurs when the
+			 * timer expires during a transfer.  Yes, it's a bug.
+			 */
+			if (pci_enable_device(pdev))
+				continue;
+			pci_set_master(pdev);
+
 			plxreg = pci_resource_start (pdev, 0);
 			io = pci_resource_start (pdev, 1);
 			mem = pci_resource_start (pdev, 2);
@@ -1365,17 +1385,6 @@
 			pci_read_config_dword(pdev, 0x30, &plxdma);
 			plxdma &= ~15;
 
-			/*
-			 * Get and check the bus-master and latency values.
-			 * Some PCI BIOSes fail to set the master-enable bit,
-			 * and the latency timer must be set to the maximum
-			 * value to avoid data corruption that occurs when the
-			 * timer expires during a transfer.  Yes, it's a bug.
-			 */
-			if (pci_enable_device(pdev))
-				continue;
-			pci_set_master(pdev);
-
 			dgrs_found_device(io, mem, irq, plxreg, plxdma);
 
 			cards_found++;
@@ -1470,8 +1479,8 @@
 
 	if (dgrs_debug)
 	{
-		printk("dgrs: SW=%s FW=Build %d %s\n",
-			version, dgrs_firmnum, dgrs_firmdate);
+		printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n",
+		       version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver);
 	}
 
 	/*
@@ -1497,9 +1506,9 @@
 		proc_reset(priv->devtbl[0], 1);
 
 		if (priv->vmem)
-			IOUNMAP(priv->vmem);
+			iounmap(priv->vmem);
 		if (priv->vplxdma)
-			IOUNMAP((uchar *) priv->vplxdma);
+			iounmap((uchar *) priv->vplxdma);
 
 		release_region(dgrs_root_dev->base_addr, 256);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/dgrs_firmware.c linux/drivers/net/dgrs_firmware.c
--- v2.4.2/linux/drivers/net/dgrs_firmware.c	Tue Feb 10 12:56:44 1998
+++ linux/drivers/net/dgrs_firmware.c	Tue Mar  6 19:28:34 2001
@@ -1,7 +1,7 @@
-int dgrs_firmnum = 550;
-char dgrs_firmver[] = "$Version$";
-char dgrs_firmdate[] = "11/16/96 03:45:15";
-unsigned char dgrs_code[] __initdata = {
+static int dgrs_firmnum = 550;
+static char dgrs_firmver[] = "$Version$";
+static char dgrs_firmdate[] = "11/16/96 03:45:15";
+static unsigned char dgrs_code[] __initdata = {
 	213,5,192,8,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0,
 	0,0,0,0,0,0,0,0,64,40,35,41,
@@ -9963,4 +9963,4 @@
 	109,46,99,0,114,99,0,0,48,120,0,0,
 	0,0,0,0,0,0,0,0,0,0,0,0
 	} ;
-int dgrs_ncode = 119520 ;
+static int dgrs_ncode = 119520 ;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- v2.4.2/linux/drivers/net/dmfe.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/dmfe.c	Tue Mar 20 12:05:01 2001
@@ -127,16 +127,17 @@
 #define DMFE_100MFD     5
 #define DMFE_AUTO       8
 
-#define DMFE_TIMER_WUT  jiffies+(HZ*2)/2	/* timer wakeup time : 1 second */
+#define DMFE_TIMER_WUT  (HZ)	/* timer wakeup time : 1 second */
 #define DMFE_TX_TIMEOUT ((HZ*3)/2)	/* tx packet time-out time 1.5 s" */
 
-#define DMFE_DBUG(dbug_now, msg, vaule) if (dmfe_debug || dbug_now) printk("DBUG: %s %x\n", msg, vaule)
-
-#define DELAY_5US udelay(5)	/* udelay scale 1 usec */
-
-#define DELAY_1US udelay(1)	/* udelay scale 1 usec */
-
-#define SHOW_MEDIA_TYPE(mode) printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+#define DMFE_DBUG(dbug_now, msg, value)	\
+	if (dmfe_debug || dbug_now)	\
+		printk("DBUG: %s %x\n", msg, value)
+
+#define SHOW_MEDIA_TYPE(mode) \
+ 	printk(KERN_WARNING "dmfe: Change Speed to %sMhz %s duplex\n",	\
+	       mode & 1 ? "100" : "10",					\
+	       mode & 4 ? "full":"half");
 
 
 /* CR9 definition: SROM/MII */
@@ -150,9 +151,17 @@
 #define PHY_DATA_0      0x00000
 #define MDCLKH          0x10000
 
-#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);DELAY_5US;outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);DELAY_5US;
-
-#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+#define SROM_CLK_WRITE(data, ioaddr) \
+	outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr);			\
+	udelay(5);							\
+	outl(data | CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, ioaddr);	\
+	udelay(5);							\
+	outl(data | CR9_SROM_READ | CR9_SRCS , ioaddr);			\
+	udelay(5);
+
+#define __CHK_IO_SIZE(pci_id, dev_rev) \
+	( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \
+		DM9102A_IO_SIZE : DM9102_IO_SIZE
 #define CHK_IO_SIZE(pci_dev, dev_rev) \
 	__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
 
@@ -353,9 +362,19 @@
 	int i;
 	struct net_device *dev;
 	u32 dev_rev;
+	u16 pci_command;
 
 	DMFE_DBUG(0, "dmfe_probe()", 0);
 
+	/* Enable Master/IO access, Disable memory access */
+	i = pci_enable_device(pdev);
+	if (i) return i;
+
+	pci_set_master(pdev);
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	pci_command &= ~PCI_COMMAND_MEMORY;
+	pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+
 	pci_iobase = pci_resource_start(pdev, 0);
 	pci_irqline = pdev->irq;
 
@@ -372,11 +391,6 @@
 		goto err_out;
 	}
 
-	/* Enable Master/IO access, Disable memory access */
-	if (pci_enable_device(pdev))
-		goto err_out;
-	pci_set_master(pdev);
-
 #if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */
 
 	/* Set Latency Timer 80h */
@@ -403,7 +417,7 @@
 	}
 
 	db = dev->priv;
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
 	db->chip_id = ent->driver_data;
 	db->ioaddr = pci_iobase;
@@ -440,7 +454,7 @@
 
 static void __exit dmfe_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct dmfe_board_info *db;
 
 	DMFE_DBUG(0, "dmfe_remove_one()", 0);
@@ -451,6 +465,8 @@
 	release_region(dev->base_addr, CHK_IO_SIZE(pdev, db->chip_revision));
 	kfree(dev);	/* free board information */
 
+	pci_set_drvdata(pdev, NULL);
+
 	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
 }
 
@@ -511,12 +527,12 @@
 		db->dm910x_chk_mode = 1;	/* Enter the check mode */
 	}
 
-	/* Initilize DM910X board */
+	/* Initialize DM910X board */
 	dmfe_init_dm910x(dev);
 
 	/* set and active a timer process */
 	init_timer(&db->timer);
-	db->timer.expires = DMFE_TIMER_WUT;
+	db->timer.expires = jiffies + DMFE_TIMER_WUT;
 	db->timer.data = (unsigned long) dev;
 	db->timer.function = &dmfe_timer;
 	add_timer(&db->timer);
@@ -526,9 +542,9 @@
 	return 0;
 }
 
-/* Initilize DM910X board
+/* Initialize DM910X board
    Reset DM910X board
-   Initilize TX/Rx descriptor chain structure
+   Initialize TX/Rx descriptor chain structure
    Send the set-up frame
    Enable Tx/Rx machine
  */
@@ -541,7 +557,7 @@
 
 	/* Reset DM910x board : need 32 PCI clock to complete */
 	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */
-	DELAY_5US;
+	udelay(5);
 	outl(db->cr0_data, ioaddr + DCR0);
 
 	outl(0x180, ioaddr + DCR12);	/* Let bit 7 output port */
@@ -559,7 +575,7 @@
 		db->op_mode = db->media_mode;
 	dmfe_process_mode(db);
 
-	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
+	/* Initialize Transmit/Receive decriptor and CR3/4 */
 	dmfe_descriptor_init(db, ioaddr);
 
 	/* Init CR6 to program DM910x operation */
@@ -623,10 +639,10 @@
 	if (db->tx_packet_cnt < TX_MAX_SEND_CNT) {
 		txptr->tdes0 = 0x80000000;	/* set owner bit to DM910X */
 		db->tx_packet_cnt++;	/* Ready to send count */
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling comand */
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
 	} else {
 		db->tx_queue_cnt++;	/* queue the tx packet */
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling comand */
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling command */
 	}
 
 	/* Tx resource check */
@@ -654,7 +670,7 @@
 
 	/* Reset & stop DM910X board */
 	outl(DM910X_RESET, ioaddr + DCR0);
-	DELAY_5US;
+	udelay(5);
 
 	/* deleted timer */
 	del_timer_sync(&db->timer);
@@ -673,7 +689,7 @@
 }
 
 /*
-   DM9102 insterrupt handler
+   DM9102 interrupt handler
    receive the packet to upper layer, free the transmitted packet
  */
 
@@ -935,7 +951,7 @@
 		 */
 		DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
 		dmfe_dynamic_reset(dev);
-		db->timer.expires = DMFE_TIMER_WUT;
+		db->timer.expires = jiffies + DMFE_TIMER_WUT;
 		add_timer(&db->timer);
 		return;
 	}
@@ -990,7 +1006,7 @@
 		allocated_rx_buffer(db);
 
 	/* Timer active again */
-	db->timer.expires = DMFE_TIMER_WUT;
+	db->timer.expires = jiffies + DMFE_TIMER_WUT;
 	add_timer(&db->timer);
 }
 
@@ -999,7 +1015,7 @@
    Stop DM910X board
    Free Tx/Rx allocated memory
    Reset DM910X board
-   Re-initilize DM910X board
+   Re-initialize DM910X board
  */
 static void dmfe_dynamic_reset(struct net_device *dev)
 {
@@ -1027,7 +1043,7 @@
 	db->wait_reset = 0;
 	db->rx_error_cnt = 0;
 
-	/* Re-initilize DM910X board */
+	/* Re-initialize DM910X board */
 	dmfe_init_dm910x(dev);
 
 	/* Leave dynamic reser route */
@@ -1123,7 +1139,7 @@
 }
 
 /*
-   Update CR6 vaule
+   Update CR6 value
    Firstly stop DM910X , then written value and start
  */
 static void update_cr6(u32 cr6_data, u32 ioaddr)
@@ -1132,14 +1148,14 @@
 
 	cr6_tmp = cr6_data & ~0x2002;	/* stop Tx/Rx */
 	outl(cr6_tmp, ioaddr + DCR6);
-	DELAY_5US;
+	udelay(5);
 	outl(cr6_data, ioaddr + DCR6);
 	cr6_tmp = inl(ioaddr + DCR6);
 	/* printk("CR6 update %x ", cr6_tmp); */
 }
 
 /* Send a setup frame for DM9132
-   This setup frame initilize DM910X addres filter mode
+   This setup frame initialize DM910X address filter mode
  */
 static void dm9132_id_table(struct net_device *dev, int mc_cnt)
 {
@@ -1180,7 +1196,7 @@
 }
 
 /* Send a setup frame for DM9102/DM9102A
-   This setup frame initilize DM910X addres filter mode
+   This setup frame initialize DM910X address filter mode
  */
 static void send_filter_frame(struct net_device *dev, int mc_cnt)
 {
@@ -1288,10 +1304,10 @@
 
 	for (i = 16; i > 0; i--) {
 		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
-		DELAY_5US;
+		udelay(5);
 		srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
 		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
-		DELAY_5US;
+		udelay(5);
 	}
 
 	outl(CR9_SROM_READ, cr9_ioaddr);
@@ -1305,10 +1321,10 @@
 static void dmfe_sense_speed(struct dmfe_board_info *db)
 {
 	int i;
-	u16 phy_mode;
+	u16 phy_mode = 0;
 
 	for (i = 1000; i; i--) {
-		DELAY_5US;
+		udelay(5);
 		phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
 		if ((phy_mode & 0x24) == 0x24)
 			break;
@@ -1429,11 +1445,11 @@
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 		phy_write_1bit(ioaddr, PHY_DATA_1);
 
-		/* Send Phy addres */
+		/* Send Phy address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
-		/* Send register addres */
+		/* Send register address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
@@ -1476,11 +1492,11 @@
 		phy_write_1bit(ioaddr, PHY_DATA_1);
 		phy_write_1bit(ioaddr, PHY_DATA_0);
 
-		/* Send Phy addres */
+		/* Send Phy address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
-		/* Send register addres */
+		/* Send register address */
 		for (i = 0x10; i > 0; i = i >> 1)
 			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
@@ -1503,11 +1519,11 @@
 static void phy_write_1bit(u32 ioaddr, u32 phy_data)
 {
 	outl(phy_data, ioaddr);	/* MII Clock Low */
-	DELAY_1US;
+	udelay(1);
 	outl(phy_data | MDCLKH, ioaddr);	/* MII Clock High */
-	DELAY_1US;
+	udelay(1);
 	outl(phy_data, ioaddr);	/* MII Clock Low */
-	DELAY_1US;
+	udelay(1);
 }
 
 /*
@@ -1518,10 +1534,10 @@
 	u16 phy_data;
 
 	outl(0x50000, ioaddr);
-	DELAY_1US;
+	udelay(1);
 	phy_data = (inl(ioaddr) >> 19) & 0x1;
 	outl(0x40000, ioaddr);
-	DELAY_1US;
+	udelay(1);
 
 	return phy_data;
 }
@@ -1570,7 +1586,7 @@
 
 /*	Description: 
  *	when user used insmod to add module, system invoked init_module()
- *	to initilize and register.
+ *	to initialize and register.
  */
  
 static int __init dmfe_init_module(void)
@@ -1599,12 +1615,10 @@
 	rc = pci_module_init(&dmfe_driver);
 	if (rc < 0)
 		return rc;
-	if (rc >= 0) {
-		printk (KERN_INFO "Davicom DM91xx net driver loaded, version "
-			DMFE_VERSION "\n");
-		return 0;
-	}
-	return -ENODEV;
+
+	printk (KERN_INFO "Davicom DM91xx net driver loaded, version "
+		DMFE_VERSION "\n");
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.4.2/linux/drivers/net/eepro.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/eepro.c	Tue Mar  6 19:28:35 2001
@@ -23,6 +23,7 @@
 	This is a compatibility hardware problem.
 
 	Versions:
+	0.12c	fixing some problems with old cards (aris, 01/08/2001)
 	0.12b	misc fixes (aris, 06/26/2000)
 	0.12a   port of version 0.12a of 2.2.x kernels to 2.3.x
 		(aris (aris@conectiva.com.br), 05/19/2000)
@@ -96,7 +97,7 @@
 */
 
 static const char *version =
-	"eepro.c: v0.12b 04/26/2000 aris@conectiva.com.br\n";
+	"eepro.c: v0.12c 01/08/2000 aris@conectiva.com.br\n";
 
 #include <linux/module.h>
 
@@ -501,8 +502,10 @@
 /* set diagnose flag */
 #define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
 
+#ifdef ANSWER_TX_AND_RX		/* experimental way of handling interrupts */
 /* ack for rx/tx int */
 #define eepro_ack_rxtx(ioaddr) outb (RX_INT | TX_INT, ioaddr + STATUS_REG)
+#endif
 
 /* ack for rx int */
 #define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
@@ -585,7 +588,7 @@
 	return -ENODEV;
 }
 
-void printEEPROMInfo(short ioaddr, struct net_device *dev)
+static void printEEPROMInfo(short ioaddr, struct net_device *dev)
 {
 	unsigned short Word;
 	int i,j;
@@ -776,7 +779,8 @@
 				}
 				if (dev->irq < 2) {
 					printk(" Duh! illegal interrupt vector stored in EEPROM.\n");
-						return -ENODEV;
+					kfree(dev->priv);
+					return -ENODEV;
 				} else 
 				
 				if (dev->irq==2)
@@ -950,6 +954,7 @@
 		|| (irq2dev_map[dev->irq] = dev) == 0) && 
 		(irq2dev_map[dev->irq]!=dev)) {
 		/* printk("%s: IRQ map wrong\n", dev->name); */
+	        free_irq(dev->irq, dev);
 		return -EAGAIN;
 	}
 #endif
@@ -1067,6 +1072,8 @@
 	}
 	
 	eepro_sel_reset(ioaddr);
+	SLOW_DOWN;
+	SLOW_DOWN;
 
 	lp->tx_start = lp->tx_end = XMT_LOWER_LIMIT << 8;
 	lp->tx_last = 0;
@@ -1162,9 +1169,11 @@
 	while (((status = inb(ioaddr + STATUS_REG)) & 0x06) && (boguscount--))
 	{
 		switch (status & (RX_INT | TX_INT)) {
+#ifdef ANSWER_TX_AND_RX
 			case (RX_INT | TX_INT):
 				eepro_ack_rxtx(ioaddr);
 				break;
+#endif
 			case RX_INT:
 				eepro_ack_rx(ioaddr);
 				break;
@@ -1178,6 +1187,9 @@
 
 			/* Get the received packets */
 			eepro_rx(dev);
+#ifndef ANSWER_TX_AND_RX
+			continue;
+#endif
 		}
 		if (status & TX_INT) {
 			if (net_debug > 4)
@@ -1367,7 +1379,11 @@
 		/* Re-enable RX and TX interrupts */
 		eepro_en_int(ioaddr);
 	}
-	eepro_complete_selreset(ioaddr);
+	if (lp->eepro == LAN595FX_10ISA) {
+		eepro_complete_selreset(ioaddr);
+	}
+	else
+		eepro_en_rx(ioaddr);
 }
 
 /* The horrible routine to read a word from the serial EEPROM. */
@@ -1535,7 +1551,9 @@
 			printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
 		return;
 	}
-	netif_stop_queue(dev);
+	if (lp->eepro == LAN595FX_10ISA)
+		netif_stop_queue(dev);
+
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
 }
@@ -1591,6 +1609,7 @@
 	
 			skb->protocol = eth_type_trans(skb,dev);	
 			netif_rx(skb);
+			dev->last_rx = jiffies;
 			lp->stats.rx_packets++;
 		}
 		
@@ -1654,9 +1673,13 @@
 		xmt_status = inw(ioaddr+IO_PORT);
 		
 		if ((xmt_status & TX_DONE_BIT) == 0) {
-			udelay(40);
-			boguscount--;
-			continue;
+			if (lp->eepro == LAN595FX_10ISA) {
+				udelay(40);
+				boguscount--;
+				continue;
+			}
+			else
+				break;
 		}
 
 		xmt_status = inw(ioaddr+IO_PORT); 
@@ -1723,10 +1746,12 @@
 	 * interrupt again for tx. in other words: tx timeout what will take
 	 * a lot of time to happen, so we'll do a complete selreset.
 	 */
-	if (!boguscount)
+	if (!boguscount && lp->eepro == LAN595FX_10ISA)
 		eepro_complete_selreset(ioaddr);
 }
 
+#ifdef MODULE
+
 #define MAX_EEPRO 8
 static struct net_device dev_eepro[MAX_EEPRO];
 
@@ -1737,7 +1762,7 @@
 };
 static int autodetect;
 
-static int n_eepro = 0;
+static int n_eepro;
 /* For linux 2.1.xx */
 
 MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)");
@@ -1746,8 +1771,6 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i");
-
-#ifdef MODULE
 
 int 
 init_module(void)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.4.2/linux/drivers/net/eexpress.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/eexpress.c	Tue Mar 20 12:05:01 2001
@@ -592,7 +592,7 @@
 
 	status = scb_status(dev);
 	unstick_cu(dev);
-	printk(KERN_INFO "%s: transmit timed out, %s?", dev->name,
+	printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
 	       (SCB_complete(status)?"lost interrupt":
 		"board on fire"));
 	lp->stats.tx_errors++;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.4.2/linux/drivers/net/epic100.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/epic100.c	Tue Mar 20 12:05:00 2001
@@ -1,6 +1,6 @@
 /* epic100.c: A SMC 83c170 EPIC/100 Fast Ethernet driver for Linux. */
 /*
-	Written/copyright 1997-2000 by Donald Becker.
+	Written/copyright 1997-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms of
 	the GNU General Public License (GPL), incorporated herein by reference.
@@ -37,15 +37,19 @@
 	* Fix locking (jgarzik)
 	* Limit 83c175 probe to ethernet-class PCI devices (rgooch)
 
+	LK1.1.6:
+	* Merge becker version 1.11
+	* Move pci_enable_device before any PCI BAR len checks
+
 */
 
 /* These identify the driver base version and may not be removed. */
 static const char version[] =
-"epic100.c:v1.09 5/29/2000 Written by Donald Becker <becker@scyld.com>\n";
+"epic100.c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
 static const char version2[] =
 "  http://www.scyld.com/network/epic100.html\n";
 static const char version3[] =
-" (unofficial 2.4.x kernel port, version 1.1.5, September 7, 2000)\n";
+" (unofficial 2.4.x kernel port, version 1.1.6, January 11, 2001)\n";
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -61,7 +65,7 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* Operational parameters that are set at compile time. */
 
@@ -73,6 +77,8 @@
 #define TX_RING_SIZE	16
 #define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
 #define RX_RING_SIZE	32
+#define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct epic_tx_desc)
+#define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct epic_rx_desc)
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -161,14 +167,13 @@
 enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
 
 #define EPIC_TOTAL_SIZE 0x100
+#define USE_IO_OPS 1
 #ifdef USE_IO_OPS
 #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
 #else
 #define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
 #endif
 
-#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
-
 typedef enum {
 	SMSC_83C170_0,
 	SMSC_83C170,
@@ -185,7 +190,7 @@
 
 
 /* indexed by chip_t */
-static struct epic_chip_info epic_chip_info[] __devinitdata = {
+static struct epic_chip_info pci_id_tbl[] = {
 	{ "SMSC EPIC/100 83c170",
 	 EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
 	{ "SMSC EPIC/100 83c170",
@@ -269,16 +274,18 @@
 	DescOwn=0x8000,
 };
 
-
+#define PRIV_ALIGN	15 	/* Required alignment mask */
 struct epic_private {
-	/* Tx and Rx rings first so that they remain paragraph aligned. */
-	struct epic_rx_desc rx_ring[RX_RING_SIZE];
-	struct epic_tx_desc tx_ring[TX_RING_SIZE];
+	struct epic_rx_desc *rx_ring;
+	struct epic_tx_desc *tx_ring;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 
+	dma_addr_t tx_ring_dma;
+	dma_addr_t rx_ring_dma;
+
 	/* Ring pointers. */
 	spinlock_t lock;				/* Group with Tx control cache line. */
 	unsigned int cur_tx, dirty_tx;
@@ -290,7 +297,7 @@
 	long last_rx_time;					/* Last Rx, in jiffies. */
 
 	struct pci_dev *pci_dev;			/* PCI bus location. */
-	int chip_flags;
+	int chip_id, chip_flags;
 
 	struct net_device_stats stats;
 	struct timer_list timer;			/* Media selection timer. */
@@ -301,7 +308,7 @@
 	int mii_phy_cnt;
 	unsigned int tx_full:1;				/* The Tx queue is full. */
 	unsigned int full_duplex:1;			/* Current duplex setting. */
-	unsigned int force_fd:1;			/* Full-duplex operation requested. */
+	unsigned int duplex_lock:1;			/* Duplex forced by the user. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	unsigned int media2:4;				/* Secondary monitored media port. */
 	unsigned int medialock:1;			/* Don't sense media type. */
@@ -310,8 +317,8 @@
 
 static int epic_open(struct net_device *dev);
 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 loc, int val);
 static void epic_restart(struct net_device *dev);
 static void epic_timer(unsigned long data);
 static void epic_tx_timeout(struct net_device *dev);
@@ -330,13 +337,15 @@
 				    const struct pci_device_id *ent)
 {
 	static int card_idx = -1;
-	static int printed_version = 0;
+	static int printed_version;
+	long ioaddr;
+	int chip_idx = (int) ent->driver_data;
+	int irq;
 	struct net_device *dev;
 	struct epic_private *ep;
 	int i, option = 0, duplex = 0;
-	struct epic_chip_info *ci = &epic_chip_info[ent->driver_data];
-	long ioaddr;
-	int chip_idx = (int) ent->driver_data;
+	void *ring_space;
+	dma_addr_t ring_dma;
 
 	card_idx++;
 	
@@ -344,16 +353,16 @@
 		printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
 			version, version2, version3);
 	
-	if ((pci_resource_len(pdev, 0) < ci->io_size) ||
-	    (pci_resource_len(pdev, 1) < ci->io_size)) {
+	i = pci_enable_device(pdev);
+	if (i)
+		return i;
+	irq = pdev->irq;
+
+	if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
 		printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
 		return -ENODEV;
 	}
 	
-	i = pci_enable_device(pdev);
-	if (i)
-		return i;
-		
 	pci_set_master(pdev);
 
 	dev = init_etherdev(NULL, sizeof (*ep));
@@ -361,20 +370,10 @@
 		printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
 		return -ENOMEM;
 	}
+	SET_MODULE_OWNER(dev);
 
-	/* request 100% of both regions 0 and 1, just to make
-	 * sure noone else steals our regions while we are talking
-	 * to them */
-	if (!request_region (pci_resource_start (pdev, 0),
-			     pci_resource_len (pdev, 0), dev->name)) {
-		printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx);
+	if (pci_request_regions(pdev, dev->name))
 		goto err_out_free_netdev;
-	}
-	if (!request_mem_region (pci_resource_start (pdev, 1),
-				 pci_resource_len (pdev, 1), dev->name)) {
-		printk (KERN_ERR "epic100 %d: I/O region busy\n", card_idx);
-		goto err_out_free_pio;
-	}
 
 #ifdef USE_IO_OPS
 	ioaddr = pci_resource_start (pdev, 0);
@@ -383,10 +382,25 @@
 	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
 	if (!ioaddr) {
 		printk (KERN_ERR "epic100 %d: ioremap failed\n", card_idx);
-		goto err_out_free_mmio;
+		goto err_out_free_res;
 	}
 #endif
 
+	pci_set_drvdata(pdev, dev);
+	ep = dev->priv;
+
+	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
+	if (!ring_space)
+		goto err_out_iounmap;
+	ep->tx_ring = (struct epic_tx_desc *)ring_space;
+	ep->tx_ring_dma = ring_dma;
+
+	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
+	if (!ring_space)
+		goto err_out_unmap_tx;
+	ep->rx_ring = (struct epic_rx_desc *)ring_space;
+	ep->rx_ring_dma = ring_dma;
+
 	if (dev->mem_start) {
 		option = dev->mem_start;
 		duplex = (dev->mem_start & 16) ? 1 : 0;
@@ -397,18 +411,13 @@
 			duplex = full_duplex[card_idx];
 	}
 
-	pdev->driver_data = dev;
-
 	dev->base_addr = ioaddr;
-	dev->irq = pdev->irq;
+	dev->irq = irq;
 
-	ep = dev->priv;
-	ep->pci_dev = pdev;
-	ep->chip_flags = ci->drv_flags;
 	spin_lock_init (&ep->lock);
 
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-		   dev->name, ci->name, ioaddr, dev->irq);
+		   dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
 
 	/* Bring the chip out of low-power mode. */
 	outl(0x4200, ioaddr + GENCTL);
@@ -416,12 +425,12 @@
 	outl(0x0008, ioaddr + TEST1);
 
 	/* Turn on the MII transceiver. */
-	outl(0x12, ioaddr + MIICfg);
+	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
 	if (chip_idx == 1)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 	outl(0x0200, ioaddr + GENCTL);
 
-	/* This could also be read from the EEPROM. */
+	/* Note: the '175 does not have a serial EEPROM. */
 	for (i = 0; i < 3; i++)
 		((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
 
@@ -436,27 +445,31 @@
 				   i % 16 == 15 ? "\n" : "");
 	}
 
+	ep->pci_dev = pdev;
+	ep->chip_id = chip_idx;
+	ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
+
 	/* Find the connected MII xcvrs.
 	   Doing this in open() would allow detecting external xcvrs later, but
 	   takes much time and no cards have external MII. */
 	{
 		int phy, phy_idx = 0;
 		for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 1);
+			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				ep->phys[phy_idx++] = phy;
 				printk(KERN_INFO "%s: MII transceiver #%d control "
 					   "%4.4x status %4.4x.\n",
-					   dev->name, phy, mdio_read(ioaddr, phy, 0), mii_status);
+					   dev->name, phy, mdio_read(dev, phy, 0), mii_status);
 			}
 		}
 		ep->mii_phy_cnt = phy_idx;
 		if (phy_idx != 0) {
 			phy = ep->phys[0];
-			ep->advertising = mdio_read(ioaddr, phy, 4);
-			printk( KERN_INFO "%s: Autonegotiation advertising %4.4x link "
-					"partner %4.4x.\n",
-					dev->name, ep->advertising, mdio_read(ioaddr, phy, 5));
+			ep->advertising = mdio_read(dev, phy, 4);
+			printk(KERN_INFO "%s: Autonegotiation advertising %4.4x link "
+				   "partner %4.4x.\n",
+				   dev->name, ep->advertising, mdio_read(dev, phy, 5));
 		} else if ( ! (ep->chip_flags & NO_MII)) {
 			printk(KERN_WARNING "%s: ***WARNING***: No MII transceiver found!\n",
 				   dev->name);
@@ -471,7 +484,11 @@
 	outl(0x0008, ioaddr + GENCTL);
 
 	/* The lower four bits are the media type. */
-	ep->force_fd = duplex;
+	if (duplex) {
+		ep->duplex_lock = ep->full_duplex = 1;
+		printk(KERN_INFO "%s:  Forced full duplex operation requested.\n",
+			   dev->name);
+	}
 	dev->if_port = ep->default_port = option;
 	if (ep->default_port)
 		ep->medialock = 1;
@@ -488,14 +505,14 @@
 
 	return 0;
 
+err_out_unmap_tx:
+	pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
+err_out_iounmap:
 #ifndef USE_IO_OPS
-err_out_free_mmio:
-	release_mem_region (pci_resource_start (pdev, 1),
-			    pci_resource_len (pdev, 1));
+	iounmap(ioaddr);
+err_out_free_res:
 #endif
-err_out_free_pio:
-	release_region (pci_resource_start (pdev, 0),
-			pci_resource_len (pdev, 0));
+	pci_release_regions(pdev);
 err_out_free_netdev:
 	unregister_netdev(dev);
 	kfree(dev);
@@ -514,7 +531,7 @@
 #define EE_ENB			(0x0001 | EE_CS)
 
 /* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but 66Mhz is untested.
+   This serves to flush the operation to the PCI bus.
  */
 
 #define eeprom_delay()	inl(ee_addr)
@@ -561,24 +578,34 @@
 
 #define MII_READOP		1
 #define MII_WRITEOP		2
-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 read_cmd = (phy_id << 9) | (location << 4) | MII_READOP;
 	int i;
 
-	outl((phy_id << 9) | (location << 4) | MII_READOP, ioaddr + MIICtrl);
-	/* Typical operation takes < 50 ticks. */
-	for (i = 4000; i > 0; i--)
-		if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0)
+	outl(read_cmd, ioaddr + MIICtrl);
+	/* Typical operation takes 25 loops. */
+	for (i = 400; i > 0; i--)
+		if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) {
+			/* Work around read failure bug. */
+			if (phy_id == 1 && location < 6
+				&& inw(ioaddr + MIIData) == 0xffff) {
+				outl(read_cmd, ioaddr + MIICtrl);
+				continue;
+			}
 			return inw(ioaddr + MIIData);
+		}
 	return 0xffff;
 }
 
-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 loc, int value)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	outw(value, ioaddr + MIIData);
-	outl((phy_id << 9) | (location << 4) | MII_WRITEOP, ioaddr + MIICtrl);
+	outl((phy_id << 9) | (loc << 4) | MII_WRITEOP, ioaddr + MIICtrl);
 	for (i = 10000; i > 0; i--) {
 		if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0)
 			break;
@@ -589,27 +616,21 @@
 
 static int epic_open(struct net_device *dev)
 {
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
 	int retval;
 
-	ep->full_duplex = ep->force_fd;
-
 	/* Soft reset the chip. */
 	outl(0x4001, ioaddr + GENCTL);
 
-	MOD_INC_USE_COUNT;
-
-	if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev))) {
-		MOD_DEC_USE_COUNT;
+	if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev)))
 		return retval;
-	}
 
 	epic_init_ring(dev);
 
 	outl(0x4000, ioaddr + GENCTL);
-	/* This next magic! line by Ken Yamaguchi.. ?? */
+	/* This magic is documented in SMSC app note 7.15 */
 	outl(0x0008, ioaddr + TEST1);
 
 	/* Pull the chip out of low-power mode, enable interrupts, and set for
@@ -617,7 +638,7 @@
 	   required by the details of which bits are reset and the transceiver
 	   wiring on the Ositech CardBus card.
 	*/
-	outl(0x12, ioaddr + MIICfg);
+	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
 	if (ep->chip_flags & MII_PWRDWN)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 
@@ -639,21 +660,20 @@
 
 	if (media2miictl[dev->if_port & 15]) {
 		if (ep->mii_phy_cnt)
-			mdio_write(ioaddr, ep->phys[0], 0, media2miictl[dev->if_port&15]);
+			mdio_write(dev, ep->phys[0], 0, media2miictl[dev->if_port&15]);
 		if (dev->if_port == 1) {
 			if (debug > 1)
 				printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
 					   "status %4.4x.\n",
-					   dev->name, mdio_read(ioaddr, ep->phys[0], 1));
-			outl(0x13, ioaddr + MIICfg);
+					   dev->name, mdio_read(dev, ep->phys[0], 1));
 		}
 	} else {
-		int mii_reg5 = mdio_read(ioaddr, ep->phys[0], 5);
+		int mii_reg5 = mdio_read(dev, ep->phys[0], 5);
 		if (mii_reg5 != 0xffff) {
 			if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040)
 				ep->full_duplex = 1;
 			else if (! (mii_reg5 & 0x4000))
-				mdio_write(ioaddr, ep->phys[0], 0, 0x1200);
+				mdio_write(dev, ep->phys[0], 0, 0x1200);
 			if (debug > 1)
 				printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
 					   " register read of %4.4x.\n", dev->name,
@@ -663,8 +683,8 @@
 	}
 
 	outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-	outl(virt_to_bus(ep->rx_ring), ioaddr + PRxCDAR);
-	outl(virt_to_bus(ep->tx_ring), ioaddr + PTxCDAR);
+	outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
+	outl(ep->tx_ring_dma, ioaddr + PTxCDAR);
 
 	/* Start the chip's Rx process. */
 	set_rx_mode(dev);
@@ -700,7 +720,7 @@
 static void epic_pause(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 
 	netif_stop_queue (dev);
 	
@@ -723,17 +743,19 @@
 static void epic_restart(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	int i;
 
-	printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
-		   dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
 	/* Soft reset the chip. */
-	outl(0x0001, ioaddr + GENCTL);
+	outl(0x4001, ioaddr + GENCTL);
 
+	printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
+		   dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
 	udelay(1);
-	/* Duplicate code from epic_open(). */
-	outl(0x0008, ioaddr + TEST1);
+
+	/* This magic is documented in SMSC app note 7.15 */
+	for (i = 16; i > 0; i--)
+		outl(0x0008, ioaddr + TEST1);
 
 #if defined(__powerpc__) || defined(__sparc__)		/* Big endian */
 	outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
@@ -750,9 +772,10 @@
 	ep->tx_threshold = TX_FIFO_THRESH;
 	outl(ep->tx_threshold, ioaddr + TxThresh);
 	outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-	outl(virt_to_bus(&ep->rx_ring[ep->cur_rx%RX_RING_SIZE]), ioaddr + PRxCDAR);
-	outl(virt_to_bus(&ep->tx_ring[ep->dirty_tx%TX_RING_SIZE]),
-		 ioaddr + PTxCDAR);
+	outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
+		sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
+	outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
+		 sizeof(struct epic_tx_desc), ioaddr + PTxCDAR);
 
 	/* Start the chip's Rx process. */
 	set_rx_mode(dev);
@@ -770,16 +793,34 @@
 	return;
 }
 
-static void epic_timer(unsigned long data)
+static void check_media(struct net_device *dev)
 {
-	struct net_device *dev = (struct net_device *)data;
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;
-	int mii_reg5 = ep->mii_phy_cnt ? mdio_read(ioaddr, ep->phys[0], 5) : 0;
+	int mii_reg5 = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], 5) : 0;
 	int negotiated = mii_reg5 & ep->advertising;
 	int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 
+	if (ep->duplex_lock)
+		return;
+	if (mii_reg5 == 0xffff)		/* Bogus read */
+		return;
+	if (ep->full_duplex != duplex) {
+		ep->full_duplex = duplex;
+		printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
+			   " partner capability of %4.4x.\n", dev->name,
+			   ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
+		outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
+	}
+}
+
+static void epic_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct epic_private *ep = dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 5*HZ;
+
 	if (debug > 3) {
 		printk(KERN_DEBUG "%s: Media monitor tick, Tx status %8.8x.\n",
 			   dev->name, (int)inl(ioaddr + TxSTAT));
@@ -789,15 +830,7 @@
 			   (int)inl(ioaddr + INTSTAT), (int)inl(ioaddr + RxSTAT));
 	}
 
-	if (! ep->force_fd) {
-		if (ep->full_duplex != duplex) {
-			ep->full_duplex = duplex;
-			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-				   " partner capability of %4.4x.\n", dev->name,
-				   ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5);
-			outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
-		}
-	}
+	check_media(dev);
 
 	ep->timer.expires = jiffies + next_tick;
 	add_timer(&ep->timer);
@@ -805,7 +838,7 @@
 
 static void epic_tx_timeout(struct net_device *dev)
 {
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	if (debug > 0) {
@@ -827,13 +860,14 @@
 
 	dev->trans_start = jiffies;
 	ep->stats.tx_errors++;
-	return;
+	if (!ep->tx_full)
+		netif_wake_queue(dev);
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void epic_init_ring(struct net_device *dev)
 {
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	int i;
 
 	ep->tx_full = 0;
@@ -847,11 +881,12 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		ep->rx_ring[i].rxstatus = 0;
 		ep->rx_ring[i].buflength = cpu_to_le32(ep->rx_buf_sz);
-		ep->rx_ring[i].next = virt_to_le32desc(&ep->rx_ring[i+1]);
+		ep->rx_ring[i].next = ep->rx_ring_dma + 
+				      (i+1)*sizeof(struct epic_rx_desc);
 		ep->rx_skbuff[i] = 0;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	ep->rx_ring[i-1].next = virt_to_le32desc(&ep->rx_ring[0]);
+	ep->rx_ring[i-1].next = ep->rx_ring_dma;
 
 	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
@@ -861,7 +896,8 @@
 			break;
 		skb->dev = dev;			/* Mark as being used by this device. */
 		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
-		ep->rx_ring[i].bufaddr = virt_to_le32desc(skb->tail);
+		ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, 
+			skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn);
 	}
 	ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -871,29 +907,31 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		ep->tx_skbuff[i] = 0;
 		ep->tx_ring[i].txstatus = 0x0000;
-		ep->tx_ring[i].next = virt_to_le32desc(&ep->tx_ring[i+1]);
+		ep->tx_ring[i].next = ep->tx_ring_dma + 
+			(i+1)*sizeof(struct epic_tx_desc);
 	}
-	ep->tx_ring[i-1].next = virt_to_le32desc(&ep->tx_ring[0]);
+	ep->tx_ring[i-1].next = ep->tx_ring_dma;
 	return;
 }
 
 static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	int entry, free_count;
 	u32 ctrl_word;
+	long flags;
 
 	/* Caution: the write order is important here, set the field with the
 	   "ownership" bit last. */
-	spin_lock_irq(&ep->lock);
 
 	/* Calculate the next Tx descriptor entry. */
+	spin_lock_irqsave(&ep->lock, flags);
 	free_count = ep->cur_tx - ep->dirty_tx;
 	entry = ep->cur_tx % TX_RING_SIZE;
 
 	ep->tx_skbuff[entry] = skb;
-	ep->tx_ring[entry].bufaddr = virt_to_le32desc(skb->data);
-
+	ep->tx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, skb->data, 
+		 			            skb->len, PCI_DMA_TODEVICE);
 	if (free_count < TX_QUEUE_LEN/2) {/* Typical path */
 		ctrl_word = cpu_to_le32(0x100000); /* No interrupt */
 	} else if (free_count == TX_QUEUE_LEN/2) {
@@ -914,8 +952,7 @@
 	if (ep->tx_full)
 		netif_stop_queue(dev);
 
-	spin_unlock_irq(&ep->lock);
-
+	spin_unlock_irqrestore(&ep->lock, flags);
 	/* Trigger an immediate transmit demand. */
 	outl(TxQueued, dev->base_addr + COMMAND);
 
@@ -934,12 +971,10 @@
 static void epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
 	int status, boguscnt = max_interrupt_work;
 
-	spin_lock(&ep->lock);
-
 	do {
 		status = inl(ioaddr + INTSTAT);
 		/* Acknowledge all of the current interrupt sources ASAP. */
@@ -962,9 +997,11 @@
 			/* Note: if this lock becomes a problem we can narrow the locked
 			   region at the cost of occasionally grabbing the lock more
 			   times. */
+			spin_lock(&ep->lock);
 			cur_tx = ep->cur_tx;
 			dirty_tx = ep->dirty_tx;
 			for (; cur_tx - dirty_tx > 0; dirty_tx++) {
+				struct sk_buff *skb;
 				int entry = dirty_tx % TX_RING_SIZE;
 				int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
 
@@ -975,7 +1012,7 @@
 					/* There was an major error, log it. */
 #ifndef final_version
 					if (debug > 1)
-						printk("%s: Transmit error, Tx status %8.8x.\n",
+						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
 							   dev->name, txstatus);
 #endif
 					ep->stats.tx_errors++;
@@ -996,13 +1033,16 @@
 				}
 
 				/* Free the original skb. */
-				dev_kfree_skb_irq(ep->tx_skbuff[entry]);
+				skb = ep->tx_skbuff[entry];
+				pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, 
+						 skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq(skb);
 				ep->tx_skbuff[entry] = 0;
 			}
 
 #ifndef final_version
 			if (cur_tx - dirty_tx > TX_RING_SIZE) {
-				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+				printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
 					   dev->name, dirty_tx, cur_tx, ep->tx_full);
 				dirty_tx += TX_RING_SIZE;
 			}
@@ -1010,10 +1050,12 @@
 			ep->dirty_tx = dirty_tx;
 			if (ep->tx_full
 				&& cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
-				/* The ring is no longer full, clear tbusy. */
+				/* The ring is no longer full, allow new TX entries. */
 				ep->tx_full = 0;
+				spin_unlock(&ep->lock);
 				netif_wake_queue(dev);
-			}
+			} else
+				spin_unlock(&ep->lock);
 		}
 
 		/* Check uncommon events all at once. */
@@ -1060,12 +1102,12 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",
 			   dev->name, status);
 
-	spin_unlock(&ep->lock);
+	return;
 }
 
 static int epic_rx(struct net_device *dev)
 {
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	int entry = ep->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx;
 	int work_done = 0;
@@ -1074,7 +1116,7 @@
 		printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
 			   ep->rx_ring[entry].rxstatus);
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while (!(le32_to_cpu(ep->rx_ring[entry].rxstatus) & DescOwn)) { 
+	while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) {
 		int status = le32_to_cpu(ep->rx_ring[entry].rxstatus);
 
 		if (debug > 4)
@@ -1098,6 +1140,10 @@
 			short pkt_len = (status >> 16) - 4;
 			struct sk_buff *skb;
 
+			pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
+					    ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, 
+					 ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			if (pkt_len > PKT_BUF_SZ - 4) {
 				printk(KERN_ERR "%s: Oversized Ethernet frame, status %x "
 					   "%d bytes.\n",
@@ -1141,7 +1187,8 @@
 				break;
 			skb->dev = dev;			/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
-			ep->rx_ring[entry].bufaddr = virt_to_le32desc(skb->tail);
+			ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, 
+				skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			work_done++;
 		}
 		ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);
@@ -1152,7 +1199,8 @@
 static int epic_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
+	struct sk_buff *skb;
 	int i;
 
 	netif_stop_queue(dev);
@@ -1167,31 +1215,36 @@
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = ep->rx_skbuff[i];
+		skb = ep->rx_skbuff[i];
 		ep->rx_skbuff[i] = 0;
 		ep->rx_ring[i].rxstatus = 0;		/* Not owned by Epic chip. */
 		ep->rx_ring[i].buflength = 0;
-		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
 		if (skb) {
+			pci_unmap_single(ep->pci_dev, ep->rx_ring[i].bufaddr, 
+				 	 ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(skb);
 		}
+		ep->rx_ring[i].bufaddr = 0xBADF00D0; /* An invalid address. */
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (ep->tx_skbuff[i])
-			dev_kfree_skb(ep->tx_skbuff[i]);
+		skb = ep->tx_skbuff[i];
 		ep->tx_skbuff[i] = 0;
+		if (!skb)
+			continue;
+		pci_unmap_single(ep->pci_dev, ep->tx_ring[i].bufaddr, 
+				 skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb(skb);
 	}
 
 	/* Green! Leave the chip in low-power mode. */
 	outl(0x0008, ioaddr + GENCTL);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static struct net_device_stats *epic_get_stats(struct net_device *dev)
 {
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	if (netif_running(dev)) {
@@ -1233,7 +1286,7 @@
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct epic_private *ep = (struct epic_private *)dev->priv;
+	struct epic_private *ep = dev->priv;
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
 	int i;
 
@@ -1271,25 +1324,26 @@
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct epic_private *ep = (void *)dev->priv;
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f;
+		data[0] = ep->phys[0] & 0x1f;
 		/* Fall Through */
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		if (! netif_running(dev)) {
 			outl(0x0200, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 		}
-		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+#if 0					/* Just leave on if the ioctl() is ever used. */
 		if (! netif_running(dev)) {
-#ifdef notdef					/* Leave on if the ioctl() is used. */
 			outl(0x0008, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-#endif
 		}
+#endif
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
@@ -1298,13 +1352,26 @@
 			outl(0x0200, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 		}
-		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		if (data[0] == ep->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				/* Check for autonegotiation on or reset. */
+				ep->duplex_lock = (value & 0x9000) ? 0 : 1;
+				if (ep->duplex_lock)
+					ep->full_duplex = (value & 0x0100) ? 1 : 0;
+				break;
+			case 4: ep->advertising = value; break;
+			}
+			/* Perhaps check_duplex(dev), depending on chip semantics. */
+		}
+		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+#if 0					/* Leave on if the ioctl() is used. */
 		if (! netif_running(dev)) {
-#ifdef notdef					/* Leave on if the ioctl() is used. */
 			outl(0x0008, ioaddr + GENCTL);
 			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-#endif
 		}
+#endif
 		return 0;
 	default:
 		return -EOPNOTSUPP;
@@ -1314,36 +1381,44 @@
 
 static void __devexit epic_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct epic_private *ep = dev->priv;
 	
+	pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
+	pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
 	unregister_netdev(dev);
 #ifndef USE_IO_OPS
-	iounmap ((void*) dev->base_addr);
+	iounmap((void*) dev->base_addr);
 #endif
-	release_mem_region (pci_resource_start (pdev, 1),
-			    pci_resource_len (pdev, 1));
-	release_region (pci_resource_start (pdev, 0),
-			pci_resource_len (pdev, 0));
+	pci_release_regions(pdev);
 	kfree(dev);
+	pci_set_drvdata(pdev, NULL);
+	/* pci_power_off(pdev, -1); */
 }
 
 
 static void epic_suspend (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	long ioaddr = dev->base_addr;
 
+	if (!netif_running(dev))
+		return;
 	epic_pause(dev);
 	/* Put the chip into low-power mode. */
 	outl(0x0008, ioaddr + GENCTL);
+	/* pci_power_off(pdev, -1); */
 }
 
 
 static void epic_resume (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 
-	epic_restart (dev);
+	if (!netif_running(dev))
+		return;
+	epic_restart(dev);
+	/* pci_power_on(pdev); */
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.4.2/linux/drivers/net/eql.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/eql.c	Tue Mar 20 12:05:01 2001
@@ -197,7 +197,7 @@
 
 static int __init eql_init(struct net_device *dev)
 {
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	/* static unsigned num_masters     = 0; */
 	equalizer_t *eql = 0;
 
@@ -721,6 +721,9 @@
 
 static int eql_insert_slave(slave_queue_t *queue, slave_t *slave)
 {
+	unsigned long flags;
+
+	save_flags(flags);
 	cli ();
 
 	if ( ! eql_is_full (queue) )
@@ -736,10 +739,10 @@
 		slave->next = queue->head->next;
 		queue->head->next = slave;
 		queue->num_slaves++;
-		sti ();
+		restore_flags(flags);
 		return 0;
 	}
-	sti ();
+	restore_flags(flags);
 	return 1;
 }
 
@@ -748,7 +751,9 @@
 {
 	slave_t *prev;
 	slave_t *curr;
+	unsigned long flags;
 
+	save_flags(flags);
 	cli ();
 
 	prev = queue->head;
@@ -766,10 +771,10 @@
 		prev->next = curr->next;
 		queue->num_slaves--;
 		curr->dev->flags = curr->dev->flags & ~IFF_SLAVE;
-		sti();
+		restore_flags(flags);
 		return curr;
 	}
-	sti ();
+	restore_flags(flags);
 	return 0;			/* not found */
 }
 
@@ -784,6 +789,9 @@
 
 	if (target != 0)
 	{
+		unsigned long flags;
+
+		save_flags(flags);
 		cli ();
 		prev = queue->head;
 		curr = prev->next;
@@ -794,7 +802,7 @@
 		}
 		prev->next = curr->next;
 		queue->num_slaves--;
-		sti ();
+		restore_flags(flags);
 		eql_delete_slave (curr);
 		return 0;
 	}
@@ -847,8 +855,10 @@
 		 */
 		unsigned long best_load = (unsigned long) ULONG_MAX;
 		slave_t *slave = 0;
+		unsigned long flags;
 		int i;
 
+		save_flags(flags);
 		cli ();
 		for (i = 1, slave = eql_first_slave (queue);
 			i <= eql_number_slaves (queue);
@@ -895,7 +905,7 @@
 				}
 			}
 		} /* for */
-		sti ();
+		restore_flags(flags);
 		eql_set_best_slave (queue, best_slave);
 	} /* else */
 	if (slave_corpse != 0)
@@ -948,9 +958,11 @@
 	slave_t *slave;
 	slave_t *slave_corpse = 0;
 	int i;
+	unsigned long flags;
 	
 	if ( ! eql_is_empty (eql->queue) )
 	{
+		save_flags(flags);
 		cli ();
 		for (i = 1, slave = eql_first_slave (eql->queue);
 			i <= eql_number_slaves (eql->queue);
@@ -968,7 +980,7 @@
 					slave_corpse = slave;
 			}
 		}
-		sti ();
+		restore_flags(flags);
 		if (slave_corpse != 0)
 		{
 			printk ("eql: timer found dead slave, burying...\n");
diff -u --recursive --new-file v2.4.2/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c
--- v2.4.2/linux/drivers/net/eth16i.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/eth16i.c	Sat Mar  3 10:55:48 2001
@@ -1195,10 +1195,6 @@
 			}
 
 			skb->protocol=eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
 
 			if( eth16i_debug > 5 ) {
 				int i;
@@ -1208,6 +1204,10 @@
 					printk(KERN_DEBUG " %02x", skb->data[i]);
 				printk(KERN_DEBUG ".\n");
 			}
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
 
 		} /* else */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v2.4.2/linux/drivers/net/ewrk3.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/ewrk3.c	Sat Mar  3 10:55:48 2001
@@ -997,19 +997,6 @@
 							isa_memcpy_fromio(p, buf, pkt_len);
 						}
 
-						/*
-						   ** Notify the upper protocol layers that there is another
-						   ** packet to handle
-						 */
-						skb->protocol = eth_type_trans(skb, dev);
-						netif_rx(skb);
-
-						/*
-						   ** Update stats
-						 */
-						dev->last_rx = jiffies;
-						lp->stats.rx_packets++;
-						lp->stats.rx_bytes += pkt_len;
 						for (i = 1; i < EWRK3_PKT_STAT_SZ - 1; i++) {
 							if (pkt_len < i * EWRK3_PKT_BIN_SZ) {
 								lp->pktStats.bins[i]++;
@@ -1031,6 +1018,19 @@
 						if (lp->pktStats.bins[0] == 0) {	/* Reset counters */
 							memset(&lp->pktStats, 0, sizeof(lp->pktStats));
 						}
+						/*
+						   ** Notify the upper protocol layers that there is another
+						   ** packet to handle
+						 */
+						skb->protocol = eth_type_trans(skb, dev);
+						netif_rx(skb);
+
+						/*
+						   ** Update stats
+						 */
+						dev->last_rx = jiffies;
+						lp->stats.rx_packets++;
+						lp->stats.rx_bytes += pkt_len;
 					} else {
 						printk("%s: Insufficient memory; nuking packet.\n", dev->name);
 						lp->stats.rx_dropped++;		/* Really, deferred. */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- v2.4.2/linux/drivers/net/fc/iph5526.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/fc/iph5526.c	Tue Mar 20 12:05:00 2001
@@ -1074,11 +1074,11 @@
 			fi->fc_stats.rx_dropped++;
 			fi->g.mfs_buffer_count += no_of_buffers;
 			if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
-			int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
+				int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
 				fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
 				update_MFSBQ_indx(fi, count);
-				return;
 			}
+			return;
 		}
 		if (wrap_around) {
 		int wrap_size = no_of_wrap_buffs * MFS_BUFFER_SIZE;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v2.4.2/linux/drivers/net/fmv18x.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/fmv18x.c	Sat Mar  3 10:55:48 2001
@@ -52,6 +52,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/errno.h>
+#include <linux/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -79,6 +80,7 @@
 	uint rx_started:1;			/* Packets are Rxing. */
 	uchar tx_queue;				/* Number of packet on the Tx queue. */
 	ushort tx_queue_len;		/* Current length of the Tx queue. */
+	spinlock_t lock;
 };
 
 
@@ -161,6 +163,7 @@
 	char irqmap[4] = {3, 7, 10, 15};
 	char irqmap_pnp[8] = {3, 4, 5, 7, 9, 10, 11, 15};
 	unsigned int i, irq, retval;
+	struct net_local *lp;
 
 	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
 	   That means we have to be careful with the register values we probe for.
@@ -268,6 +271,8 @@
 		goto out_irq;
 	}
 	memset(dev->priv, 0, sizeof(struct net_local));
+	lp = dev->priv;
+	spin_lock_init(&lp->lock);
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
@@ -292,7 +297,7 @@
 
 static int net_open(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 
 	/* Set the configuration register 0 to 32K 100ns. byte-wide memory,
@@ -326,7 +331,7 @@
 
 static void net_timeout(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 	
@@ -346,8 +351,7 @@
 		htons(inw(ioaddr+FJ_CONFIG0)));
 	lp->stats.tx_errors++;
 	/* ToDo: We should try to restart the adaptor... */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lp->lock, flags);
 
 	/* Initialize LAN Controller and LAN Card */
 	outb(0xda, ioaddr + CONFIG_0);   /* Initialize LAN Controller */
@@ -355,20 +359,21 @@
 	outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
 	outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */
 	net_open(dev);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lp->lock, flags);
+
+	netif_wake_queue(dev);
 }
 
 static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	unsigned char *buf = skb->data;
+	unsigned long flags;
 
 	/* Block a transmit from overlapping.  */
 	
-	netif_stop_queue(dev);
-	
 	if (length > ETH_FRAME_LEN) {
 		if (net_debug)
 			printk("%s: Attempting to send a large packet (%d bytes).\n",
@@ -383,6 +388,7 @@
 	   codes we possibly catch a Tx interrupt. Thus we flag off
 	   tx_queue_ready, so that we prevent the interrupt routine
 	   (net_interrupt) to start transmitting. */
+	spin_lock_irqsave(&lp->lock, flags);
 	lp->tx_queue_ready = 0;
 	{
 		outw(length, ioaddr + DATAPORT);
@@ -391,6 +397,8 @@
 		lp->tx_queue_len += length + 2;
 	}
 	lp->tx_queue_ready = 1;
+	spin_unlock_irqrestore(&lp->lock, flags);
+
 	if (lp->tx_started == 0) {
 		/* If the Tx is idle, always trigger a transmit. */
 		outb(0x80 | lp->tx_queue, ioaddr + TX_START);
@@ -398,10 +406,10 @@
 		lp->tx_queue_len = 0;
 		dev->trans_start = jiffies;
 		lp->tx_started = 1;
-		netif_wake_queue(dev);
 	} else if (lp->tx_queue_len < 4096 - 1502)
 		/* Yes, there is room for one more packet. */
-		netif_wake_queue(dev);
+	else
+		netif_stop_queue(dev);
 
 	dev_kfree_skb(skb);
 	return 0;
@@ -417,7 +425,7 @@
 	int ioaddr, status;
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = dev->priv;
 	status = inw(ioaddr + TX_STATUS);
 	outw(status, ioaddr + TX_STATUS);
 
@@ -447,6 +455,7 @@
 			lp->stats.collisions++;
 		}
 		if (status & 0x82) {
+			spin_lock(&lp->lock);
 			lp->stats.tx_packets++;
 			if (lp->tx_queue && lp->tx_queue_ready) {
 				outb(0x80 | lp->tx_queue, ioaddr + TX_START);
@@ -458,6 +467,7 @@
 				lp->tx_started = 0;
 				netif_wake_queue(dev);	/* Inform upper layers. */
 			}
+			spin_unlock(&lp->lock);
 		}
 	}
 	return;
@@ -466,7 +476,7 @@
 /* We have a good packet(s), get it/them out of the buffers. */
 static void net_rx(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 	int boguscount = 5;
 
@@ -581,7 +591,7 @@
    closed. */
 static struct net_device_stats *net_get_stats(struct net_device *dev)
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
+	struct net_local *lp = dev->priv;
 	return &lp->stats;
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c
--- v2.4.2/linux/drivers/net/hamachi.c	Wed Feb 21 18:20:26 2001
+++ linux/drivers/net/hamachi.c	Sat Mar  3 10:55:48 2001
@@ -477,6 +477,7 @@
 };
 
 #define PRIV_ALIGN   15    				/* Required alignment mask */
+#define MII_CNT		4
 struct hamachi_private {
 	/* Descriptor rings first for alignment.  Tx requires a second descriptor
 	   for status. */
@@ -503,7 +504,7 @@
 	/* MII transceiver section. */
 	int mii_cnt;								/* MII device addresses. */
 	u16 advertising;							/* NWay media advertisement */
-	unsigned char phys[2];					/* MII device addresses. */
+	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	u_int32_t rx_int_var, tx_int_var;	/* interrupt control variables */
 	u_int32_t option;							/* Hold on to a copy of the options */
 	u_int8_t pad[16];							/* Used for 32-byte alignment */
@@ -554,7 +555,7 @@
 	struct hamachi_private *hmp;
 	int option, i, rx_int_var, tx_int_var, boguscnt;
 	int chip_id = ent->driver_data;
-	int irq = pdev->irq;
+	int irq;
 	long ioaddr;
 	static int card_idx = 0;
 	struct net_device *dev;
@@ -562,15 +563,17 @@
 	if (hamachi_debug > 0  &&  did_version++ == 0)
 		printk(version);
 
+	if (pci_enable_device(pdev))
+		return -EIO;
+
 	ioaddr = pci_resource_start(pdev, 0);
 #ifdef __alpha__				/* Really "64 bit addrs" */
 	ioaddr |= (pci_resource_start(pdev, 1) << 32);
 #endif
 
-	if (pci_enable_device(pdev))
-		return -EIO;
 	pci_set_master(pdev);
 
+	irq = pdev->irq;
 	ioaddr = (long) ioremap(ioaddr, 0x400);
 	if (!ioaddr)
 		return -ENOMEM;
@@ -703,7 +706,7 @@
 
 	if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {
 		int phy, phy_idx = 0;
-		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
 			int mii_status = mdio_read(ioaddr, phy, 1);
 			if (mii_status != 0xffff  &&
 				mii_status != 0x0000) {
@@ -1062,7 +1065,6 @@
 	hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 	/* Mark the last entry as wrapping the ring. */
 	hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing);
-
 
 	/* Trigger an immediate transmit demand. */
 	dev->trans_start = jiffies;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.4.2/linux/drivers/net/hamradio/scc.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/hamradio/scc.c	Tue Mar 20 12:05:00 2001
@@ -582,7 +582,7 @@
 		
 		if (skb != NULL) 
 			dev_kfree_skb_irq(skb);
-		scc->rx_buff = NULL;
+		scc->rx_buff = skb = NULL;
 	}
 
 	if(status & END_FR && skb != NULL)	/* end of frame */
@@ -689,7 +689,7 @@
 			break;
 		}
 
-		/* This looks wierd and it is. At least the BayCom USCC doesn't
+		/* This looks weird and it is. At least the BayCom USCC doesn't
 		 * use the Interrupt Daisy Chain, thus we'll have to start
 		 * all over again to be sure not to miss an interrupt from 
 		 * (any of) the other chip(s)...
diff -u --recursive --new-file v2.4.2/linux/drivers/net/hamradio/soundmodem/gentbl.c linux/drivers/net/hamradio/soundmodem/gentbl.c
--- v2.4.2/linux/drivers/net/hamradio/soundmodem/gentbl.c	Thu Jun 25 12:25:16 1998
+++ linux/drivers/net/hamradio/soundmodem/gentbl.c	Tue Mar 20 12:04:59 2001
@@ -26,6 +26,7 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <math.h>
 #include <string.h>
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.4.2/linux/drivers/net/hp100.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/hp100.c	Sat Mar  3 10:55:47 2001
@@ -45,6 +45,8 @@
 **   along with this program; if not, write to the Free Software
 **   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 **
+** 1.57b -> 1.57c - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+**   - release resources on failure in init_module
 **
 ** 1.57 -> 1.57b - Jean II
 **   - fix spinlocks, SMP is now working !
@@ -265,12 +267,14 @@
 
 #define HP100_EISA_IDS_SIZE	(sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id))
 
+#ifdef CONFIG_PCI
 static struct hp100_pci_id hp100_pci_ids[] = {
   { PCI_VENDOR_ID_HP, 		PCI_DEVICE_ID_HP_J2585A },
   { PCI_VENDOR_ID_HP,		PCI_DEVICE_ID_HP_J2585B },
   { PCI_VENDOR_ID_COMPEX,	PCI_DEVICE_ID_COMPEX_ENET100VG4 },
   { PCI_VENDOR_ID_COMPEX2,	PCI_DEVICE_ID_COMPEX2_100VG }
 };
+#endif
 
 #define HP100_PCI_IDS_SIZE	(sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id))
 
@@ -1896,7 +1900,7 @@
 
   /* First get indication of received lan packet */
   /* RX_PKT_CND indicates the number of packets which have been fully */
-  /* received onto the card but have not been fully transfered of the card */
+  /* received onto the card but have not been fully transferred of the card */
   packets = hp100_inb( RX_PKT_CNT );
 #ifdef HP100_DEBUG_RX
   if ( packets > 1 )
@@ -1967,11 +1971,6 @@
 	    insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 );
       
 	  skb->protocol = eth_type_trans( skb, dev );
-
-	  netif_rx( skb );
-	  dev->last_rx = jiffies;
-	  lp->stats.rx_packets++;
-	  lp->stats.rx_bytes += pkt_len;
       
 #ifdef HP100_DEBUG_RX
 	  printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
@@ -1979,6 +1978,10 @@
 		  ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ],
 		  ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] );
 #endif
+	  netif_rx( skb );
+	  dev->last_rx = jiffies;
+	  lp->stats.rx_packets++;
+	  lp->stats.rx_bytes += pkt_len;
 	}
   
       /* Indicate the card that we have got the packet */
@@ -3017,16 +3020,34 @@
 #ifdef MODULE
 
 /* Parameters set by insmod */
-int hp100_port[5] = { 0, -1, -1, -1, -1 };
+static int hp100_port[5] = { 0, -1, -1, -1, -1 };
 MODULE_PARM(hp100_port, "1-5i");
 
 /* Allocate 5 string of length IFNAMSIZ, one string for each device */
-char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
+static char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" };
 /* Allow insmod to write those 5 strings individually */
 MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ));
 
 /* List of devices */
-static struct net_device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL };
+static struct net_device *hp100_devlist[5];
+
+static void release_dev(int i)
+{
+	struct net_device *d = hp100_devlist[i];
+	struct hp100_private *p = (struct hp100_private *)d->priv;
+
+	unregister_netdev(d);
+	release_region(d->base_addr, HP100_REGION_SIZE);
+
+	if (p->mode == 1) /* busmaster */
+		kfree(p->page_vaddr); 
+	if (p->mem_ptr_virt)
+		iounmap(p->mem_ptr_virt);
+	kfree(d->priv);
+	d->priv = NULL;
+	kfree(d);
+	hp100_devlist[i] = NULL;
+}
 
 /*
  * Note: if you have more than five 100vg cards in your pc, feel free to
@@ -3053,6 +3074,8 @@
     {
       /* Create device and set basics args */
       hp100_devlist[i] = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+      if (!hp100_devlist[i])
+	goto fail;
       memset(hp100_devlist[i], 0x00, sizeof(struct net_device));
 #if LINUX_VERSION_CODE >= 0x020362	/* 2.3.99-pre7 */
       memcpy(hp100_devlist[i]->name, hp100_name[i], IFNAMSIZ);	/* Copy name */
@@ -3075,6 +3098,13 @@
     }			/* Loop over all devices */
 
   return cards > 0 ? 0 : -ENODEV;
+ fail:
+  while (cards && --i)
+	  if (hp100_devlist[i]) {
+		release_dev(i);
+		--cards;
+	  }
+  return -ENOMEM;
 }
 
 void cleanup_module( void )
@@ -3084,18 +3114,7 @@
   /* TODO: Check if all skb's are released/freed. */
   for(i = 0; i < 5; i++)
     if(hp100_devlist[i] != (struct net_device *) NULL)
-      {
-	unregister_netdev( hp100_devlist[i] );
-	release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE );
-	if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */
-	  kfree( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr ); 
-	if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt )
-	  iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt );
-	kfree( hp100_devlist[i]->priv );
-	hp100_devlist[i]->priv = NULL;
-	kfree(hp100_devlist[i]);
-	hp100_devlist[i] = (struct net_device *) NULL;
-      }
+	    release_dev(i);
 }
 
 #endif		/* MODULE */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/ibmlana.h linux/drivers/net/ibmlana.h
--- v2.4.2/linux/drivers/net/ibmlana.h	Tue Jul 11 11:12:23 2000
+++ linux/drivers/net/ibmlana.h	Tue Mar  6 19:28:34 2001
@@ -127,12 +127,12 @@
 #define TCREG_POWC       0x4000	/* timer start out of window detect */
 #define TCREG_CRCI       0x2000	/* inhibit CRC generation           */
 #define TCREG_EXDIS      0x1000	/* disable excessive deferral timer */
-#define TCREG_EXD        0x0400	/* excessive deferral occured       */
-#define TCREG_DEF        0x0200	/* single deferral occured          */
+#define TCREG_EXD        0x0400	/* excessive deferral occurred       */
+#define TCREG_DEF        0x0200	/* single deferral occurred          */
 #define TCREG_NCRS       0x0100	/* no carrier detected              */
 #define TCREG_CRSL       0x0080	/* carrier lost                     */
-#define TCREG_EXC        0x0040	/* excessive collisions occured     */
-#define TCREG_OWC        0x0020	/* out of window collision occured  */
+#define TCREG_EXC        0x0040	/* excessive collisions occurred     */
+#define TCREG_OWC        0x0020	/* out of window collision occurred  */
 #define TCREG_PMB        0x0008	/* packet monitored bad             */
 #define TCREG_FU         0x0004	/* FIFO underrun                    */
 #define TCREG_BCM        0x0002	/* byte count mismatch of fragments */
@@ -141,7 +141,7 @@
 /* Interrupt Mask Register */
 
 #define SONIC_IMREG      0x08
-#define IMREG_BREN       0x4000	/* interrupt when bus retry occured */
+#define IMREG_BREN       0x4000	/* interrupt when bus retry occurred */
 #define IMREG_HBLEN      0x2000	/* interrupt when heartbeat lost    */
 #define IMREG_LCDEN      0x1000	/* interrupt when CAM loaded        */
 #define IMREG_PINTEN     0x0800	/* interrupt when PINT in TDA set   */
@@ -160,7 +160,7 @@
 /* Interrupt Status Register */
 
 #define SONIC_ISREG      0x0a
-#define ISREG_BR         0x4000	/* bus retry occured                */
+#define ISREG_BR         0x4000	/* bus retry occurred                */
 #define ISREG_HBL        0x2000	/* heartbeat lost                   */
 #define ISREG_LCD        0x1000	/* CAM loaded                       */
 #define ISREG_PINT       0x0800	/* PINT in TDA set                  */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
--- v2.4.2/linux/drivers/net/ioc3-eth.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/ioc3-eth.c	Tue Mar 20 12:04:58 2001
@@ -67,11 +67,16 @@
 #include <asm/sn/sn0/ip27.h>
 #include <asm/pci/bridge.h>
 
-/* 32 RX buffers.  This is tunable in the range of 16 <= x < 512.  */
+/*
+ * 32 RX buffers.  This is tunable in the range of 16 <= x < 512.  The
+ * value must be a power of two.
+ */
 #define RX_BUFFS 64
 
-/* Private ioctls that de facto are well known and used for examply
-   by mii-tool.  */
+/*
+ * Private ioctls that de facto are well known and used for examply
+ * by mii-tool.
+ */
 #define SIOCGMIIPHY (SIOCDEVPRIVATE)	/* Read from current PHY */
 #define SIOCGMIIREG (SIOCDEVPRIVATE+1)	/* Read any PHY register */
 #define SIOCSMIIREG (SIOCDEVPRIVATE+2)	/* Write any PHY register */
@@ -707,8 +712,10 @@
 
 	if (ip->rxr == NULL) {
 		/* Allocate and initialize rx ring.  4kb = 512 entries  */
-		ip->rxr = (unsigned long *) get_free_page(GFP_KERNEL|GFP_ATOMIC);
+		ip->rxr = (unsigned long *) get_free_page(GFP_ATOMIC);
 		rxr = (unsigned long *) ip->rxr;
+		if (!rxr)
+			printk("ioc3_alloc_rings(): get_free_page() failed!\n");
 
 		/* Now the rx buffers.  The RX ring may be larger but
 		   we only allocate 16 buffers for now.  Need to tune
@@ -738,7 +745,9 @@
 
 	if (ip->txr == NULL) {
 		/* Allocate and initialize tx rings.  16kb = 128 bufs.  */
-		ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL|GFP_ATOMIC, 2);
+		ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2);
+		if (!ip->txr)
+			printk("ioc3_alloc_rings(): get_free_page() failed!\n");
 		ip->tx_pi = 0;
 		ip->tx_ci = 0;
 	}
@@ -862,9 +871,6 @@
 	ioc3_init(dev);
 
 	netif_start_queue(dev);
-
-	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -880,27 +886,26 @@
 	free_irq(dev->irq, dev);
 
 	ioc3_free_rings(ip);
-
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
-static int ioc3_pci_init(struct pci_dev *pdev)
+static int __devinit ioc3_probe(struct pci_dev *pdev,
+	                        const struct pci_device_id *ent)
 {
 	u16 mii0, mii_status, mii2, mii3, mii4;
-	struct net_device *dev = NULL;	// XXX
+	struct net_device *dev = NULL;
 	struct ioc3_private *ip;
 	struct ioc3 *ioc3;
 	unsigned long ioc3_base, ioc3_size;
 	u32 vendor, model, rev;
-	int phy;
+	int phy, err;
 
 	dev = init_etherdev(0, sizeof(struct ioc3_private));
 
 	if (!dev)
 		return -ENOMEM;
 
+	SET_MODULE_OWNER(dev);
 	ip = dev->priv;
 	memset(ip, 0, sizeof(*ip));
 
@@ -916,6 +921,11 @@
 	ioc3_base = pdev->resource[0].start;
 	ioc3_size = pdev->resource[0].end - ioc3_base;
 	ioc3 = (struct ioc3 *) ioremap(ioc3_base, ioc3_size);
+	if (!ioc3) {
+		printk(KERN_CRIT"%s: Unable to map device I/O.\n", dev->name);
+		err = -ENOMEM;
+		goto out_free;
+	}
 	ip->regs = ioc3;
 
 	spin_lock_init(&ip->ioc3_lock);
@@ -930,11 +940,8 @@
 	phy = ip->phy;
 	if (phy == -1) {
 		printk(KERN_CRIT"%s: Didn't find a PHY, goodbye.\n", dev->name);
-		ioc3_stop(dev);
-		free_irq(dev->irq, dev);
-		ioc3_free_rings(ip);
-
-		return -ENODEV;
+		err = -ENODEV;
+		goto out_stop;
 	}
 
 	mii0 = mii_read(ioc3, phy, 0);
@@ -967,34 +974,42 @@
 	dev->set_multicast_list	= ioc3_set_multicast_list;
 
 	return 0;
+
+out_stop:
+	ioc3_stop(dev);
+	free_irq(dev->irq, dev);
+	ioc3_free_rings(ip);
+out_free:
+	kfree(dev);
+	return err;
 }
 
-static int __init ioc3_probe(void)
+static void __devexit eepro100_remove_one (struct pci_dev *pdev)
 {
-	static int called = 0;
-	int cards = 0;
-
-	if (called)
-		return -ENODEV;
-	called = 1;
+	/* Later ... */
+}
 
-	if (pci_present()) {
-		struct pci_dev *pdev = NULL;
+static struct pci_device_id ioc3_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(pci, ioc3_pci_tbl);
 
-		while ((pdev = pci_find_device(PCI_VENDOR_ID_SGI,
-		                               PCI_DEVICE_ID_SGI_IOC3, pdev))) {
-			if (ioc3_pci_init(pdev))
-				return -ENOMEM;
-			cards++;
-		}
-	}
+static struct pci_driver ioc3_driver = {
+	name:		"ioc3-eth",
+	id_table:	ioc3_pci_tbl,
+	probe:		ioc3_probe,
+	/* remove:		ioc3_remove_one, */
+};
 
-	return cards ? -ENODEV : 0;
+static int __init ioc3_init_module(void)
+{
+	return pci_module_init(&ioc3_driver);
 }
 
 static void __exit ioc3_cleanup_module(void)
 {
-	/* Later, when we really support modules.  */
+	pci_unregister_driver(&ioc3_driver);
 }
 
 static int
@@ -1192,10 +1207,8 @@
 	}
 }
 
-#ifdef MODULE
 MODULE_AUTHOR("Ralf Baechle <ralf@oss.sgi.com>");
 MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
-#endif /* MODULE */
 
-module_init(ioc3_probe);
+module_init(ioc3_init_module);
 module_exit(ioc3_cleanup_module);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- v2.4.2/linux/drivers/net/irda/irport.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/irda/irport.c	Tue Mar 20 12:04:59 2001
@@ -609,7 +609,7 @@
  *
  *    Transmits the current frame until FIFO is full, then
  *    waits until the next transmitt interrupt, and continues until the
- *    frame is transmited.
+ *    frame is transmitted.
  */
 int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -1008,7 +1008,7 @@
 
 #ifdef MODULE
 MODULE_PARM(io, "1-4i");
-MODULE_PARM_DESC(io, "Base I/O adresses");
+MODULE_PARM_DESC(io, "Base I/O addresses");
 MODULE_PARM(irq, "1-4i");
 MODULE_PARM_DESC(irq, "IRQ lines");
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.4.2/linux/drivers/net/irda/irtty.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/irda/irtty.c	Tue Mar 20 12:04:59 2001
@@ -824,7 +824,7 @@
 /*
  * Function irtty_raw_read (self, buf, len)
  *
- *    Receive incomming data. This function sleeps, so it must only be
+ *    Receive incoming data. This function sleeps, so it must only be
  *    called with a process context. Timeout is currently defined to be
  *    a multiple of 10 ms.
  */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- v2.4.2/linux/drivers/net/irda/nsc-ircc.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/irda/nsc-ircc.c	Tue Mar 20 12:04:59 2001
@@ -1263,7 +1263,7 @@
  * Function nsc_ircc_pio_xmit (self, iobase)
  *
  *    Transmit data using PIO. Returns the number of bytes that actually
- *    got transfered
+ *    got transferred
  *
  */
 static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- v2.4.2/linux/drivers/net/irda/smc-ircc.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/irda/smc-ircc.c	Tue Mar 20 12:04:59 2001
@@ -560,7 +560,7 @@
 		 */
 		/* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */
 
-		/* Be ready for incomming frames */
+		/* Be ready for incoming frames */
 		ircc_dma_receive(self, iobase);
 	} else {
 		/* Install SIR transmit handler */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- v2.4.2/linux/drivers/net/irda/w83977af_ir.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/irda/w83977af_ir.c	Tue Mar 20 12:04:59 2001
@@ -875,7 +875,7 @@
 				self->stats.rx_fifo_errors++;
 			
 		} else {
-			/* Check if we have transfered all data to memory */
+			/* Check if we have transferred all data to memory */
 			switch_bank(iobase, SET0);
 			if (inb(iobase+USR) & USR_RDR) {
 #ifdef CONFIG_USE_INTERNAL_TIMER
diff -u --recursive --new-file v2.4.2/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c
--- v2.4.2/linux/drivers/net/jazzsonic.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/jazzsonic.c	Sat Mar  3 10:55:47 2001
@@ -62,7 +62,7 @@
 #endif
 
 /*
- * Base address and interupt of the SONIC controller on JAZZ boards
+ * Base address and interrupt of the SONIC controller on JAZZ boards
  */
 static struct {
     unsigned int port;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.4.2/linux/drivers/net/lance.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/lance.c	Tue Mar  6 19:28:35 2001
@@ -33,6 +33,9 @@
     
     Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
     the 2.1 version of the old driver - Alan Cox
+
+    Get rid of check_region, check kmalloc return in lance_probe1
+    Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
 */
 
 static const char *version = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
@@ -61,9 +64,9 @@
 static int lance_probe1(struct net_device *dev, int ioaddr, int irq, int options);
 
 #ifdef LANCE_DEBUG
-int lance_debug = LANCE_DEBUG;
+static int lance_debug = LANCE_DEBUG;
 #else
-int lance_debug = 1;
+static int lance_debug = 1;
 #endif
 
 /*
@@ -295,6 +298,7 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
 MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM(lance_debug, "i");
 
 int init_module(void)
 {
@@ -352,17 +356,27 @@
 
 	for (port = lance_portlist; *port; port++) {
 		int ioaddr = *port;
+		struct resource *r = request_region(ioaddr, LANCE_TOTAL_SIZE,
+							"lance-probe");
 
-		if ( check_region(ioaddr, LANCE_TOTAL_SIZE) == 0) {
+		if (r) {
 			/* Detect "normal" 0x57 0x57 and the NI6510EB 0x52 0x44
 			   signatures w/ minimal I/O reads */
 			char offset15, offset14 = inb(ioaddr + 14);
 			
 			if ((offset14 == 0x52 || offset14 == 0x57) &&
-				((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) {
+				((offset15 = inb(ioaddr + 15)) == 0x57 ||
+				 offset15 == 0x44)) {
 				result = lance_probe1(dev, ioaddr, 0, 0);
-				if ( !result ) return 0;
+				if (!result) {
+					struct lance_private *lp = dev->priv;
+					int ver = lp->chip_version;
+
+					r->name = chip_table[ver].name;
+					return 0;
+				}
 			}
+			release_resource(r);
 		}
 	}
 	return -ENODEV;
@@ -444,12 +458,10 @@
 		printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
 	dev->base_addr = ioaddr;
-	request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
-
 	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
 		
 	lp = (struct lance_private *)(((unsigned long)kmalloc(sizeof(*lp)+7,
-										   GFP_DMA | GFP_KERNEL)+7) & ~7);
+					   GFP_DMA | GFP_KERNEL)+7) & ~7);
 	if(lp==NULL)
 		return -ENODEV;
 	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
@@ -457,11 +469,15 @@
 	dev->priv = lp;
 	lp->name = chipname;
 	lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
-										  GFP_DMA | GFP_KERNEL);
-	if (lance_need_isa_bounce_buffers)
+						  GFP_DMA | GFP_KERNEL);
+	if (!lp->rx_buffs)
+		goto out_lp;
+	if (lance_need_isa_bounce_buffers) {
 		lp->tx_bounce_buffs = kmalloc(PKT_BUF_SZ*TX_RING_SIZE,
-									  GFP_DMA | GFP_KERNEL);
-	else
+						  GFP_DMA | GFP_KERNEL);
+		if (!lp->tx_bounce_buffs)
+			goto out_rx;
+	} else
 		lp->tx_bounce_buffs = NULL;
 
 	lp->chip_version = lance_version;
@@ -628,6 +644,9 @@
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 	return 0;
+out_rx:	kfree((void*)lp->rx_buffs);
+out_lp:	kfree(lp);
+	return -ENOMEM;
 }
 
 static int
diff -u --recursive --new-file v2.4.2/linux/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c
--- v2.4.2/linux/drivers/net/mac89x0.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/mac89x0.c	Tue Mar  6 19:28:35 2001
@@ -48,6 +48,11 @@
   I/O space and NuBus interrupts for these cards, but neglected to
   provide anything even remotely resembling a NuBus ROM.  Therefore we
   have to probe for them in a brain-damaged ISA-like fashion.
+
+  Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
+  check kmalloc and release the allocated memory on failure in
+  mac89x0_probe and in init_module
+  use save_flags/restore_flags in net_get_stat, not just cli/sti
 */
 
 static char *version =
@@ -167,9 +172,9 @@
    anywhere else until we have a really good reason to do so. */
 int __init mac89x0_probe(struct net_device *dev)
 {
-	static int once_is_enough = 0;
+	static int once_is_enough;
 	struct net_local *lp;
-	static unsigned version_printed = 0;
+	static unsigned version_printed;
 	int i, slot;
 	unsigned rev_type = 0;
 	unsigned long ioaddr;
@@ -213,6 +218,8 @@
 	/* Initialize the net_device structure. */
 	if (dev->priv == NULL) {
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+		if (!dev->priv)
+			return -ENOMEM;
                 memset(dev->priv, 0, sizeof(struct net_local));
         }
 	lp = (struct net_local *)dev->priv;
@@ -252,6 +259,8 @@
 	/* Try to read the MAC address */
 	if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
 		printk("\nmac89x0: No EEPROM, giving up now.\n");
+		kfree(dev->priv);
+		dev->priv = NULL;
 		return -ENODEV;
         } else {
                 for (i = 0; i < ETH_ALEN; i += 2) {
@@ -558,12 +567,14 @@
 net_get_stats(struct net_device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
 
+	save_flags(flags);
 	cli();
 	/* Update the statistics from the device registers. */
 	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
 	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
-	sti();
+	restore_flags(flags);
 
 	return &lp->stats;
 }
@@ -621,16 +632,16 @@
 int
 init_module(void)
 {
-	struct net_local *lp;
-
 	net_debug = debug;
         dev_cs89x0.init = mac89x0_probe;
         dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if (!dev_cs89x0.priv)
+		return -ENOMEM;
 	memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
-	lp = (struct net_local *)dev_cs89x0.priv;
 
         if (register_netdev(&dev_cs89x0) != 0) {
                 printk(KERN_WARNING "mac89x0.c: No card found\n");
+		kfree(dev_cs89x0.priv);
                 return -ENXIO;
         }
 	return 0;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.4.2/linux/drivers/net/mace.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/mace.c	Tue Mar 20 12:05:01 2001
@@ -87,7 +87,7 @@
 /*
  * If we can't get a skbuff when we need it, we use this area for DMA.
  */
-static unsigned char dummy_buf[RX_BUFLEN+2];
+static unsigned char *dummy_buf;
 
 /* Bit-reverse one byte of an ethernet hardware address. */
 static inline int
@@ -106,7 +106,7 @@
 
 	for (mace = find_devices("mace"); mace != NULL; mace = mace->next)
 		mace_probe1(mace);
-	return 0;
+	return mace_devs? 0: -ENODEV;
 }
 
 static void __init mace_probe1(struct device_node *mace)
@@ -132,6 +132,14 @@
 		}
 	}
 
+	if (dummy_buf == NULL) {
+		dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL);
+		if (dummy_buf == NULL) {
+			printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n");
+			return;
+		}
+	}
+
 	dev = init_etherdev(0, PRIV_BYTES);
 	if (!dev)
 		return;
@@ -897,6 +905,10 @@
 
 	unregister_netdev(dev);
 	kfree(dev);
+    }
+    if (dummy_buf != NULL) {
+	kfree(dummy_buf);
+	dummy_buf = NULL;
     }
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/macmace.c linux/drivers/net/macmace.c
--- v2.4.2/linux/drivers/net/macmace.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/macmace.c	Sat Mar  3 10:55:47 2001
@@ -632,7 +632,7 @@
 }
 
 /*
- *	A transmit error has occured. (We kick the transmit side from
+ *	A transmit error has occurred. (We kick the transmit side from
  *	the DMA completion)
  */
  
@@ -661,7 +661,7 @@
 }
 
 /*
- *	A receive interrupt occured.
+ *	A receive interrupt occurred.
  */
  
 static void mace68k_recv_interrupt(struct net_device *dev)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.4.2/linux/drivers/net/macsonic.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/macsonic.c	Tue Mar  6 19:28:35 2001
@@ -59,8 +59,8 @@
 
 #include "sonic.h"
 
-static int sonic_debug = 0;
-static int sonic_version_printed = 0;
+static int sonic_debug;
+static int sonic_version_printed;
 
 extern int macsonic_probe(struct net_device* dev);
 extern int mac_onboard_sonic_probe(struct net_device* dev);
@@ -272,7 +272,7 @@
 int __init mac_onboard_sonic_probe(struct net_device* dev)
 {
 	/* Bwahahaha */
-	static int once_is_more_than_enough = 0;
+	static int once_is_more_than_enough;
 	struct sonic_local* lp;
 	int i;
 	
@@ -438,7 +438,7 @@
 
 int __init mac_nubus_sonic_probe(struct net_device* dev)
 {
-	static int slots = 0;
+	static int slots;
 	struct nubus_dev* ndev = NULL;
 	struct sonic_local* lp;
 	unsigned long base_addr, prom_addr;
@@ -567,11 +567,7 @@
 
 #ifdef MODULE
 static char namespace[16] = "";
-static struct net_device dev_macsonic = {
-        NULL,
-        0, 0, 0, 0,
-        0, 0,
-        0, 0, 0, NULL, NULL };
+static struct net_device dev_macsonic;
 
 MODULE_PARM(sonic_debug, "i");
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/ne.c linux/drivers/net/ne.c
--- v2.4.2/linux/drivers/net/ne.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/ne.c	Tue Mar  6 19:28:34 2001
@@ -76,13 +76,18 @@
 };
 #endif
 
-static struct { unsigned short vendor, function; char *name; }
-isapnp_clone_list[] __initdata = {
-	{ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216),		"NN NE2000" },
-	{ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6),		"Generic PNP" },
-	{0,}
+static struct isapnp_device_id isapnp_clone_list[] __initdata = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216),
+		(long) "NN NE2000" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6),
+		(long) "Generic PNP" },
+	{ }	/* terminate list */
 };
 
+MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list);
+
 #ifdef SUPPORT_NE_BAD_CLONES
 /* A list of bad clones that we none-the-less recognize. */
 static struct { const char *name8, *name16; unsigned char SAprefix[4];}
@@ -206,7 +211,7 @@
 			dev->base_addr = idev->resource[0].start;
 			dev->irq = idev->irq_resource[0].start;
 			printk(KERN_INFO "ne.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
-				isapnp_clone_list[i].name,
+				(char *) isapnp_clone_list[i].driver_data,
 
 				dev->base_addr, dev->irq);
 			if (ne_probe1(dev, dev->base_addr) != 0) {	/* Shouldn't happen. */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.4.2/linux/drivers/net/net_init.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/net_init.c	Fri Mar  2 11:02:15 2001
@@ -390,23 +390,6 @@
 
 #endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
 
-int ether_config(struct net_device *dev, struct ifmap *map)
-{
-	if (map->mem_start != (u_long)(-1))
-		dev->mem_start = map->mem_start;
-	if (map->mem_end != (u_long)(-1))
-		dev->mem_end = map->mem_end;
-	if (map->base_addr != (u_short)(-1))
-		dev->base_addr = map->base_addr;
-	if (map->irq != (u_char)(-1))
-		dev->irq = map->irq;
-	if (map->dma != (u_char)(-1))
-		dev->dma = map->dma;
-	if (map->port != (u_char)(-1))
-		dev->if_port = map->port;
-	return 0;
-}
-
 int register_netdev(struct net_device *dev)
 {
 	int err;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/ni5010.c linux/drivers/net/ni5010.c
--- v2.4.2/linux/drivers/net/ni5010.c	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/ni5010.c	Tue Mar  6 19:28:34 2001
@@ -469,7 +469,7 @@
         }
 
         if ((status & IS_DMA_INT) == 0) {
-                PRINTK((KERN_DEBUG "%s: DMA complete (???)\n", dev->name));
+                PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name));
                 outb(0, IE_DMA_RST); /* Reset DMA int */
         }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/ni52.h linux/drivers/net/ni52.h
--- v2.4.2/linux/drivers/net/ni52.h	Wed Feb 21 18:20:27 2001
+++ linux/drivers/net/ni52.h	Tue Mar  6 19:28:34 2001
@@ -68,7 +68,7 @@
   unsigned short cbl_offset;    /* pointeroffset, command block list */
   unsigned short rfa_offset;    /* pointeroffset, receive frame area */
   unsigned short crc_errs;      /* CRC-Error counter */
-  unsigned short aln_errs;      /* allignmenterror counter */
+  unsigned short aln_errs;      /* alignmenterror counter */
   unsigned short rsc_errs;      /* Resourceerror counter */
   unsigned short ovrn_errs;     /* OVerrunerror counter */
 };
diff -u --recursive --new-file v2.4.2/linux/drivers/net/oaknet.c linux/drivers/net/oaknet.c
--- v2.4.2/linux/drivers/net/oaknet.c	Sat Dec 30 11:23:14 2000
+++ linux/drivers/net/oaknet.c	Sat Mar  3 10:55:47 2001
@@ -53,7 +53,7 @@
 
 static const char *name = "National DP83902AV";
 
-static struct net_device *oaknet_devs = NULL;
+static struct net_device *oaknet_devs;
 
 
 /* Function Prototypes */
@@ -94,6 +94,7 @@
 {
 	register int i;
 	int reg0, regd;
+	int ret;
 	struct net_device tmp, *dev = NULL;
 #if 0
 	unsigned long ioaddr = OAKNET_IO_BASE; 
@@ -102,6 +103,8 @@
 #endif
 	bd_t *bip = (bd_t *)__res;
 
+	if (!ioaddr)
+		return -ENOMEM;
 	/*
 	 * This MUST happen here because of the nic_* macros
 	 * which have an implicit dependency on dev->base_addr.
@@ -110,15 +113,15 @@
 	tmp.base_addr = ioaddr;
 	dev = &tmp;
 
+	ret = -EBUSY;
 	if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))
-		return -EBUSY;
+		goto out_unmap;
 
 	/* Quick register check to see if the device is really there. */
 
-	if ((reg0 = ei_ibp(ioaddr)) == 0xFF) {
-		release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-		return (ENODEV);
-	}
+	ret = -ENODEV;
+	if ((reg0 = ei_ibp(ioaddr)) == 0xFF)
+		goto out_region;
 
 	/*
 	 * That worked. Now a more thorough check, using the multicast
@@ -134,13 +137,11 @@
 
 	/* It's no good. Fix things back up and leave. */
 
+	ret = -ENODEV;
 	if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {
 		ei_obp(reg0, ioaddr);
 		ei_obp(regd, ioaddr + 0x0D);
-		dev->base_addr = 0;
-
-		release_region(dev->base_addr, OAKNET_IO_SIZE);
-		return (-ENODEV);
+		goto out_region;
 	}
 
 	/*
@@ -149,10 +150,9 @@
 	 */
 
 	dev = init_etherdev(NULL, 0);
-	if (!dev) {
-		release_region(dev->base_addr, OAKNET_IO_SIZE);
-		return (-ENOMEM);
-	}
+	ret = -ENOMEM;
+	if (!dev)
+		goto out_region;
 	SET_MODULE_OWNER(dev);
 	oaknet_devs = dev;
 
@@ -166,10 +166,10 @@
 
 	/* Allocate 8390-specific device-private area and fields. */
 
+	ret = -ENOMEM;
 	if (ethdev_init(dev)) {
 		printk(" unable to get memory for dev->priv.\n");
-		release_region(dev->base_addr, OAKNET_IO_SIZE);
-		return (-ENOMEM);
+		goto out_dev;
 	}
 
 	/*
@@ -182,12 +182,11 @@
 
 	/* Attempt to get the interrupt line */
 
+	ret = -EAGAIN;
 	if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
 		printk("%s: unable to request interrupt %d.\n",
 		       dev->name, dev->irq);
-		kfree(dev->priv);
-		release_region(dev->base_addr, OAKNET_IO_SIZE);
-		return (EAGAIN);
+		goto out_priv;
 	}
 
 	/* Tell the world about what and where we've found. */
@@ -218,6 +217,16 @@
 	NS8390_init(dev, FALSE);
 
 	return (0);
+out_priv:
+	kfree(dev->priv);
+out_dev:
+	unregister_netdev(dev);
+	kfree(dev);
+out_region:
+	release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
+out_unmap:
+	iounmap(ioaddr);
+	return ret;
 }
 
 /*
@@ -303,8 +312,6 @@
 	ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);
 	ei_status.txing = 0;
 	ei_status.dmaing = 0;
-
-	return;
 }
 
 /*
@@ -365,8 +372,6 @@
 
 	outb_p(ENISR_RDC, base + EN0_ISR);	/* ACK Remote DMA interrupt */
 	ei_status.dmaing &= ~0x01;
-
-	return;
 }
 
 /*
@@ -444,8 +449,6 @@
 #ifdef OAKNET_DISINT
 	restore_flags(flags);
 #endif
-
-	return;
 }
 
 /*
@@ -627,8 +630,6 @@
 	
 	ei_obp(ENISR_RDC, base + EN0_ISR);	/* Ack intr. */
 	ei_status.dmaing &= ~0x01;
-
-	return;
 }
 
 /*
@@ -636,7 +637,7 @@
  *
  * Description:
  *   This routine prints out a last-ditch informative message to the console
- *   indicating that a DMA error occured. If you see this, it's the last
+ *   indicating that a DMA error occurred. If you see this, it's the last
  *   thing you'll see.
  *
  * Input(s):
@@ -658,8 +659,6 @@
 	       "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
 	       dev->name, name, ei_status.dmaing, ei_status.irqlock,
 	       dev->interrupt);
-
-	return;
 }
 
 /*
@@ -686,12 +685,13 @@
 		void *priv = oaknet_devs->priv;
 		free_irq(oaknet_devs->irq, oaknet_devs);
 		release_region(ioaddr, OAKNET_IO_SIZE);
+		iounmap(ioaddr);
 		unregister_netdev(oaknet_dev);
 		kfree(priv);
 	}
 
-	oaknet_devs = NULL;
-
+	/* Convert to loop once driver supports multiple devices. */
+	kfree(oaknet_devs);
 }
 
 module_init(oaknet_init_module);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pci-skeleton.c linux/drivers/net/pci-skeleton.c
--- v2.4.2/linux/drivers/net/pci-skeleton.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pci-skeleton.c	Tue Mar 20 12:05:01 2001
@@ -609,6 +609,11 @@
 	SET_MODULE_OWNER(dev);
 	tp = dev->priv;
 
+	/* enable device (incl. PCI PM wakeup), and bus-mastering */
+	rc = pci_enable_device (pdev);
+	if (rc)
+		goto err_out;
+
 	pio_start = pci_resource_start (pdev, 0);
 	pio_end = pci_resource_end (pdev, 0);
 	pio_flags = pci_resource_flags (pdev, 0);
@@ -623,8 +628,6 @@
 	 * we talk to the chip directly */
 	DPRINTK("PIO region size == 0x%02X\n", pio_len);
 	DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
-	if (pio_len == RTL8139B_IO_SIZE)
-		tp->chipset = CH_8139B;
 
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
@@ -648,24 +651,9 @@
 		goto err_out;
 	}
 
-	/* make sure our PIO region in PCI space is available */
-	if (!request_region (pio_start, pio_len, dev->name)) {
-		printk (KERN_ERR PFX "no I/O resource available, aborting\n");
-		rc = -EBUSY;
-		goto err_out;
-	}
-
-	/* make sure our MMIO region in PCI space is available */
-	if (!request_mem_region (mmio_start, mmio_len, dev->name)) {
-		printk (KERN_ERR PFX "no mem resource available, aborting\n");
-		rc = -EBUSY;
-		goto err_out_free_pio;
-	}
-
-	/* enable device (incl. PCI PM wakeup), and bus-mastering */
-	rc = pci_enable_device (pdev);
+	rc = pci_request_regions (pdev, dev->name);
 	if (rc)
-		goto err_out_free_mmio;
+		goto err_out;
 
 	pci_set_master (pdev);
 
@@ -677,7 +665,7 @@
 	if (ioaddr == NULL) {
 		printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
 		rc = -EIO;
-		goto err_out_free_mmio;
+		goto err_out_free_res;
 	}
 #endif /* USE_IO_OPS */
 
@@ -692,14 +680,7 @@
 			udelay (10);
 
 	/* Bring the chip out of low-power mode. */
-	if (tp->chipset == CH_8139B) {
-		NETDRV_W8 (Config1, NETDRV_R8 (Config1) & ~(1<<4));
-		NETDRV_W8 (Config4, NETDRV_R8 (Config4) & ~(1<<2));
-	} else {
-		/* handle RTL8139A and RTL8139 cases */
-		/* XXX from becker driver. is this right?? */
-		NETDRV_W8 (Config1, 0);
-	}
+	/* <insert device-specific code here> */
 
 #ifndef USE_IO_OPS
 	/* sanity checks -- ensure PIO and MMIO registers agree */
@@ -709,19 +690,6 @@
 	assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));
 #endif /* !USE_IO_OPS */
 
-	/* make sure chip thinks PIO and MMIO are enabled */
-	tmp8 = NETDRV_R8 (Config1);
-	if ((tmp8 & Cfg1_PIO) == 0) {
-		printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8);
-		rc = -EIO;
-		goto err_out_iounmap;
-	}
-	if ((tmp8 & Cfg1_MMIO) == 0) {
-		printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8);
-		rc = -EIO;
-		goto err_out_iounmap;
-	}
-
 	/* identify chip attached to board */
 	tmp = NETDRV_R8 (ChipVersion);
 	for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--)
@@ -747,15 +715,10 @@
 	*dev_out = dev;
 	return 0;
 
-err_out_iounmap:
-	assert (ioaddr > 0);
 #ifndef USE_IO_OPS
-	iounmap (ioaddr);
+err_out_free_res:
+	pci_release_regions (pdev);
 #endif /* !USE_IO_OPS */
-err_out_free_mmio:
-	release_mem_region (mmio_start, mmio_len);
-err_out_free_pio:
-	release_region (pio_start, pio_len);
 err_out:
 	unregister_netdev (dev);
 	kfree (dev);
@@ -828,7 +791,7 @@
 	tp->mmio_addr = ioaddr;
 	tp->lock = SPIN_LOCK_UNLOCKED;
 
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
 	tp->phys[0] = 32;
 
@@ -849,12 +812,6 @@
 	/* Put the chip into low-power mode. */
 	NETDRV_W8_F (Cfg9346, Cfg9346_Unlock);
 
-	tmp = NETDRV_R8 (Config1) & Config1Clear;
-	tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
-	NETDRV_W8_F (Config1, tmp);
-
-	NETDRV_W8_F (HltClk, 'H');	/* 'R' would leave the clock running. */
-
 	/* The lower four bits are the media type. */
 	option = (board_idx > 7) ? 0 : media[board_idx];
 	if (option > 0) {
@@ -879,14 +836,14 @@
 
 static void __devexit netdrv_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata (pdev);
 	struct netdrv_private *np;
 
 	DPRINTK ("ENTER\n");
 
 	assert (dev != NULL);
 
-	np = (struct netdrv_private *) (dev->priv);
+	np = dev->priv;
 	assert (np != NULL);
 
 	unregister_netdev (dev);
@@ -895,10 +852,7 @@
 	iounmap (np->mmio_addr);
 #endif /* !USE_IO_OPS */
 
-	release_region (pci_resource_start (pdev, 0),
-			pci_resource_len (pdev, 0));
-	release_mem_region (pci_resource_start (pdev, 1),
-			    pci_resource_len (pdev, 1));
+	pci_release_regions (pdev);
 
 #ifndef NETDRV_NDEBUG
 	/* poison memory before freeing */
@@ -909,7 +863,7 @@
 
 	kfree (dev);
 
-	pdev->driver_data = NULL;
+	pci_set_drvdata (pdev, NULL);
 
 	pci_power_off (pdev, -1);
 
@@ -1029,7 +983,7 @@
 
 static int mdio_read (struct net_device *dev, int phy_id, int location)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *mdio_addr = tp->mmio_addr + Config4;
 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int retval = 0;
@@ -1072,7 +1026,7 @@
 static void mdio_write (struct net_device *dev, int phy_id, int location,
 			int value)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *mdio_addr = tp->mmio_addr + Config4;
 	int mii_cmd =
 	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
@@ -1115,7 +1069,7 @@
 
 static int netdrv_open (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	int retval;
 #ifdef NETDRV_DEBUG
 	void *ioaddr = tp->mmio_addr;
@@ -1176,7 +1130,7 @@
 /* Start the hardware at open or resume. */
 static void netdrv_hw_start (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	u32 i;
 	u8 tmp;
@@ -1213,27 +1167,6 @@
 
 	tp->cur_rx = 0;
 
-	if (tp->chipset >= CH_8139A) {
-		tmp = NETDRV_R8 (Config1) & Config1Clear;
-		tmp |= Cfg1_Driver_Load;
-		tmp |= (tp->chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */
-		NETDRV_W8_F (Config1, tmp);
-	} else {
-		u8 foo = NETDRV_R8 (Config1) & Config1Clear;
-		NETDRV_W8 (Config1, tp->full_duplex ? (foo|0x60) : (foo|0x20));
-	}
-
-	if (tp->chipset >= CH_8139B) {
-		tmp = NETDRV_R8 (Config4) & ~(1<<2);
-		/* chip will clear Rx FIFO overflow automatically */
-		tmp |= (1<<7);
-		NETDRV_W8 (Config4, tmp);
-
-		/* disable magic packet scanning, which is enabled
-		 * when PM is enabled above (Config1) */
-		NETDRV_W8 (Config3, NETDRV_R8 (Config3) & ~(1<<5));
-	}
-
 	/* Lock Config[01234] and BMCR register writes */
 	NETDRV_W8_F (Cfg9346, Cfg9346_Lock);
 	udelay (10);
@@ -1268,7 +1201,7 @@
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void netdrv_init_ring (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	int i;
 
 	DPRINTK ("ENTER\n");
@@ -1287,104 +1220,10 @@
 }
 
 
-#ifndef NETDRV_TUNE_TWISTER
-static inline void netdrv_tune_twister (struct net_device *dev,
-				  struct netdrv_private *tp) {}
-#else
-static void netdrv_tune_twister (struct net_device *dev,
-				  struct netdrv_private *tp)
-{
-	int linkcase;
-
-	DPRINTK ("ENTER\n");
-
-	/* This is a complicated state machine to configure the "twister" for
-	   impedance/echos based on the cable length.
-	   All of this is magic and undocumented.
-	 */
-	switch (tp->twistie) {
-	case 1:
-		if (NETDRV_R16 (CSCR) & CSCR_LinkOKBit) {
-			/* We have link beat, let us tune the twister. */
-			NETDRV_W16 (CSCR, CSCR_LinkDownOffCmd);
-			tp->twistie = 2;	/* Change to state 2. */
-			next_tick = HZ / 10;
-		} else {
-			/* Just put in some reasonable defaults for when beat returns. */
-			NETDRV_W16 (CSCR, CSCR_LinkDownCmd);
-			NETDRV_W32 (FIFOTMS, 0x20);	/* Turn on cable test mode. */
-			NETDRV_W32 (PARA78, PARA78_default);
-			NETDRV_W32 (PARA7c, PARA7c_default);
-			tp->twistie = 0;	/* Bail from future actions. */
-		}
-		break;
-	case 2:
-		/* Read how long it took to hear the echo. */
-		linkcase = NETDRV_R16 (CSCR) & CSCR_LinkStatusBits;
-		if (linkcase == 0x7000)
-			tp->twist_row = 3;
-		else if (linkcase == 0x3000)
-			tp->twist_row = 2;
-		else if (linkcase == 0x1000)
-			tp->twist_row = 1;
-		else
-			tp->twist_row = 0;
-		tp->twist_col = 0;
-		tp->twistie = 3;	/* Change to state 2. */
-		next_tick = HZ / 10;
-		break;
-	case 3:
-		/* Put out four tuning parameters, one per 100msec. */
-		if (tp->twist_col == 0)
-			NETDRV_W16 (FIFOTMS, 0);
-		NETDRV_W32 (PARA7c, param[(int) tp->twist_row]
-			 [(int) tp->twist_col]);
-		next_tick = HZ / 10;
-		if (++tp->twist_col >= 4) {
-			/* For short cables we are done.
-			   For long cables (row == 3) check for mistune. */
-			tp->twistie =
-			    (tp->twist_row == 3) ? 4 : 0;
-		}
-		break;
-	case 4:
-		/* Special case for long cables: check for mistune. */
-		if ((NETDRV_R16 (CSCR) &
-		     CSCR_LinkStatusBits) == 0x7000) {
-			tp->twistie = 0;
-			break;
-		} else {
-			NETDRV_W32 (PARA7c, 0xfb38de03);
-			tp->twistie = 5;
-			next_tick = HZ / 10;
-		}
-		break;
-	case 5:
-		/* Retune for shorter cable (column 2). */
-		NETDRV_W32 (FIFOTMS, 0x20);
-		NETDRV_W32 (PARA78, PARA78_default);
-		NETDRV_W32 (PARA7c, PARA7c_default);
-		NETDRV_W32 (FIFOTMS, 0x00);
-		tp->twist_row = 2;
-		tp->twist_col = 0;
-		tp->twistie = 3;
-		next_tick = HZ / 10;
-		break;
-
-	default:
-		/* do nothing */
-		break;
-	}
-
-	DPRINTK ("EXIT\n");
-}
-#endif /* NETDRV_TUNE_TWISTER */
-
-
 static void netdrv_timer (unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int next_tick = 60 * HZ;
 	int mii_reg5;
@@ -1407,8 +1246,6 @@
 		}
 	}
 
-	netdrv_tune_twister (dev, tp);
-
 	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
 		 dev->name, NETDRV_R16 (NWayLPAR));
 	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
@@ -1451,7 +1288,7 @@
 
 static void netdrv_tx_timeout (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int i;
 	u8 tmp8;
@@ -1498,7 +1335,7 @@
 
 static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int entry;
 
@@ -1839,7 +1676,7 @@
 			       struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	int boguscnt = max_interrupt_work;
 	void *ioaddr = tp->mmio_addr;
 	int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
@@ -1853,31 +1690,8 @@
 		if (status == 0xFFFF)
 			break;
 
-		/* Acknowledge all of the current interrupt sources ASAP, but
-		   an first get an additional status bit from CSCR. */
-		if (status & RxUnderrun)
-			link_changed = NETDRV_R16 (CSCR) & CSCR_LinkChangeBit;
-
-		/* E. Gill */
-		/* In case of an RxFIFOOver we must also clear the RxOverflow
-		   bit to avoid dropping frames for ever. Believe me, I got a
-		   lot of troubles copying huge data (approximately 2 RxFIFOOver
-		   errors per 1GB data transfer).
-		   The following is written in the 'p-guide.pdf' file (RTL8139(A/B)
-		   Programming guide V0.1, from 1999/1/15) on page 9 from REALTEC.
-		   -----------------------------------------------------------
-		   2. RxFIFOOvw handling:
-		     When RxFIFOOvw occurs, all incoming packets are discarded.
-		     Clear ISR(RxFIFOOvw) doesn't dismiss RxFIFOOvw event. To
-		     dismiss RxFIFOOvw event, the ISR(RxBufOvw) must be written
-		     with a '1'.
-		   -----------------------------------------------------------
-		   Unfortunately I was not able to find any reason for the
-		   RxFIFOOver error (I got the feeling this depends on the
-		   CPU speed, lower CPU speed --> more errors).
-		   After clearing the RxOverflow bit the transfer of the
-		   packet was repeated and all data are error free transfered */
-		NETDRV_W16_F (IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
+		/* Acknowledge all of the current interrupt sources ASAP */
+		NETDRV_W16_F (IntrStatus, status);
 
 		DPRINTK ("%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
 				dev->name, status,
@@ -1922,7 +1736,7 @@
 
 static int netdrv_close (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
@@ -1964,7 +1778,7 @@
 	/* Green! Put the chip in low-power mode. */
 	NETDRV_W8 (Cfg9346, Cfg9346_Unlock);
 	NETDRV_W8 (Config1, 0x03);
-	NETDRV_W8 (HltClk, 'H');	/* 'R' would leave the clock running. */
+	NETDRV_W8 (Cfg9346, Cfg9346_Lock);
 
 	DPRINTK ("EXIT\n");
 	return 0;
@@ -1973,7 +1787,7 @@
 
 static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	u16 *data = (u16 *) & rq->ifr_data;
 	unsigned long flags;
 	int rc = 0;
@@ -2014,7 +1828,7 @@
 
 static struct net_device_stats *netdrv_get_stats (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 
 	DPRINTK ("ENTER\n");
@@ -2062,7 +1876,7 @@
 
 static void netdrv_set_rx_mode (struct net_device *dev)
 {
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
@@ -2117,11 +1931,13 @@
 
 static void netdrv_suspend (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
-	struct netdrv_private *tp = (struct netdrv_private *) dev->priv;
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct netdrv_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
+	if (!netif_running(dev))
+		return;
 	netif_device_detach (dev);
 
 	spin_lock_irqsave (&tp->lock, flags);
@@ -2142,8 +1958,10 @@
 
 static void netdrv_resume (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata (pdev);
 
+	if (!netif_running(dev))
+		return;
 	pci_power_on (pdev);
 	netif_device_attach (dev);
 	netdrv_hw_start (dev);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/3c574_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/3c574_cs.c	Fri Mar  2 11:02:15 2001
@@ -1166,7 +1166,9 @@
 
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
+				dev->last_rx = jiffies;
 				lp->stats.rx_packets++;
+				lp->stats.rx_bytes += pkt_len;
 			} else {
 				DEBUG(1, "%s: couldn't allocate a sk_buff of"
 					  " size %d.\n", dev->name, pkt_len);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/3c589_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/3c589_cs.c	Fri Mar  2 11:02:15 2001
@@ -4,7 +4,7 @@
     
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    3c589_cs.c 1.154 2000/09/30 17:39:04
+    3c589_cs.c 1.156 2001/02/07 00:19:41
 
     The network driver code is based on Donald Becker's 3c589 code:
     
@@ -117,7 +117,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"3c589_cs.c 1.154 2000/09/30 17:39:04 (David Hinds)";
+"3c589_cs.c 1.156 2001/02/07 00:19:41 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -993,8 +993,9 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
-		lp->stats.rx_bytes += skb->len;
+		lp->stats.rx_bytes += pkt_len;
 	    } else {
 		DEBUG(1, "%s: couldn't allocate a sk_buff of"
 		      " size %d.\n", dev->name, pkt_len);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.4.2/linux/drivers/net/pcmcia/Config.in	Sat Nov 11 18:56:58 2000
+++ linux/drivers/net/pcmcia/Config.in	Fri Mar 23 11:47:23 2001
@@ -26,6 +26,7 @@
    bool '  Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
    if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then
       dep_tristate '    Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
+      dep_tristate '    Hermes (AT&T/Lucent/Orinoco/3com) wireless support' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA
       dep_tristate '    Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
       dep_tristate '    AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
       dep_tristate '    Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.4.2/linux/drivers/net/pcmcia/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/pcmcia/Makefile	Fri Mar 23 11:47:23 2001
@@ -25,6 +25,7 @@
 obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o
 
 # 16-bit wireless client drivers
+obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o hermes.o
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
 obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
 obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/aironet4500_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/aironet4500_cs.c	Tue Mar 20 12:05:00 2001
@@ -177,8 +177,14 @@
 
 	/* Create the PC card device object. */
 	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-	memset(link, 0, sizeof(struct dev_link_t));
+	if (!link)
+		return NULL;
 	link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL);
+	if (!link->dev) {
+		kfree(link);
+		return NULL;
+	}
+	memset(link, 0, sizeof(struct dev_link_t));
 	memset(link->dev, 0, sizeof(struct dev_node_t));
 
 	link->release.function = &awc_release;
@@ -199,7 +205,6 @@
 	/* Create the network device object. */
 
 	dev = kmalloc(sizeof(struct net_device ), GFP_KERNEL);
-	memset(dev,0,sizeof(struct net_device));
 //	dev =  init_etherdev(0, sizeof(struct awc_private) );
 	if (!dev ) {
 		printk(KERN_CRIT "out of mem on dev alloc \n");
@@ -207,6 +212,7 @@
 		kfree(link);
 		return NULL;
 	};
+	memset(dev,0,sizeof(struct net_device));
 	dev->priv = kmalloc(sizeof(struct awc_private), GFP_KERNEL);
 	if (!dev->priv ) {printk(KERN_CRIT "out of mem on dev priv alloc \n"); return NULL;};
 	memset(dev->priv,0,sizeof(struct awc_private));
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/fmvj18x_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/fmvj18x_cs.c	Fri Mar  2 11:02:15 2001
@@ -1,5 +1,5 @@
 /*======================================================================
-    fmvj18x_cs.c,v 2.0 2000/10/01  03:13:53 root Exp
+    fmvj18x_cs.c 2.2 2001/01/07
 
     A fmvj18x (and its compatibles) PCMCIA client driver
 
@@ -19,7 +19,7 @@
     Director, National Security Agency.
     
     This software may be used and distributed according to the terms
-    of the GNU Public License, incorporated herein by reference.
+    of the GNU General Public License, incorporated herein by reference.
     
     The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
     Center of Excellence in Space Data and Information Sciences
@@ -87,8 +87,7 @@
    driver version infomation 
  */
 #ifdef PCMCIA_DEBUG
-static char *version =
- "fmvj18x_cs.c,v 2.0 2000/10/01 03:13:53 root Exp";
+static char *version = "fmvj18x_cs.c 2.2 2001/01/07";
 #endif
 
 /*====================================================================*/
@@ -96,6 +95,7 @@
     PCMCIA event handlers
  */
 static void fmvj18x_config(dev_link_t *link);
+static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id);
 static void fmvj18x_release(u_long arg);
 static int fmvj18x_event(event_t event, int priority,
 			  event_callback_args_t *args);
@@ -103,7 +103,7 @@
 static void fmvj18x_detach(dev_link_t *);
 
 /*
-    LAN controler(MBH86960A) specific routines
+    LAN controller(MBH86960A) specific routines
  */
 static int fjn_config(struct net_device *dev, struct ifmap *map);
 static int fjn_open(struct net_device *dev);
@@ -122,7 +122,9 @@
 /*
     card type
  */
-typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN } cardtype_t;
+typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, 
+	       XXX10304
+} cardtype_t;
 
 #define MANFID_UNGERMANN 0x02c0
 
@@ -223,8 +225,8 @@
 #define RECV_ALL             0x03 /* (RX_MODE) */
 #define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
 #define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
-#define CONFIG0_RST          0xda /* Data Link Controler off (CONFIG_0) */
-#define CONFIG0_RST_1        0xde /* Data Link Controler off (CONFIG_0) */
+#define CONFIG0_RST          0xda /* Data Link Controller off (CONFIG_0) */
+#define CONFIG0_RST_1        0xde /* Data Link Controller off (CONFIG_0) */
 #define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
 #define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
 #define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
@@ -235,8 +237,8 @@
 #define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
 #define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
 #define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
-#define INTR_OFF             0x0d /* LAN controler ignores interrupts */
-#define INTR_ON              0x1d /* LAN controler will catch interrupts */
+#define INTR_OFF             0x0d /* LAN controller ignores interrupts */
+#define INTR_ON              0x1d /* LAN controller will catch interrupts */
 
 #define TX_TIMEOUT		((400*HZ)/1000)
 
@@ -321,8 +323,10 @@
     ether_setup(dev);
     dev->open = &fjn_open;
     dev->stop = &fjn_close;
+#ifdef HAVE_TX_TIMEOUT
     dev->tx_timeout = fjn_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
+#endif
     
     /* Register with Card Services */
     link->next = dev_list;
@@ -438,6 +442,12 @@
 	switch (le16_to_cpu(buf[0])) {
 	case MANFID_TDK:
 	    cardtype = TDK;
+	    if (le16_to_cpu(buf[1]) == PRODID_TDK_CF010) {
+		cs_status_t status;
+		CardServices(GetStatus, handle, &status);
+		if (status.CardState & CS_EVENT_3VCARD)
+		    link->conf.Vcc = 33; /* inserted in 3.3V slot */
+	    }
 	    break;
 	case MANFID_CONTEC:
 	    cardtype = CONTEC;
@@ -461,6 +471,15 @@
 	else
 	    buf[0] = 0xffff;
 	switch (le16_to_cpu(buf[0])) {
+	case MANFID_FUJITSU:
+	    if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304) {
+		cardtype = XXX10304;    /* MBH10304 with buggy CIS */
+	        link->conf.ConfigIndex = 0x20;
+	    } else {
+		cardtype = MBH10302;
+		link->conf.ConfigIndex = 1;
+	    }
+	    break;
 	case MANFID_UNGERMANN:
 	    cardtype = UNGERMANN;
 	    /*
@@ -505,7 +524,7 @@
     else
 	outb(BANK_0, ioaddr + CONFIG_1);
 
-    /* Reset controler */
+    /* Reset controller */
     if( sram_config == 0 ) 
 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
     else
@@ -550,6 +569,19 @@
 	    dev->dev_addr[i] = inb(ioaddr + UNGERMANN_MAC_ID + i);
 	card_name = "Access/CARD";
 	break;
+    case XXX10304:
+	/* Read MACID from Buggy CIS */
+	if (fmvj18x_get_hwinfo(link, tuple.TupleData) == -1) {
+	    printk(KERN_NOTICE "fmvj18x_cs: unable to read hardware net 
+		address.");
+	    unregister_netdev(dev);
+	    goto failed;
+	}
+	for (i = 0 ; i < 6; i++) {
+	    dev->dev_addr[i] = tuple.TupleData[i];
+	}
+	card_name = "FMV-J182";
+	break;
     case MBH10302:
     default:
 	/* Read MACID from register */
@@ -580,7 +612,60 @@
     fmvj18x_release((u_long)link);
 
 } /* fmvj18x_config */
- 
+/*====================================================================*/
+
+static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id)
+{
+    win_req_t req;
+    memreq_t mem;
+    u_char *base;
+    int i, j;
+
+    /* 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);
+
+    /*
+     *  MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
+     *  22 0d xx xx xx 04 06 yy yy yy yy yy yy ff
+     *  'xx' is garbage.
+     *  'yy' is MAC address.
+    */ 
+    for (i = 0; i < 0x200; i++) {
+	if (readb(base+i*2) == 0x22) {	
+	    if (readb(base+(i-1)*2) == 0xff
+	     && readb(base+(i+5)*2) == 0x04
+	     && readb(base+(i+6)*2) == 0x06
+	     && readb(base+(i+13)*2) == 0xff) 
+		break;
+	}
+    }
+
+    if (i != 0x200) {
+	for (j = 0 ; j < 6; j++,i++) {
+	    node_id[j] = readb(base+(i+7)*2);
+	}
+    }
+
+    iounmap(base);
+    j = CardServices(ReleaseWindow, link->win);
+    if (j != CS_SUCCESS)
+	cs_error(link->handle, ReleaseWindow, j);
+    return (i != 0x200) ? 0 : -1;
+
+} /* fmvj18x_get_hwinfo */
 /*====================================================================*/
 
 static void fmvj18x_release(u_long arg)
@@ -775,7 +860,7 @@
     lp->sent = 0;
     lp->open_time = jiffies;
     sti();
-    netif_start_queue(dev);
+    netif_wake_queue(dev);
 }
 
 static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -923,7 +1008,7 @@
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
-    /* Turn on interrupts from LAN card controler */
+    /* Turn on interrupts from LAN card controller */
     if( lp->cardtype != TDK ) 
 		outb(INTR_ON, ioaddr + LAN_CTRL);
 } /* fjn_reset */
@@ -995,8 +1080,9 @@
 #endif
 
 	    netif_rx(skb);
+	    dev->last_rx = jiffies;
 	    lp->stats.rx_packets++;
-	    lp->stats.rx_bytes += skb->len;
+	    lp->stats.rx_bytes += pkt_len;
 	}
 	if (--boguscount <= 0)
 	    break;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/hermes.c linux/drivers/net/pcmcia/hermes.c
--- v2.4.2/linux/drivers/net/pcmcia/hermes.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/hermes.c	Fri Mar 23 11:47:23 2001
@@ -0,0 +1,498 @@
+/* hermes.c
+ *
+ * Driver core for the "Hermes" wireless MAC controller, as used in
+ * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
+ * work on the hfa3841 and hfa3842 MAC controller chips used in the
+ * Prism I & II chipsets.
+ *
+ * This is not a complete driver, just low-level access routines for
+ * the MAC controller itself.
+ *
+ * Based on the prism2 driver from Absolute Value Systems' linux-wlan
+ * project, the Linux wvlan_cs driver, Lucent's HCF-Light
+ * (wvlan_hcf.c) library, and the NetBSD wireless driver.
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ * 
+ * This file distributed under the GPL, version 2.
+ */
+
+static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>";
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <asm/io.h>
+#include <linux/ptrace.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/errno.h>
+
+#include "hermes.h"
+
+#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
+#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
+#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */
+#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
+#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
+#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */
+
+#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
+#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
+
+/*
+ * Debugging helpers
+ */
+
+#undef HERMES_DEBUG
+#ifdef HERMES_DEBUG
+
+#include <stdarg.h>
+
+#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \
+			printk(#stuff);} while (0)
+
+#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff)
+
+#else /* ! HERMES_DEBUG */
+
+#define DEBUG(lvl, stuff...) do { } while (0)
+
+#endif /* ! HERMES_DEBUG */
+
+/*
+ * Prototypes
+ */
+
+static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0);
+
+/*
+ * Internal inline functions
+ */
+
+/*
+ * Internal functions
+ */
+
+/* Issue a command to the chip. Waiting for it to complete is the caller's
+   problem.
+
+   Returns -EBUSY if the command register is busy, 0 on success.
+
+   Callable from any context.
+*/
+static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0)
+{
+	uint16_t reg;
+/*  	unsigned long k = CMD_BUSY_TIMEOUT; */
+
+	/* First check that the command register is not busy */
+	reg = hermes_read_regn(hw, CMD);
+	if (reg & HERMES_CMD_BUSY) {
+		return -EBUSY;
+	}
+
+	hermes_write_regn(hw, PARAM2, 0);
+	hermes_write_regn(hw, PARAM1, 0);
+	hermes_write_regn(hw, PARAM0, param0);
+	hermes_write_regn(hw, CMD, cmd);
+	
+	return 0;
+}
+
+/*
+ * Function definitions
+ */
+
+void hermes_struct_init(hermes_t *hw, ushort io)
+{
+	hw->iobase = io;
+	hw->inten = 0x0;
+}
+
+int hermes_reset(hermes_t *hw)
+{
+	uint16_t status, reg;
+	int err = 0;
+	int k;
+
+	/* We don't want to be interrupted while resetting the chipset */
+	hw->inten = 0x0;
+	hermes_write_regn(hw, INTEN, 0);
+	hermes_write_regn(hw, EVACK, 0xffff);
+
+	/* Because we hope we can reset the card even if it gets into
+	   a stupid state, we actually wait to see if the command
+	   register will unbusy itself */
+	k = CMD_BUSY_TIMEOUT;
+	reg = hermes_read_regn(hw, CMD);
+	while (k && (reg & HERMES_CMD_BUSY)) {
+		if (reg == 0xffff) /* Special case - the card has probably been removed,
+				      so don't wait for the timeout */
+			return -ENODEV;
+
+		k--;
+		udelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+	
+	/* No need to explicitly handle the timeout - hermes_issue_cmd() will
+	   probably return -EBUSY */
+
+	/* We don't use hermes_docmd_wait here, because the reset wipes
+	   the magic constant in SWSUPPORT0 away, and it gets confused */
+	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
+	if (err)
+		return err;
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = CMD_INIT_TIMEOUT;
+	while ( (! (reg & HERMES_EV_CMD)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+
+	DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k);
+
+	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+
+	if (! hermes_present(hw)) {
+		DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
+		       hw->iobase);
+		err = -ENODEV;
+		goto out;
+	}
+		
+	if (! (reg & HERMES_EV_CMD)) {
+		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n",
+		       hw->iobase, reg);
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	status = hermes_read_regn(hw, STATUS);
+
+	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+	err = status & HERMES_STATUS_RESULT;
+
+ out:
+	return err;
+}
+
+/* Issue a command to the chip, and (busy!) wait for it to
+ * complete.
+ *
+ * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
+ *
+ * Callable from any context, but locking is your problem. */
+int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp)
+{
+	int err;
+	int k;
+	uint16_t reg;
+
+	err = hermes_issue_cmd(hw, cmd, parm0);
+	if (err) {
+		if (! hermes_present(hw)) {
+			printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n",
+			       hw->iobase);
+			err = -ENODEV;
+		} else 
+			printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n",
+			       hw->iobase);
+		goto out;
+	}
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = CMD_COMPL_TIMEOUT;
+	while ( (! (reg & HERMES_EV_CMD)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+
+	if (! hermes_present(hw)) {
+		printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n",
+		       hw->iobase);
+		err = -ENODEV;
+		goto out;
+	}
+		
+	if (! (reg & HERMES_EV_CMD)) {
+		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n",
+		       hw->iobase);
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	resp->status = hermes_read_regn(hw, STATUS);
+	resp->resp0 = hermes_read_regn(hw, RESP0);
+	resp->resp1 = hermes_read_regn(hw, RESP1);
+	resp->resp2 = hermes_read_regn(hw, RESP2);
+
+	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+	err = resp->status & HERMES_STATUS_RESULT;
+
+ out:
+	return err;
+}
+
+int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid)
+{
+	int err = 0;
+	hermes_response_t resp;
+	int k;
+	uint16_t reg;
+	
+	if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
+		return -EINVAL;
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp);
+	if (err)
+		return err;
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = ALLOC_COMPL_TIMEOUT;
+	while ( (! (reg & HERMES_EV_ALLOC)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+	
+	if (! hermes_present(hw)) {
+		printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n",
+		       hw->iobase);
+		return -ENODEV;
+	}
+		
+	if (! (reg & HERMES_EV_ALLOC)) {
+		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n",
+		       hw->iobase);
+		return -ETIMEDOUT;
+	}
+
+	*fid = hermes_read_regn(hw, ALLOCFID);
+	hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
+	
+	return 0;
+}
+
+/* Set up a BAP to read a particular chunk of data from card's internal buffer.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
+ * from firmware
+ *
+ * Callable from any context */
+static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
+{
+	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
+	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
+	int k;
+	int l = BAP_ERROR_RETRY;
+	uint16_t reg;
+
+	/* Paranoia.. */
+	if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
+		return -EINVAL;
+
+	k = BAP_BUSY_TIMEOUT;
+	reg = hermes_read_reg(hw, oreg);
+
+	if (reg & HERMES_OFFSET_BUSY)
+		return -EBUSY;
+
+	/* Now we actually set up the transfer */
+ retry:
+	hermes_write_reg(hw, sreg, id);
+	hermes_write_reg(hw, oreg, offset);
+
+	/* Wait for the BAP to be ready */
+	k = BAP_BUSY_TIMEOUT;
+	reg = hermes_read_reg(hw, oreg);
+	while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
+		k--;
+		udelay(1);
+		reg = hermes_read_reg(hw, oreg);
+	}
+
+	if (reg & HERMES_OFFSET_BUSY)
+		return -ETIMEDOUT;
+
+	/* For some reason, seeking the BAP seems to randomly fail somewhere
+	   (firmware bug?). We retry a few times before giving up. */
+	if (reg & HERMES_OFFSET_ERR) {
+		if (l--) {
+			udelay(1);
+			goto retry;
+		} else
+			return -EIO;
+	}
+
+	return 0;
+}
+
+/* Read a block of data from the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem.  len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ */
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
+		     uint16_t id, uint16_t offset)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err = 0;
+
+	if (len % 2)
+		return -EINVAL;
+
+	err = hermes_bap_seek(hw, bap, id, offset);
+	if (err)
+		goto out;
+
+	/* Actually do the transfer */
+	hermes_read_data(hw, dreg, buf, len/2);
+
+ out:
+	return err;
+}
+
+/* Write a block of data to the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem. len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ */
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
+		      uint16_t id, uint16_t offset)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err = 0;
+
+	if (len % 2)
+		return -EINVAL;
+
+	err = hermes_bap_seek(hw, bap, id, offset);
+	if (err)
+		goto out;
+	
+	/* Actually do the transfer */
+	hermes_write_data(hw, dreg, buf, len/2);
+
+ out:	
+	return err;
+}
+
+/* Read a Length-Type-Value record from the card.
+ *
+ * If length is NULL, we ignore the length read from the card, and
+ * read the entire buffer regardless. This is useful because some of
+ * the configuration records appear to have incorrect lengths in
+ * practice.
+ *
+ * Callable from user or bh context.  */
+int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
+		    uint16_t *length, void *buf)
+{
+	int err = 0;
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	uint16_t rlength, rtype;
+	hermes_response_t resp;
+	int count;
+
+	if (buflen % 2)
+		return -EINVAL;
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp);
+	if (err)
+		goto out;
+
+	err = hermes_bap_seek(hw, bap, rid, 0);
+	if (err)
+		goto out;
+
+	rlength = hermes_read_reg(hw, dreg);
+	rtype = hermes_read_reg(hw, dreg);
+
+	if (length)
+		*length = rlength;
+
+	if (rtype != rid)
+		printk(KERN_WARNING "hermes_read_ltv(): rid  (0x%04x) does "
+		       "not match type (0x%04x)\n", rid, rtype);
+	if (HERMES_RECLEN_TO_BYTES(rlength) > buflen)
+		printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. "
+		       "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
+		       HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength);
+	
+	/* For now we always read the whole buffer, the
+	   lengths in the records seem to be wrong, frequently */
+	count = buflen / 2;
+
+#if 0
+	if (length)
+		count = (MIN(buflen, rlength) + 1) / 2;
+	else {
+		count = buflen / 2;
+		if (rlength != buflen)
+			printk(KERN_WARNING "hermes_read_ltv(): Incorrect \
+record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid);
+	}
+#endif
+	hermes_read_data(hw, dreg, buf, count);
+
+ out:
+	return err;
+}
+
+int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, 
+		     uint16_t length, const void *value)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err = 0;
+	hermes_response_t resp;
+	int count;
+	
+	DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n",
+	      bap, rid, length, * ((uint16_t *)value));
+
+	err = hermes_bap_seek(hw, bap, rid, 0);
+	if (err)
+		goto out;
+
+	hermes_write_reg(hw, dreg, length);
+	hermes_write_reg(hw, dreg, rid);
+
+	count = length - 1;
+
+	hermes_write_data(hw, dreg, value, count);
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
+				rid, &resp);
+
+ out:
+	return err;
+}
+
+EXPORT_SYMBOL(hermes_struct_init);
+EXPORT_SYMBOL(hermes_reset);
+EXPORT_SYMBOL(hermes_docmd_wait);
+EXPORT_SYMBOL(hermes_allocate);
+
+EXPORT_SYMBOL(hermes_bap_pread);
+EXPORT_SYMBOL(hermes_bap_pwrite);
+EXPORT_SYMBOL(hermes_read_ltv);
+EXPORT_SYMBOL(hermes_write_ltv);
+
+static int __init init_hermes(void)
+{
+	printk(KERN_INFO "%s\n", version);
+
+	return 0;
+}
+
+module_init(init_hermes);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/hermes.h linux/drivers/net/pcmcia/hermes.h
--- v2.4.2/linux/drivers/net/pcmcia/hermes.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/hermes.h	Fri Mar 23 11:47:23 2001
@@ -0,0 +1,391 @@
+/* hermes.h
+ *
+ * Driver core for the "Hermes" wireless MAC controller, as used in
+ * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
+ * work on the hfa3841 and hfa3842 MAC controller chips used in the
+ * Prism I & II chipsets.
+ *
+ * This is not a complete driver, just low-level access routines for
+ * the MAC controller itself.
+ *
+ * Based on the prism2 driver from Absolute Value Systems' linux-wlan
+ * project, the Linux wvlan_cs driver, Lucent's HCF-Light
+ * (wvlan_hcf.c) library, and the NetBSD wireless driver.
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ *
+ * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ *
+ * This file distributed under the GPL, version 2.
+ */
+
+#ifndef _HERMES_H
+#define _HERMES_H
+
+/* Notes on locking:
+ *
+ * As a module of low level hardware access routines, there is no
+ * locking. Users of this module should ensure that they serialize
+ * access to the hermes_t structure, and to the hardware
+*/
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+
+/*
+ * Limits and constants
+ */
+#define		HERMES_ALLOC_LEN_MIN		((uint16_t)4)
+#define		HERMES_ALLOC_LEN_MAX		((uint16_t)2400)
+#define		HERMES_LTV_LEN_MAX		(34)
+#define		HERMES_BAP_DATALEN_MAX		((uint16_t)4096)
+#define		HERMES_BAP_OFFSET_MAX		((uint16_t)4096)
+#define		HERMES_PORTID_MAX		((uint16_t)7)
+#define		HERMES_NUMPORTS_MAX		((uint16_t)(HERMES_PORTID_MAX+1))
+#define		HERMES_PDR_LEN_MAX		((uint16_t)260)	/* in bytes, from EK */
+#define		HERMES_PDA_RECS_MAX		((uint16_t)200)	/* a guess */
+#define		HERMES_PDA_LEN_MAX		((uint16_t)1024)	/* in bytes, from EK */
+#define		HERMES_SCANRESULT_MAX		((uint16_t)35)
+#define		HERMES_CHINFORESULT_MAX		((uint16_t)8)
+#define		HERMES_FRAME_LEN_MAX		(2304)
+#define		HERMES_MAX_MULTICAST		(16)
+#define		HERMES_MAGIC			(0x7d1f)
+
+/*
+ * Hermes register offsets
+ */
+#define		HERMES_CMD			(0x00)
+#define		HERMES_PARAM0			(0x02)
+#define		HERMES_PARAM1			(0x04)
+#define		HERMES_PARAM2			(0x06)
+#define		HERMES_STATUS			(0x08)
+#define		HERMES_RESP0			(0x0A)
+#define		HERMES_RESP1			(0x0C)
+#define		HERMES_RESP2			(0x0E)
+#define		HERMES_INFOFID			(0x10)
+#define		HERMES_RXFID			(0x20)
+#define		HERMES_ALLOCFID			(0x22)
+#define		HERMES_TXCOMPLFID		(0x24)
+#define		HERMES_SELECT0			(0x18)
+#define		HERMES_OFFSET0			(0x1C)
+#define		HERMES_DATA0			(0x36)
+#define		HERMES_SELECT1			(0x1A)
+#define		HERMES_OFFSET1			(0x1E)
+#define		HERMES_DATA1			(0x38)
+#define		HERMES_EVSTAT			(0x30)
+#define		HERMES_INTEN			(0x32)
+#define		HERMES_EVACK			(0x34)
+#define		HERMES_CONTROL			(0x14)
+#define		HERMES_SWSUPPORT0		(0x28)
+#define		HERMES_SWSUPPORT1		(0x2A)
+#define		HERMES_SWSUPPORT2		(0x2C)
+#define		HERMES_AUXPAGE			(0x3A)
+#define		HERMES_AUXOFFSET		(0x3C)
+#define		HERMES_AUXDATA			(0x3E)
+
+/*
+ * CMD register bitmasks
+ */
+#define		HERMES_CMD_BUSY			((uint16_t)0x8000)
+#define		HERMES_CMD_AINFO		((uint16_t)0x7f00)
+#define		HERMES_CMD_MACPORT		((uint16_t)0x0700)
+#define		HERMES_CMD_RECL			((uint16_t)0x0100)
+#define		HERMES_CMD_WRITE		((uint16_t)0x0100)
+#define		HERMES_CMD_PROGMODE		((uint16_t)0x0300)
+#define		HERMES_CMD_CMDCODE		((uint16_t)0x003f)
+
+/*
+ * STATUS register bitmasks
+ */
+#define		HERMES_STATUS_RESULT		((uint16_t)0x7f00)
+#define		HERMES_STATUS_CMDCODE		((uint16_t)0x003f)
+
+/*
+ * OFFSET refister bitmasks
+ */
+#define		HERMES_OFFSET_BUSY		((uint16_t)0x8000)
+#define		HERMES_OFFSET_ERR		((uint16_t)0x4000)
+#define		HERMES_OFFSET_DATAOFF		((uint16_t)0x0ffe)
+
+/*
+ * Event register bitmasks (INTEN, EVSTAT, EVACK)
+ */
+#define		HERMES_EV_TICK			((uint16_t)0x8000)
+#define		HERMES_EV_WTERR			((uint16_t)0x4000)
+#define		HERMES_EV_INFDROP		((uint16_t)0x2000)
+#define		HERMES_EV_INFO			((uint16_t)0x0080)
+#define		HERMES_EV_DTIM			((uint16_t)0x0020)
+#define		HERMES_EV_CMD			((uint16_t)0x0010)
+#define		HERMES_EV_ALLOC			((uint16_t)0x0008)
+#define		HERMES_EV_TXEXC			((uint16_t)0x0004)
+#define		HERMES_EV_TX			((uint16_t)0x0002)
+#define		HERMES_EV_RX			((uint16_t)0x0001)
+
+/*
+ * Command codes
+ */
+/*--- Controller Commands --------------------------*/
+#define		HERMES_CMD_INIT			((uint16_t)0x00)
+#define		HERMES_CMD_ENABLE		((uint16_t)0x01)
+#define		HERMES_CMD_DISABLE		((uint16_t)0x02)
+#define		HERMES_CMD_DIAG			((uint16_t)0x03)
+
+/*--- Buffer Mgmt Commands --------------------------*/
+#define		HERMES_CMD_ALLOC		((uint16_t)0x0A)
+#define		HERMES_CMD_TX			((uint16_t)0x0B)
+#define		HERMES_CMD_CLRPRST		((uint16_t)0x12)
+
+/*--- Regulate Commands --------------------------*/
+#define		HERMES_CMD_NOTIFY		((uint16_t)0x10)
+#define		HERMES_CMD_INQ			((uint16_t)0x11)
+
+/*--- Configure Commands --------------------------*/
+#define		HERMES_CMD_ACCESS		((uint16_t)0x21)
+#define		HERMES_CMD_DOWNLD		((uint16_t)0x22)
+
+/*--- Debugging Commands -----------------------------*/
+#define 	HERMES_CMD_MONITOR		((uint16_t)(0x38))
+#define		HERMES_MONITOR_ENABLE		((uint16_t)(0x0b))
+#define		HERMES_MONITOR_DISABLE		((uint16_t)(0x0f))
+
+/*
+ * Configuration RIDs
+ */
+
+#define		HERMES_RID_CNF_PORTTYPE		((uint16_t)0xfc00)
+#define		HERMES_RID_CNF_MACADDR		((uint16_t)0xfc01)
+#define		HERMES_RID_CNF_DESIRED_SSID	((uint16_t)0xfc02)
+#define		HERMES_RID_CNF_CHANNEL		((uint16_t)0xfc03)
+#define		HERMES_RID_CNF_OWN_SSID		((uint16_t)0xfc04)
+#define		HERMES_RID_CNF_SYSTEM_SCALE	((uint16_t)0xfc06)
+#define		HERMES_RID_CNF_MAX_DATA_LEN	((uint16_t)0xfc07)
+#define		HERMES_RID_CNF_PM_ENABLE	((uint16_t)0xfc09)
+#define		HERMES_RID_CNF_PM_MCAST_RX	((uint16_t)0xfc0b)
+#define		HERMES_RID_CNF_PM_PERIOD	((uint16_t)0xfc0c)
+#define		HERMES_RID_CNF_NICKNAME		((uint16_t)0xfc0e)
+#define		HERMES_RID_CNF_WEP_ON		((uint16_t)0xfc20)
+#define		HERMES_RID_CNF_MWO_ROBUST	((uint16_t)0xfc25)
+#define		HERMES_RID_CNF_PRISM2_WEP_ON	((uint16_t)0xfc28)
+#define		HERMES_RID_CNF_MULTICAST_LIST	((uint16_t)0xfc80)
+#define		HERMES_RID_CNF_CREATEIBSS	((uint16_t)0xfc81)
+#define		HERMES_RID_CNF_FRAG_THRESH	((uint16_t)0xfc82)
+#define		HERMES_RID_CNF_RTS_THRESH	((uint16_t)0xfc83)
+#define		HERMES_RID_CNF_TX_RATE_CTRL	((uint16_t)0xfc84)
+#define		HERMES_RID_CNF_PROMISCUOUS	((uint16_t)0xfc85)
+#define		HERMES_RID_CNF_KEYS		((uint16_t)0xfcb0)
+#define		HERMES_RID_CNF_TX_KEY		((uint16_t)0xfcb1)
+#define		HERMES_RID_CNF_TICKTIME		((uint16_t)0xfce0)
+
+#define		HERMES_RID_CNF_PRISM2_TX_KEY	((uint16_t)0xfc23)
+#define		HERMES_RID_CNF_PRISM2_KEY0	((uint16_t)0xfc24)
+#define		HERMES_RID_CNF_PRISM2_KEY1	((uint16_t)0xfc25)
+#define		HERMES_RID_CNF_PRISM2_KEY2	((uint16_t)0xfc26)
+#define		HERMES_RID_CNF_PRISM2_KEY3	((uint16_t)0xfc27)
+
+/*
+ * Information RIDs
+ */
+#define		HERMES_RID_CHANNEL_LIST		((uint16_t)0xfd10)
+#define		HERMES_RID_STAIDENTITY		((uint16_t)0xfd20)
+#define		HERMES_RID_CURRENT_SSID		((uint16_t)0xfd41)
+#define		HERMES_RID_CURRENT_BSSID	((uint16_t)0xfd42)
+#define		HERMES_RID_COMMSQUALITY		((uint16_t)0xfd43)
+#define 	HERMES_RID_CURRENT_TX_RATE	((uint16_t)0xfd44)
+#define		HERMES_RID_WEP_AVAIL		((uint16_t)0xfd4f)
+#define		HERMES_RID_CURRENT_CHANNEL	((uint16_t)0xfdc1)
+#define		HERMES_RID_DATARATES		((uint16_t)0xfdc6)
+
+/*
+ * Frame structures and constants
+ */
+
+typedef struct hermes_frame_desc {
+	/* Hermes - i.e. little-endian byte-order */
+	uint16_t status; /* 0x0 */
+	uint16_t res1, res2; /* 0x2, 0x4 */
+	uint16_t q_info; /* 0x6 */
+	uint16_t res3, res4; /* 0x8, 0xA */
+	uint16_t tx_ctl; /* 0xC */
+} __attribute__ ((packed)) hermes_frame_desc_t;
+
+#define		HERMES_RXSTAT_ERR		((uint16_t)0x0003)
+#define		HERMES_RXSTAT_MACPORT		((uint16_t)0x0700)
+#define		HERMES_RXSTAT_MSGTYPE		((uint16_t)0xE000)
+
+#define		HERMES_RXSTAT_BADCRC		((uint16_t)0x0001)
+#define		HERMES_RXSTAT_UNDECRYPTABLE	((uint16_t)0x0002)
+
+/* RFC-1042 encoded frame */
+#define		HERMES_RXSTAT_1042		((uint16_t)0x2000)
+/* Bridge-tunnel encoded frame */
+#define		HERMES_RXSTAT_TUNNEL		((uint16_t)0x4000)
+/* Wavelan-II Management Protocol frame */
+#define		HERMES_RXSTAT_WMP		((uint16_t)0x6000)
+
+#ifdef __KERNEL__
+
+/* Basic control structure */
+typedef struct hermes {
+	uint iobase;
+
+	uint16_t inten; /* Which interrupts should be enabled? */
+} hermes_t;
+
+typedef struct hermes_response {
+	uint16_t status, resp0, resp1, resp2;
+} hermes_response_t;
+
+/* Firmware information structure */
+typedef struct hermes_identity {
+	uint16_t id, vendor, major, minor;
+} __attribute__ ((packed)) hermes_identity_t;
+
+/* "ID" structure - used for ESSID and station nickname */
+typedef struct hermes_id {
+	uint16_t len;
+	uint16_t val[16];
+} __attribute__ ((packed)) hermes_id_t;
+
+typedef struct hermes_commsqual {
+	uint16_t qual, signal, noise;
+} __attribute__ ((packed)) hermes_commsqual_t;
+
+typedef struct hermes_multicast {
+	uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN];
+} __attribute__ ((packed)) hermes_multicast_t;
+
+/* Register access convenience macros */
+#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off)))
+#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off)))
+
+#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name))
+#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val)))
+
+/* Note that for the next two, the count is in 16-bit words, not bytes */
+#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count)))
+#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count)))
+
+/* Function prototypes */
+void hermes_struct_init(hermes_t *hw, ushort io);
+int hermes_reset(hermes_t *hw);
+int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp);
+int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid);
+
+
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
+		       uint16_t id, uint16_t offset);
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
+			uint16_t id, uint16_t offset);
+int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
+		    uint16_t *length, void *buf);
+int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid,
+		      uint16_t length, const void *value);
+
+/* Inline functions */
+
+static inline int hermes_present(hermes_t *hw)
+{
+	return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
+}
+
+static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events)
+{
+	hw->inten |= events;
+	hermes_write_regn(hw, INTEN, hw->inten);
+}
+
+static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events)
+{
+	hw->inten = events;
+	hermes_write_regn(hw, INTEN, events);
+}
+
+static inline int hermes_enable_port(hermes_t *hw, int port)
+{
+	hermes_response_t resp;
+
+	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
+				 0, &resp);
+}
+
+static inline int hermes_disable_port(hermes_t *hw, int port)
+{
+	hermes_response_t resp;
+
+	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 
+				 0, &resp);
+}
+
+#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 )
+#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
+
+#define HERMES_READ_RECORD(hw, bap, rid, buf) \
+	(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
+#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
+	(hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf)))
+
+static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word)
+{
+	uint16_t rec;
+	int err;
+
+	err = HERMES_READ_RECORD(hw, bap, rid, &rec);
+	*word = le16_to_cpu(rec);
+	return err;
+}
+
+static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word)
+{
+	uint16_t rec = cpu_to_le16(word);
+	return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
+}
+
+static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf)
+{
+	int err;
+
+	err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf);
+	if (err)
+		return err;
+
+	le16_to_cpus(&buf->id);
+	le16_to_cpus(&buf->vendor);
+	le16_to_cpus(&buf->major);
+	le16_to_cpus(&buf->minor);
+	
+	return 0;
+}
+
+static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf)
+{
+	int err;
+
+	err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf);
+	if (err)
+		return err;
+
+	le16_to_cpus(&buf->qual);
+	le16_to_cpus(&buf->signal);
+	le16_to_cpus(&buf->noise);
+	
+	return 0;
+}
+
+#else /* ! __KERNEL__ */
+
+/* These are provided for the benefit of userspace drivers and testing programs
+   which use ioperm() or iopl() */
+
+#define hermes_read_reg(base, off) (inw((base) + (off)))
+#define hermes_write_reg(base, off, val) (outw((val), (base) + (off)))
+
+#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name))
+#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val)))
+
+/* Note that for the next two, the count is in 16-bit words, not bytes */
+#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count)))
+#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count)))
+
+#endif /* ! __KERNEL__ */
+
+#endif  /* _HERMES_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/i82593.h linux/drivers/net/pcmcia/i82593.h
--- v2.4.2/linux/drivers/net/pcmcia/i82593.h	Wed Oct 20 21:33:12 1999
+++ linux/drivers/net/pcmcia/i82593.h	Fri Mar  2 11:02:15 2001
@@ -221,4 +221,4 @@
 
 #define I82593_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
 
-#endif _I82593_H
+#endif /* _I82593_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/netwave_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/netwave_cs.c	Fri Mar  2 11:02:15 2001
@@ -1463,16 +1463,16 @@
 	skb->protocol = eth_type_trans(skb,dev);
 	/* Queue packet for network layer */
 	netif_rx(skb);
-		
+
+	dev->last_rx = jiffies;
+	priv->stats.rx_packets++;
+	priv->stats.rx_bytes += rcvLen;
+
 	/* Got the packet, tell the adapter to skip it */
 	wait_WOC(iobase);
 	writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
 	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
 	DEBUG(3, "Packet reception ok\n");
-		
-	priv->stats.rx_packets++;
-
-	priv->stats.rx_bytes += skb->len;
     }
     return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/nmclan_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/nmclan_cs.c	Fri Mar  2 11:02:15 2001
@@ -1288,9 +1288,9 @@
 	skb->protocol = eth_type_trans(skb, dev);
 	
 	netif_rx(skb); /* Send the packet to the upper (protocol) layers. */
-
+	dev->last_rx = jiffies;
 	lp->linux_stats.rx_packets++;
-	lp->linux_stats.rx_bytes += skb->len;
+	lp->linux_stats.rx_bytes += pkt_len;
 	outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
 	continue;
       } else {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/orinoco_cs.c linux/drivers/net/pcmcia/orinoco_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/orinoco_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/orinoco_cs.c	Fri Mar 23 11:47:23 2001
@@ -0,0 +1,3562 @@
+/* dldwd_cs.c 0.01
+ *
+ * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+ * as the Lucent/Orinoco cards and the Cabletron RoamAbout. It should
+ * also be usable on Prism II based cards such as the Farallon Skyline
+ * and the 3Com AirConnect.
+ *
+ * Copyright (C) 2000 David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ *
+ * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
+ *
+ * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy@fasta.fh-dortmund.de>
+ *      http://www.fasta.fh-dortmund.de/users/andy/wvlan/
+ *
+ * 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 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.
+ */
+
+/* Notes on locking:
+ *
+ * The basic principle of operation is that everything except the
+ * interrupt handler is serialized through a single spinlock in the
+ * dldwd_priv_t structure, using dldwd_lock() and
+ * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()).
+ *
+ * The kernel's IRQ handling stuff ensures that the interrupt handler
+ * does not re-enter itself. The interrupt handler is written such
+ * that everything it does is safe without a lock: chiefly this means
+ * that the Rx path uses one of the Hermes chipset's BAPs while
+ * everything else uses the other.
+ *
+ * For the moment access to the device statistics from the interrupt
+ * handler is unsafe - we just put up with any resulting errors in the
+ * statisics. FIXME: This should probably be changed to store the
+ * stats in atomic types.
+ *
+ * EXCEPT that we don't want the irq handler running when we actually
+ * reset or shut down the card, because strange things might happen
+ * (probably the worst would be one packet of garbage, but you can't
+ * be too careful). For this we use __dldwd_stop_irqs() which will set
+ * a flag to disable the interrupt handler, and wait for any
+ * outstanding instances of the handler to complete. THIS WILL LOSE
+ * INTERRUPTS! so it shouldn't be used except for resets, when we
+ * don't care about that.*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+#include "hermes.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+static char *version = "dldwd_cs.c 0.01 (David Gibson <hermes@gibson.dropbear.id.au>)";
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0)
+#else
+#define DEBUG(n, args...) do { } while (0)
+#define DEBUGMORE(n, args...) do { } while (0)
+#endif
+
+#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname);
+#define TRACE_EXIT(devname)  DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname);
+
+#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
+#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
+
+#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) )
+
+
+#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10)
+#error "dldwd_cs requires Wireless extensions v10 or later."
+#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static uint irq_mask = 0xdeb8;
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+#define DLDWD_MIN_MTU		256
+#define DLDWD_MAX_MTU		(HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD)
+
+#define LTV_BUF_SIZE		128
+#define USER_BAP		0
+#define IRQ_BAP			1
+#define DLDWD_MACPORT		0
+#define IRQ_LOOP_MAX		10
+#define TX_NICBUF_SIZE		2048
+#define MAX_KEYS		4
+#define MAX_KEY_SIZE		14
+#define LARGE_KEY_SIZE		13
+#define SMALL_KEY_SIZE		5
+#define MAX_FRAME_SIZE		2304
+
+const long channel_frequency[] = {
+	2412, 2417, 2422, 2427, 2432, 2437, 2442,
+	2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )
+
+/* This tables gives the actual meanings of the bitrate IDs returned by the firmware.
+   It gives the rate in halfMb/s, negative indicates auto mode */
+const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0};
+
+#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0]))
+typedef struct dldwd_key {
+	uint16_t len;
+	char data[MAX_KEY_SIZE];
+} __attribute__ ((packed)) dldwd_key_t;
+
+typedef dldwd_key_t dldwd_keys_t[MAX_KEYS];
+
+typedef struct dldwd_priv {
+	dev_link_t link;
+	dev_node_t node;
+	int instance;
+
+	spinlock_t lock;
+	long state;
+#define DLDWD_STATE_INIRQ 0
+#define DLDWD_STATE_DOIRQ 1
+
+	/* Net device stuff */
+	struct net_device ndev;
+	struct net_device_stats stats;
+	struct iw_statistics wstats;
+
+
+	/* Hardware control variables */
+	hermes_t hw;
+	uint16_t txfid;
+
+	/* Capabilities of the hardware/firmware */
+	hermes_identity_t firmware_info;
+	int has_ibss, has_port3, prefer_port3;
+	int has_wep, has_big_wep, wep_type;
+#define WEP_TYPE_LUCENT 1
+#define WEP_TYPE_PRISM 2
+	int has_mwo;
+	int has_pm;
+	int broken_reset;
+	uint16_t channel_mask;
+
+	/* Current configuration */
+	uint32_t iw_mode;
+	int port_type, allow_ibss;
+	uint16_t wep_on, tx_key;
+	dldwd_keys_t keys;
+ 	char nick[IW_ESSID_MAX_SIZE+1];
+	char desired_essid[IW_ESSID_MAX_SIZE+1];
+	uint16_t frag_thresh, mwo_robust;
+	uint16_t channel;
+	uint16_t ap_density, rts_thresh;
+	uint16_t tx_rate_ctrl;
+	uint16_t pm_on, pm_mcast, pm_period;
+
+	int promiscuous, allmulti, mc_count;
+
+	/* /proc based debugging stuff */
+	struct proc_dir_entry *dir_dev;
+	struct proc_dir_entry *dir_regs;
+	struct proc_dir_entry *dir_recs;
+} dldwd_priv_t;
+
+struct p80211_hdr {
+	uint16_t frame_ctl;
+	uint16_t duration_id;
+	uint8_t addr1[ETH_ALEN];
+	uint8_t addr2[ETH_ALEN];
+	uint8_t addr3[ETH_ALEN];
+	uint16_t seq_ctl;
+	uint8_t addr4[ETH_ALEN];
+	uint16_t data_len;
+} __attribute__ ((packed));
+
+/* Frame control field constants */
+#define DLDWD_FCTL_VERS			0x0002
+#define DLDWD_FCTL_FTYPE		0x000c
+#define DLDWD_FCTL_STYPE		0x00f0
+#define DLDWD_FCTL_TODS			0x0100
+#define DLDWD_FCTL_FROMDS		0x0200
+#define DLDWD_FCTL_MOREFRAGS		0x0400
+#define DLDWD_FCTL_RETRY		0x0800
+#define DLDWD_FCTL_PM			0x1000
+#define DLDWD_FCTL_MOREDATA		0x2000
+#define DLDWD_FCTL_WEP			0x4000
+#define DLDWD_FCTL_ORDER		0x8000
+
+#define DLDWD_FTYPE_MGMT		0x0000
+#define DLDWD_FTYPE_CTL			0x0004
+#define DLDWD_FTYPE_DATA		0x0008
+
+struct p8022_hdr {
+	uint8_t dsap;
+	uint8_t ssap;
+	uint8_t ctrl;
+	uint8_t oui[3];
+} __attribute__ ((packed));
+
+struct dldwd_frame_hdr {
+	hermes_frame_desc_t desc;
+	struct p80211_hdr p80211;
+	struct ethhdr p8023;
+	struct p8022_hdr p8022;
+	uint16_t ethertype;
+} __attribute__ ((packed));
+
+#define P8023_OFFSET		(sizeof(hermes_frame_desc_t) + \
+				sizeof(struct p80211_hdr))
+#define ENCAPS_OVERHEAD		(sizeof(struct p8022_hdr) + 2)
+
+/*
+ * Function prototypes
+ */
+
+/* PCMCIA gumpf */
+
+static void dldwd_config(dev_link_t * link);
+static void dldwd_release(u_long arg);
+static int dldwd_event(event_t event, int priority,
+		       event_callback_args_t * args);
+
+static dev_link_t *dldwd_attach(void);
+static void dldwd_detach(dev_link_t *);
+
+/* Hardware control routines */
+
+static int __dldwd_hw_reset(dldwd_priv_t *priv);
+static void dldwd_shutdown(dldwd_priv_t *dev);
+static int dldwd_reset(dldwd_priv_t *dev);
+static int __dldwd_hw_setup_wep(dldwd_priv_t *priv);
+static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]);
+static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]);
+static long dldwd_hw_get_freq(dldwd_priv_t *priv);
+static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
+				    int32_t *rates, int max);
+
+/* Interrupt handling routines */
+void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw);
+
+/* struct net_device methods */
+static int dldwd_init(struct net_device *dev);
+static int dldwd_open(struct net_device *dev);
+static int dldwd_stop(struct net_device *dev);
+
+static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev);
+static void dldwd_tx_timeout(struct net_device *dev);
+
+static struct net_device_stats *dldwd_get_stats(struct net_device *dev);
+static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev);
+
+static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
+static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
+static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
+static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
+static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
+static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
+static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
+static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
+static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
+static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
+static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
+static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+
+static int dldwd_change_mtu(struct net_device *dev, int new_mtu);
+static void __dldwd_set_multicast_list(struct net_device *dev);
+
+/* /proc debugging stuff */
+static int dldwd_proc_init(void);
+static void dldwd_proc_cleanup(void);
+static int dldwd_proc_dev_init(dldwd_priv_t *dev);
+static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev);
+
+/*
+ * Inline functions
+ */
+static inline void
+dldwd_lock(dldwd_priv_t *priv)
+{
+	spin_lock_bh(&priv->lock);
+}
+
+static inline void
+dldwd_unlock(dldwd_priv_t *priv)
+{
+	spin_unlock_bh(&priv->lock);
+}
+
+static inline int
+dldwd_irqs_allowed(dldwd_priv_t *priv)
+{
+	return test_bit(DLDWD_STATE_DOIRQ, &priv->state);
+}
+
+static inline void
+__dldwd_stop_irqs(dldwd_priv_t *priv)
+{
+	hermes_t *hw = &priv->hw;
+
+	hermes_set_irqmask(hw, 0);
+	clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
+	while (test_bit(DLDWD_STATE_INIRQ, &priv->state))
+		;
+}
+
+static inline void
+__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask)
+{
+	hermes_t *hw = &priv->hw;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	__cli();
+	set_bit(DLDWD_STATE_DOIRQ, &priv->state);
+	hermes_set_irqmask(hw, irqmask);
+	__sti();
+
+	TRACE_EXIT(priv->ndev.name);
+}
+
+static inline void
+set_port_type(dldwd_priv_t *priv)
+{
+	switch (priv->iw_mode) {
+	case IW_MODE_INFRA:
+		priv->port_type = 1;
+		priv->allow_ibss = 0;
+		break;
+	case IW_MODE_ADHOC:
+		if (priv->prefer_port3) {
+			priv->port_type = 3;
+			priv->allow_ibss = 0;
+		} else {
+			priv->port_type = 1;
+			priv->allow_ibss = 1;
+		}
+		break;
+	default:
+		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
+		       priv->ndev.name);
+	}
+}
+
+static inline void
+dldwd_set_multicast_list(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+
+	dldwd_lock(priv);
+	__dldwd_set_multicast_list(dev);
+	dldwd_unlock(priv);
+}
+
+/*
+ * Hardware control routines
+ */
+
+static int
+__dldwd_hw_reset(dldwd_priv_t *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err;
+
+	if (! priv->broken_reset)
+		return hermes_reset(hw);
+	else {
+		hw->inten = 0;
+		hermes_write_regn(hw, INTEN, 0);
+		err = hermes_disable_port(hw, 0);
+		hermes_write_regn(hw, EVACK, 0xffff);
+		return err;
+	}
+}
+
+static void
+dldwd_shutdown(dldwd_priv_t *priv)
+{
+/* 	hermes_t *hw = &priv->hw; */
+	int err = 0;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	dldwd_lock(priv);
+	__dldwd_stop_irqs(priv);
+
+	err = __dldwd_hw_reset(priv);
+	if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */
+		printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err);
+
+	dldwd_unlock(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+}
+
+static int
+dldwd_reset(dldwd_priv_t *priv)
+{
+	struct net_device *dev = &priv->ndev;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	hermes_id_t idbuf;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	dldwd_lock(priv);
+
+	__dldwd_stop_irqs(priv);
+
+	err = __dldwd_hw_reset(priv);
+	if (err)
+		goto out;
+
+	err = hermes_allocate(hw, TX_NICBUF_SIZE, &priv->txfid);
+	if (err)
+		goto out;
+
+	/* Now set up all the parameters on the card */
+	
+	/* Set up the link mode */
+	
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type);
+	if (err)
+		goto out;
+	if (priv->has_ibss) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS,
+					   priv->allow_ibss);
+		if (err)
+			goto out;
+	}
+
+	/* Set up encryption */
+	err = __dldwd_hw_setup_wep(priv);
+	if (err)
+		goto out;
+
+	/* Set the desired ESSID */
+	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+	err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ?
+			       HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID,
+			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+			       &idbuf);
+	if (err)
+		goto out;
+
+	/* Set the station name */
+	idbuf.len = cpu_to_le16(strlen(priv->nick));
+	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
+			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+			       &idbuf);
+	if (err)
+		goto out;
+
+	/* Set the channel/frequency */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel);
+	if (err)
+		goto out;
+
+	/* Set AP density */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density);
+	if (err)
+		goto out;
+
+	/* Set RTS threshold */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh);
+	if (err)
+		goto out;
+
+	/* Set fragmentation threshold or MWO robustness */
+	if (priv->has_mwo)
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust);
+	else
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh);
+	if (err)
+		goto out;
+
+	/* Set bitrate */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL,
+				   priv->tx_rate_ctrl);
+	if (err)
+		goto out;
+
+	/* Set power management */
+	if (priv->has_pm) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE,
+					   priv->pm_on);
+		if (err)
+			goto out;
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX,
+					   priv->pm_mcast);
+		if (err)
+			goto out;
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
+					   priv->pm_period);
+		if (err)
+			goto out;
+	}
+
+	/* Set promiscuity / multicast*/
+	priv->promiscuous = 0;
+	priv->allmulti = 0;
+	priv->mc_count = 0;
+	__dldwd_set_multicast_list(dev);
+	
+	err = hermes_enable_port(hw, DLDWD_MACPORT);
+	if (err)
+		goto out;
+	
+	__dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
+			   HERMES_EV_TX | HERMES_EV_TXEXC |
+			   HERMES_EV_WTERR | HERMES_EV_INFO |
+			   HERMES_EV_INFDROP);
+
+ out:
+	dldwd_unlock(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return err;
+}
+
+static int __dldwd_hw_setup_wep(dldwd_priv_t *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	
+	switch (priv->wep_type) {
+	case 1: /* Lucent style WEP */
+		if (priv->wep_on) {
+			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key);
+			if (err)
+				return err;
+			
+			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys);
+			if (err)
+				return err;
+		}
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on);
+		if (err)
+			return err;
+		break;
+
+	case 2: /* Prism II style WEP */
+		if (priv->wep_on) {
+			char keybuf[SMALL_KEY_SIZE+1];
+			
+			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY,
+						   priv->tx_key);
+			if (err)
+				return err;
+			
+			keybuf[SMALL_KEY_SIZE] = '\0';
+
+			memcpy(keybuf, priv->keys[0].data, SMALL_KEY_SIZE);
+			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY0, &keybuf);
+			if (err)
+				return err;
+			memcpy(keybuf, priv->keys[1].data, SMALL_KEY_SIZE);
+			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY1, &keybuf);
+			if (err)
+				return err;
+			memcpy(keybuf, priv->keys[2].data, SMALL_KEY_SIZE);
+			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY2, &keybuf);
+			if (err)
+				return err;
+			memcpy(keybuf, priv->keys[3].data, SMALL_KEY_SIZE);
+			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_PRISM2_KEY3, &keybuf);
+			if (err)
+				return err;
+		}
+		
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, priv->wep_on);
+		if (err)
+			return err;	
+		break;
+
+	default:
+		if (priv->wep_on) {
+			printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
+			       priv->ndev.name);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+	return 0;
+}
+
+static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN])
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+
+	dldwd_lock(priv);
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID,
+			      ETH_ALEN, NULL, buf);
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active,
+			      char buf[IW_ESSID_MAX_SIZE+1])
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	hermes_id_t essidbuf;
+	char *p = (char *)(&essidbuf.val);
+	int len;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	dldwd_lock(priv);
+
+	if (strlen(priv->desired_essid) > 0) {
+		/* We read the desired SSID from the hardware rather
+		   than from priv->desired_essid, just in case the
+		   firmware is allowed to change it on us. I'm not
+		   sure about this */
+		uint16_t rid;
+
+		*active = 1;
+
+		rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID :
+			HERMES_RID_CNF_DESIRED_SSID;
+		
+		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+				      NULL, &essidbuf);
+		if (err)
+			goto fail_unlock;
+	} else {
+		*active = 0;
+
+		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID,
+				      sizeof(essidbuf), NULL, &essidbuf);
+		if (err)
+			goto fail_unlock;
+	}
+
+	len = le16_to_cpu(essidbuf.len);
+
+	memset(buf, 0, sizeof(buf));
+	memcpy(buf, p, len);
+	buf[len] = '\0';
+
+ fail_unlock:
+	dldwd_unlock(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return err;       
+}
+
+static long dldwd_hw_get_freq(dldwd_priv_t *priv)
+{
+	
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t channel;
+	long freq = 0;
+
+	dldwd_lock(priv);
+	
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel);
+	if (err)
+		goto out;
+
+	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
+		struct net_device *dev = &priv->ndev;
+
+		printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
+		err = -EBUSY;
+		goto out;
+
+	}
+	freq = channel_frequency[channel-1] * 100000;
+
+ out:
+	dldwd_unlock(priv);
+
+	if (err > 0)
+		err = -EBUSY;
+	return err ? err : freq;
+}
+
+static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
+				    int32_t *rates, int max)
+{
+	hermes_t *hw = &priv->hw;
+	hermes_id_t list;
+	unsigned char *p = (unsigned char *)&list.val;
+	int err = 0;
+	int num;
+	int i;
+
+	dldwd_lock(priv);
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list),
+			      NULL, &list);
+	dldwd_unlock(priv);
+
+	if (err)
+		return err;
+	
+	num = le16_to_cpu(list.len);
+	*numrates = num;
+	num = MIN(num, max);
+
+	for (i = 0; i < num; i++) {
+		rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
+	}
+
+	return 0;
+}
+
+#ifndef PCMCIA_DEBUG
+static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {}
+#else
+static void show_rx_frame(struct dldwd_frame_hdr *frame)
+{
+	printk(KERN_DEBUG "RX descriptor:\n");
+	printk(KERN_DEBUG "  status      = 0x%04x\n", frame->desc.status);
+	printk(KERN_DEBUG "  res1        = 0x%04x\n", frame->desc.res1);
+	printk(KERN_DEBUG "  res2        = 0x%04x\n", frame->desc.res2);
+	printk(KERN_DEBUG "  q_info      = 0x%04x\n", frame->desc.q_info);
+	printk(KERN_DEBUG "  res3        = 0x%04x\n", frame->desc.res3);
+	printk(KERN_DEBUG "  res4        = 0x%04x\n", frame->desc.res4);
+	printk(KERN_DEBUG "  tx_ctl      = 0x%04x\n", frame->desc.tx_ctl);
+
+	printk(KERN_DEBUG "IEEE 802.11 header:\n");
+	printk(KERN_DEBUG "  frame_ctl   = 0x%04x\n",
+	       frame->p80211.frame_ctl);
+	printk(KERN_DEBUG "  duration_id = 0x%04x\n",
+	       frame->p80211.duration_id);
+	printk(KERN_DEBUG "  addr1       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr1[0], frame->p80211.addr1[1],
+	       frame->p80211.addr1[2], frame->p80211.addr1[3],
+	       frame->p80211.addr1[4], frame->p80211.addr1[5]);
+	printk(KERN_DEBUG "  addr2       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr2[0], frame->p80211.addr2[1],
+	       frame->p80211.addr2[2], frame->p80211.addr2[3],
+	       frame->p80211.addr2[4], frame->p80211.addr2[5]);
+	printk(KERN_DEBUG "  addr3       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr3[0], frame->p80211.addr3[1],
+	       frame->p80211.addr3[2], frame->p80211.addr3[3],
+	       frame->p80211.addr3[4], frame->p80211.addr3[5]);
+	printk(KERN_DEBUG "  seq_ctl     = 0x%04x\n",
+	       frame->p80211.seq_ctl);
+	printk(KERN_DEBUG "  addr4       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr4[0], frame->p80211.addr4[1],
+	       frame->p80211.addr4[2], frame->p80211.addr4[3],
+	       frame->p80211.addr4[4], frame->p80211.addr4[5]);
+	printk(KERN_DEBUG "  data_len    = 0x%04x\n",
+	       frame->p80211.data_len);
+
+	printk(KERN_DEBUG "IEEE 802.3 header:\n");
+	printk(KERN_DEBUG "  dest        = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p8023.h_dest[0], frame->p8023.h_dest[1],
+	       frame->p8023.h_dest[2], frame->p8023.h_dest[3],
+	       frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
+	printk(KERN_DEBUG "  src         = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p8023.h_source[0], frame->p8023.h_source[1],
+	       frame->p8023.h_source[2], frame->p8023.h_source[3],
+	       frame->p8023.h_source[4], frame->p8023.h_source[5]);
+	printk(KERN_DEBUG "  len         = 0x%04x\n", frame->p8023.h_proto);
+
+	printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
+	printk(KERN_DEBUG "  DSAP        = 0x%02x\n", frame->p8022.dsap);
+	printk(KERN_DEBUG "  SSAP        = 0x%02x\n", frame->p8022.ssap);
+	printk(KERN_DEBUG "  ctrl        = 0x%02x\n", frame->p8022.ctrl);
+	printk(KERN_DEBUG "  OUI         = %02x:%02x:%02x\n",
+	       frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
+	printk(KERN_DEBUG "  ethertype  = 0x%04x\n", frame->ethertype);
+}
+#endif
+
+/*
+ * Interrupt handler
+ */
+void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *) dev_id;
+	hermes_t *hw = &priv->hw;
+	struct net_device *dev = &priv->ndev;
+	int count = IRQ_LOOP_MAX;
+	uint16_t evstat, events;
+	static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */
+
+	if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state))
+		BUG();
+
+	if (! dldwd_irqs_allowed(priv)) {
+		clear_bit(DLDWD_STATE_INIRQ, &priv->state);
+		return;
+	}
+
+	DEBUG(3, "%s: dldwd_interrupt()  irq %d\n", priv->ndev.name, irq);
+
+	while (1) {
+		if (jiffies != old_time)
+			timecount = 0;
+		if ( (++timecount > 50) || (! count--) ) {
+			printk(KERN_CRIT "%s: IRQ handler is looping too \
+much! Shutting down.\n",
+			       dev->name);
+			/* Perform an emergency shutdown */
+			clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
+			hermes_set_irqmask(hw, 0);
+			break;
+		}
+
+		evstat = hermes_read_regn(hw, EVSTAT);
+		DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n",
+		      count, evstat, hw->inten);
+
+		events = evstat & hw->inten;
+
+		if (! events) {
+			if (netif_queue_stopped(dev)) {
+				/* There seems to be a firmware bug which
+				   sometimes causes the card to give an
+				   interrupt with no event set, when there
+				   sould be a Tx completed event. */
+				DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n",
+				      dev->name, (int)hermes_read_regn(hw, ALLOCFID));
+				events = HERMES_EV_TX | HERMES_EV_ALLOC;
+			} else /* Nothing's happening, we're done */
+				break;
+		}
+
+		/* Check the card hasn't been removed */
+		if (! hermes_present(hw)) {
+			DEBUG(0, "dldwd_interrupt(): card removed\n");
+			break;
+		}
+
+		if (events & HERMES_EV_TICK)
+			__dldwd_ev_tick(priv, hw);
+		if (events & HERMES_EV_WTERR)
+			__dldwd_ev_wterr(priv, hw);
+		if (events & HERMES_EV_INFDROP)
+			__dldwd_ev_infdrop(priv, hw);
+		if (events & HERMES_EV_INFO)
+			__dldwd_ev_info(priv, hw);
+		if (events & HERMES_EV_RX)
+			__dldwd_ev_rx(priv, hw);
+		if (events & HERMES_EV_TXEXC)
+			__dldwd_ev_txexc(priv, hw);
+		if (events & HERMES_EV_TX)
+			__dldwd_ev_tx(priv, hw);
+		if (events & HERMES_EV_ALLOC)
+			__dldwd_ev_alloc(priv, hw);
+		
+		hermes_write_regn(hw, EVACK, events);
+	}
+
+	clear_bit(DLDWD_STATE_INIRQ, &priv->state);
+}
+
+static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+
+	printk(KERN_DEBUG "%s: TICK\n", dev->name);
+}
+
+static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+
+	/* This seems to happen a fair bit under load, but ignoring it
+	   seems to work fine...*/
+	DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n", dev->name);
+}
+
+static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+
+	printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
+}
+
+static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+
+	DEBUG(3, "%s: Information frame received.\n", dev->name);
+	/* We don't actually do anything about it - we assume the MAC
+	   controller can deal with it */
+}
+
+static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+	struct net_device_stats *stats = &priv->stats;
+	struct iw_statistics *wstats = &priv->wstats;
+	struct sk_buff *skb = NULL;
+	uint16_t rxfid, status;
+	int length, data_len, data_off;
+	char *p;
+	struct dldwd_frame_hdr hdr;
+	struct ethhdr *eh;
+	int err;
+
+	rxfid = hermes_read_regn(hw, RXFID);
+	DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid);
+
+	/* We read in the entire frame header here. This isn't really
+	   necessary, since we ignore most of it, but it's
+	   conceptually simpler. We can tune this later if
+	   necessary. */
+	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading frame header. "
+		       "Frame dropped.\n", dev->name, err);
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	status = le16_to_cpu(hdr.desc.status);
+	
+	if (status & HERMES_RXSTAT_ERR) {
+		if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) {
+			stats->rx_crc_errors++;
+			printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n",
+			       dev->name);
+			show_rx_frame(&hdr);
+		} else if ((status & HERMES_RXSTAT_ERR)
+			   == HERMES_RXSTAT_UNDECRYPTABLE) {
+			wstats->discard.code++;
+			printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n",
+			       dev->name);
+		} else {
+			wstats->discard.misc++;
+			printk("%s: Unknown Rx error (0x%x). Frame dropped.\n",
+			       dev->name, status & HERMES_RXSTAT_ERR);
+		}
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	length = le16_to_cpu(hdr.p80211.data_len);
+	/* Yes, you heard right, that's le16. 802.2 and 802.3 are
+	   big-endian, but 802.11 is little-endian believe it or
+	   not. */
+	
+	/* Sanity check */
+	if (length > MAX_FRAME_SIZE) {
+		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
+		       dev->name, length);
+		stats->rx_length_errors++;
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	/* We need space for the packet data itself, plus an ethernet
+	   header, plus 2 bytes so we can align the IP header on a
+	   32bit boundary, plus 1 byte so we can read in odd length
+	   packets from the card, which has an IO granularity of 16
+	   bits */  
+	skb = dev_alloc_skb(length+ETH_HLEN+2+1);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
+		       dev->name);
+		stats->rx_dropped++;
+		goto drop;
+	}
+
+	skb_reserve(skb, 2); /* This way the IP header is aligned */
+
+	/* Handle decapsulation */
+	switch (status & HERMES_RXSTAT_MSGTYPE) {
+		/* These both indicate a SNAP within 802.2 LLC within
+		   802.3 within 802.11 frame which we'll need to
+		   de-encapsulate. IEEE and ISO OSI have a lot to
+		   answer for.  */
+	case HERMES_RXSTAT_1042:
+	case HERMES_RXSTAT_TUNNEL:
+		data_len = length - ENCAPS_OVERHEAD;
+		data_off = sizeof(hdr);
+
+		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
+
+		memcpy(eh, &hdr.p8023, sizeof(hdr.p8023));
+		eh->h_proto = hdr.ethertype;
+
+		break;
+
+		/* Otherwise, we just throw the whole thing in, and hope
+		   the protocol layer can deal with it as 802.3 */
+	default:
+		data_len = length;
+		data_off = P8023_OFFSET;
+		break;
+	}
+
+	p = skb_put(skb, data_len);
+	if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
+			     rxfid, data_off) != 0) {
+		printk(KERN_WARNING "%s: Error reading packet data\n",
+		       dev->name);
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	dev->last_rx = jiffies;
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+	skb->ip_summed = CHECKSUM_NONE;
+	
+	
+	netif_rx(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += length;
+
+	return;
+
+ drop:	
+	if (skb)
+		dev_kfree_skb_irq(skb);
+	return;
+}
+
+static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+	struct net_device_stats *stats = &priv->stats;
+
+	printk(KERN_WARNING "%s: Tx error!\n", dev->name);
+
+	netif_wake_queue(dev);
+	stats->tx_errors++;
+}
+
+static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+	struct net_device_stats *stats = &priv->stats;
+
+	DEBUG(3, "%s: Transmit completed\n", dev->name);
+
+	stats->tx_packets++;
+	netif_wake_queue(dev);
+}
+
+static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw)
+{
+	uint16_t allocfid;
+
+	allocfid = hermes_read_regn(hw, ALLOCFID);
+	DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid);
+
+	/* For some reason we don't seem to get transmit completed events properly */
+	if (allocfid == priv->txfid)
+		__dldwd_ev_tx(priv, hw);
+
+/* 	hermes_write_regn(hw, ALLOCFID, 0); */
+}
+
+/*
+ * struct net_device methods
+ */
+
+static int dldwd_init(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	hermes_id_t nickbuf;
+	uint16_t reclen;
+	int len;
+	char *vendor_str;
+	uint32_t firmver;
+
+	TRACE_ENTER("dldwd");
+	
+	dldwd_lock(priv);
+
+	err = hermes_reset(hw);
+	if (err != 0) {
+		printk(KERN_ERR "%s: failed to reset hardware\n", dev->name);
+		goto out;
+	}
+	
+	/* Get the firmware version */
+	err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info);
+	if (err) {
+		printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
+		       dev->name, err);
+		memset(&priv->firmware_info, 0, sizeof(priv->firmware_info));
+	}
+
+	firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor;
+
+	/* Determine capabilities from the firmware version */
+
+	switch (priv->firmware_info.vendor) {
+	case 0x1:
+		/* Lucent Wavelan IEEE, Orinoco or Cabletron card */
+		vendor_str = "Lucent";
+
+		priv->broken_reset = 0;
+		priv->has_port3 = 1;
+		priv->has_ibss = (firmver >= 0x60006);
+		priv->has_wep = (firmver >= 0x40020);
+		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+					  Gold cards from the others? */
+		priv->wep_type = WEP_TYPE_LUCENT;
+		priv->has_mwo = (firmver >= 0x60000);
+		priv->has_pm = (firmver >= 0x40020);
+		break;
+	case 0x2:
+		vendor_str = "Generic Prism II";
+
+		priv->broken_reset = 0;
+		priv->has_port3 = 1; /* FIXME: no idea if this is right */
+		priv->has_ibss = 0; /* FIXME: no idea if this is right */
+		priv->has_wep = 1;
+		priv->has_big_wep = 0;
+		priv->wep_type = WEP_TYPE_PRISM;
+		priv->has_mwo = 0;
+		priv->has_pm = 1;
+		break;
+	case 0x6:
+		vendor_str = "LinkSys";
+
+		priv->broken_reset = 0;
+		priv->has_port3 = 1;
+		priv->has_ibss = 0;
+		priv->has_wep = 1;
+		priv->has_big_wep = 0;
+		priv->wep_type = WEP_TYPE_PRISM;
+		priv->has_mwo = 0;
+		priv->has_pm = 1;
+		break;
+	default:
+		vendor_str = "UNKNOWN";
+
+		priv->broken_reset = 0;
+		priv->has_port3 = 0;
+		priv->has_ibss = 0;
+		priv->has_wep = 0;
+		priv->has_big_wep = 0;
+		priv->wep_type = 0;
+		priv->has_mwo = 0;
+		priv->has_pm = 0;
+	}
+
+	printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n",
+	       dev->name, priv->firmware_info.id, priv->firmware_info.vendor,
+	       vendor_str, priv->firmware_info.major, priv->firmware_info.minor);
+	
+	if (priv->has_port3)
+		printk(KERN_INFO "%s: Lucent ad-hoc demo mode supported.\n", dev->name);
+	if (priv->has_ibss)
+		printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n",
+		       dev->name);
+	if (priv->has_wep) {
+		printk(KERN_INFO "%s: WEP supported, ", dev->name);
+		if (priv->has_big_wep)
+			printk("\"128\"-bit key.\n");
+		else
+			printk("40-bit key.");
+	}
+
+	/* Get the MAC address */
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR,
+			      ETH_ALEN, NULL, dev->dev_addr);
+	if (err) {
+		printk(KERN_WARNING "%s: failed to read MAC address!\n",
+		       dev->name);
+		goto out;
+	}
+
+	printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
+	       dev->name, dev->dev_addr[0], dev->dev_addr[1],
+	       dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
+	       dev->dev_addr[5]);
+
+	/* Get the station name */
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
+			      sizeof(nickbuf), &reclen, &nickbuf);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read station name!n",
+		       dev->name);
+		goto out;
+	}
+	if ( nickbuf.len )
+		len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len));
+	else
+		len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen);
+	memcpy(priv->nick, &nickbuf.val, len);
+	priv->nick[len] = '\0';
+
+	printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick);
+
+	/* Get allowed channels */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read channel list!\n",
+		       dev->name);
+		goto out;
+	}
+
+	/* Get initial AP density */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read AP density!\n", dev->name);
+		goto out;
+	}
+
+	/* Get initial RTS threshold */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name);
+		goto out;
+	}
+
+	/* Get initial fragmentation settings */
+	if (priv->has_mwo)
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST,
+					  &priv->mwo_robust);
+	else
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH,
+					  &priv->frag_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name);
+		goto out;
+	}
+
+	/* Set initial bitrate control*/
+	priv->tx_rate_ctrl = 3;
+
+	/* Power management setup */
+	if (priv->has_pm) {
+		priv->pm_on = 0;
+		priv->pm_mcast = 1;
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
+					  &priv->pm_period);
+		if (err) {
+			printk(KERN_ERR "%s: failed to read power management period!\n",
+			       dev->name);
+			goto out;
+		}
+	}
+		
+	/* Set up the default configuration */
+	priv->iw_mode = IW_MODE_INFRA;
+	/* By default use IEEE/IBSS ad-hoc mode if we have it */
+	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
+	set_port_type(priv);
+
+	priv->promiscuous = 0;
+	priv->allmulti = 0;
+	priv->wep_on = 0;
+	priv->tx_key = 0;
+
+	printk(KERN_INFO "%s: ready\n", dev->name);
+
+ out:
+	dldwd_unlock(priv);
+
+	TRACE_EXIT("dldwd");
+
+	return err;
+}
+
+static int dldwd_open(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	dev_link_t *link = &priv->link;
+	int err = 0;
+	
+	TRACE_ENTER(dev->name);
+
+	link->open++;
+	MOD_INC_USE_COUNT;
+	netif_device_attach(dev);
+	
+	err = dldwd_reset(priv);
+	if (err)
+		dldwd_stop(dev);
+	else
+		netif_start_queue(dev);
+
+	TRACE_EXIT(dev->name);
+
+	return err;
+}
+
+static int dldwd_stop(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	dev_link_t *link = &priv->link;
+
+	TRACE_ENTER(dev->name);
+
+	netif_stop_queue(dev);
+
+	dldwd_shutdown(priv);
+	
+	link->open--;
+
+	if (link->state & DEV_STALE_CONFIG)
+		mod_timer(&link->release, jiffies + HZ/20);
+	
+	MOD_DEC_USE_COUNT;
+
+	TRACE_EXIT(dev->name);
+	
+	return 0;
+}
+
+static struct net_device_stats *dldwd_get_stats(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	
+	return &priv->stats;
+}
+
+static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	hermes_t *hw = &priv->hw;
+	struct iw_statistics *wstats = &priv->wstats;
+	int err = 0;
+	hermes_commsqual_t cq;
+
+	dldwd_lock(priv);
+
+	if (priv->port_type == 3) {
+		memset(&wstats->qual, 0, sizeof(wstats->qual));
+	} else {
+		err = hermes_read_commsqual(hw, USER_BAP, &cq);
+		
+		wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0);
+		wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95;
+		wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95;
+		wstats->qual.updated = 7;
+	}
+
+	dldwd_unlock(priv);
+
+	if (err)
+		return NULL;
+		
+	return wstats;
+}
+
+struct p8022_hdr encaps_hdr = {
+	0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}
+};
+
+static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t txfid = priv->txfid;
+	char *p;
+	struct ethhdr *eh;
+	int len, data_len, data_off;
+	struct dldwd_frame_hdr hdr;
+	hermes_response_t resp;
+
+	if (! netif_running(dev)) {
+		printk(KERN_ERR "%s: Tx on stopped device!\n",
+		       dev->name);
+		return 1;
+
+	}
+	
+	if (netif_queue_stopped(dev)) {
+		printk(KERN_ERR "%s: Tx while transmitter busy!\n", 
+		       dev->name);
+		return 1;
+	}
+	
+	dldwd_lock(priv);
+
+	/* Length of the packet body */
+	len = MAX(skb->len - ETH_HLEN, ETH_ZLEN);
+
+	eh = (struct ethhdr *)skb->data;
+
+	/* Build the IEEE 802.11 header */
+	memset(&hdr, 0, sizeof(hdr));
+	memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN);
+	memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN);
+	hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA;
+
+	/* Encapsulate Ethernet-II frames */
+	if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
+		data_len = len;
+		data_off = sizeof(hdr);
+		p = skb->data + ETH_HLEN;
+
+		/* 802.11 header */
+		hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD);
+
+		/* 802.3 header */
+		memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN);
+		memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN);
+		hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD);
+		
+		/* 802.2 header */
+		memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr));
+
+		hdr.ethertype = eh->h_proto;
+		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
+					 txfid, 0);
+		if (err) {
+			printk(KERN_ERR
+			       "%s: Error %d writing packet header to BAP\n",
+			       dev->name, err);
+			stats->tx_errors++;
+			goto fail;
+		}
+	} else { /* IEEE 802.3 frame */
+		data_len = len + ETH_HLEN;
+		data_off = P8023_OFFSET;
+		p = skb->data;
+		
+		/* 802.11 header */
+		hdr.p80211.data_len = cpu_to_le16(len);
+		err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET,
+					txfid, 0);
+		if (err) {
+			printk(KERN_ERR
+			       "%s: Error %d writing packet header to BAP\n",
+			       dev->name, err);
+			stats->tx_errors++;
+			goto fail;
+		}
+	}
+
+	/* Round up for odd length packets */
+	err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d writing packet data to BAP\n",
+		       dev->name, err);
+		stats->tx_errors++;
+		goto fail;
+	}
+	
+
+	/* Finally, we actually initiate the send */
+	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err);
+		stats->tx_errors++;
+		goto fail;
+	}
+
+	dev->trans_start = jiffies;
+	stats->tx_bytes += data_off + data_len;
+
+	netif_stop_queue(dev);
+
+	dldwd_unlock(priv);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+ fail:
+
+	dldwd_unlock(priv);
+	return err;
+}
+
+static void dldwd_tx_timeout(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	int err = 0;
+
+	printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name);
+
+	stats->tx_errors++;
+
+	err = dldwd_reset(priv);
+	if (err)
+		printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
+		       dev->name, err);
+	else {
+		dev->trans_start = jiffies;
+		netif_wake_queue(dev);
+	}
+}
+
+static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+	int ptype;
+	struct iw_range range;
+	int numrates;
+	int i, k;
+
+	TRACE_ENTER(dev->name);
+
+	err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range));
+	if (err)
+		return err;
+
+	rrq->length = sizeof(range);
+
+	dldwd_lock(priv);
+	ptype = priv->port_type;
+	dldwd_unlock(priv);
+
+	memset(&range, 0, sizeof(range));
+
+	/* Much of this shamelessly taken from wvlan_cs.c. No idea
+	 * what it all means -dgibson */
+	range.throughput = 0.5 * 1024 * 1024; /* TCP throughput measured with socklib.
+					       I'm hoping MB/s are the right units. */
+	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+
+	
+	range.num_channels = NUM_CHANNELS;
+	if (err)
+		return err;
+	k = 0;
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (priv->channel_mask & (1 << i)) {
+			range.freq[k].i = i + 1;
+			range.freq[k].m = channel_frequency[i] * 100000;
+			range.freq[k].e = 1;
+			k++;
+		}
+		
+		if (k >= IW_MAX_FREQUENCIES)
+			break;
+	}
+	range.num_frequency = k;
+
+	range.sensitivity = 3;
+
+	if (ptype == 3) {
+		/* Quality stats meaningless in ad-hoc mode */
+		range.max_qual.qual = 0;
+		range.max_qual.level = 0;
+		range.max_qual.noise = 0;
+	} else {
+		range.max_qual.qual = 0x8b - 0x2f;
+		range.max_qual.level = 0x2f - 0x95 - 1;
+		range.max_qual.noise = 0x2f - 0x95 - 1;
+	}
+
+	err = dldwd_hw_get_bitratelist(priv, &numrates,
+				       range.bitrate, IW_MAX_BITRATES);
+	if (err)
+		return err;
+	range.num_bitrates = numrates;
+	
+	range.min_rts = 0;
+	range.max_rts = 2347;
+	range.min_frag = 256;
+	range.max_frag = 2346;
+
+	dldwd_lock(priv);
+	if (priv->has_wep) {
+		range.max_encoding_tokens = MAX_KEYS;
+
+		range.encoding_size[0] = SMALL_KEY_SIZE;
+		range.num_encoding_sizes = 1;
+
+		if (priv->has_big_wep) {
+			range.encoding_size[1] = LARGE_KEY_SIZE;
+			range.num_encoding_sizes = 2;
+		}
+	} else {
+		range.num_encoding_sizes = 0;
+		range.max_encoding_tokens = 0;
+	}
+	dldwd_unlock(priv);
+		
+	range.min_pmp = 0;
+	range.max_pmp = 65535000;
+	range.pmp_flags = IW_POWER_PERIOD;
+	range.pmt_flags = 0;
+	range.pm_capa = IW_POWER_PERIOD | IW_POWER_UNICAST_R;
+
+	range.num_txpower = 0;
+	range.txpower[0] = 15; /* 15dBm */
+	range.txpower_capa = IW_TXPOW_DBM;
+
+	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
+		return -EFAULT;
+
+	TRACE_EXIT(dev->name);
+
+	return 0;
+}
+
+static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	int enable = 0;
+	uint16_t xlen = 0;
+	int err = 0;
+	char keybuf[MAX_KEY_SIZE];
+
+	if (erq->flags & IW_ENCODE_RESTRICTED)
+		return -EINVAL;
+
+	if (erq->pointer) {
+		/* We actually have a key to set */
+		
+		if (copy_from_user(keybuf, erq->pointer, erq->length))
+			return -EFAULT;
+	}
+	
+	dldwd_lock(priv);
+	
+	if (erq->pointer) {
+		if (erq->length > MAX_KEY_SIZE) {
+			err = -E2BIG;
+			goto out;
+		}
+		
+		if ( (erq->length > LARGE_KEY_SIZE)
+		     || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE))  ) {
+			err = -EINVAL;
+			goto out;
+		}
+		
+		if ((index < 0) || (index >= MAX_KEYS))
+			index = priv->tx_key;
+		
+		if (erq->length > SMALL_KEY_SIZE) {
+			xlen = LARGE_KEY_SIZE;
+		} else if (erq->length > 0) {
+			xlen = SMALL_KEY_SIZE;
+		} else
+			xlen = 0;
+		
+		if ( (index == priv->tx_key) && (xlen > 0) )
+			enable = 1;
+	} else {
+		if ((index < 0) || (index >= MAX_KEYS)) {
+			err = -EINVAL;
+			goto out;
+		}
+		
+		enable = 1;
+	}
+	
+	if (erq->flags & IW_ENCODE_DISABLED)
+		enable = 0;
+	
+	if (erq->pointer) {
+		priv->keys[index].len = cpu_to_le16(xlen);
+		memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data));
+		memcpy(priv->keys[index].data, keybuf, erq->length);
+	}
+	priv->tx_key = index;
+	priv->wep_on = enable;
+	
+ out:
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	uint16_t xlen = 0;
+	char keybuf[MAX_KEY_SIZE];
+
+	
+	dldwd_lock(priv);
+
+	if ((index < 0) || (index >= MAX_KEYS))
+		index = priv->tx_key;
+
+	erq->flags = 0;
+	if (! priv->wep_on)
+		erq->flags |= IW_ENCODE_DISABLED;
+	erq->flags |= index + 1;
+	
+	xlen = le16_to_cpu(priv->keys[index].len);
+
+	erq->length = xlen;
+
+	if (erq->pointer) {
+		memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE);
+	}
+	
+	dldwd_unlock(priv);
+
+	if (erq->pointer) {
+		if (copy_to_user(erq->pointer, keybuf, xlen))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char essidbuf[IW_ESSID_MAX_SIZE+1];
+
+	memset(&essidbuf, 0, sizeof(essidbuf));
+
+	if (erq->flags) { 
+		if (erq->length > IW_ESSID_MAX_SIZE)
+			return -E2BIG;
+		
+		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
+			return -EFAULT;
+
+		essidbuf[erq->length] = '\0';
+	}
+
+	dldwd_lock(priv);
+
+	memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1);
+
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char essidbuf[IW_ESSID_MAX_SIZE+1];
+	int active;
+	int err = 0;
+
+	TRACE_ENTER(dev->name);
+
+	err = dldwd_hw_get_essid(priv, &active, essidbuf);
+	if (err)
+		return err;
+
+	erq->flags = 1;
+	erq->length = strlen(essidbuf) + 1;
+	if (erq->pointer)
+		if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
+			return -EFAULT;
+
+	TRACE_EXIT(dev->name);
+	
+	return 0;
+}
+
+static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char nickbuf[IW_ESSID_MAX_SIZE+1];
+
+	if (nrq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
+
+	memset(nickbuf, 0, sizeof(nickbuf));
+
+	if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
+		return -EFAULT;
+
+	nickbuf[nrq->length] = '\0';
+	
+	dldwd_lock(priv);
+
+	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char nickbuf[IW_ESSID_MAX_SIZE+1];
+
+	dldwd_lock(priv);
+	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
+	dldwd_unlock(priv);
+
+	nrq->length = strlen(nickbuf)+1;
+
+	if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int chan = -1;
+
+	if (priv->iw_mode == IW_MODE_ADHOC)
+		return -EOPNOTSUPP;
+
+	if ( (frq->e == 0) && (frq->m <= 1000) ) {
+		/* Setting by channel number */
+		chan = frq->m;
+	} else {
+		/* Setting by frequency - search the table */
+		int mult = 1;
+		int i;
+
+		for (i = 0; i < (6 - frq->e); i++)
+			mult *= 10;
+
+		for (i = 0; i < NUM_CHANNELS; i++)
+			if (frq->m == (channel_frequency[i] * mult))
+				chan = i+1;
+	}
+
+	if ( (chan < 1) || (chan > NUM_CHANNELS) ||
+	     ! (priv->channel_mask & (1 << (chan-1)) ) )
+		return -EINVAL;
+
+	dldwd_lock(priv);
+	priv->channel = chan;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	uint16_t val;
+	int err;
+
+	dldwd_lock(priv);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val);
+	dldwd_unlock(priv);
+
+	if (err)
+		return err;
+
+	srq->value = val;
+	srq->fixed = 0; /* auto */
+
+	return 0;
+}
+
+static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int val = srq->value;
+
+	if ((val < 1) || (val > 3))
+		return -EINVAL;
+	
+	dldwd_lock(priv);
+	priv->ap_density = val;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int val = rrq->value;
+
+	if (rrq->disabled)
+		val = 2347;
+
+	if ( (val < 0) || (val > 2347) )
+		return -EINVAL;
+
+	dldwd_lock(priv);
+	priv->rts_thresh = val;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+
+	dldwd_lock(priv);
+
+	if (priv->has_mwo) {
+		if (frq->disabled)
+			priv->mwo_robust = 0;
+		else {
+			if (frq->fixed)
+				printk(KERN_WARNING "%s: Fixed fragmentation not \
+supported on this firmware. Using MWO robust instead.\n", dev->name);
+			priv->mwo_robust = 1;
+		}
+	} else {
+		if (frq->disabled)
+			priv->frag_thresh = 2346;
+		else {
+			if ( (frq->value < 256) || (frq->value > 2346) )
+				err = -EINVAL;
+			else
+				priv->frag_thresh = frq->value & ~0x1; /* must be even */
+		}
+	}
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t val;
+
+	dldwd_lock(priv);
+	
+	if (priv->has_mwo) {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val);
+		if (err)
+			val = 0;
+
+		frq->value = val ? 2347 : 0;
+		frq->disabled = ! val;
+		frq->fixed = 0;
+	} else {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val);
+		if (err)
+			val = 0;
+
+		frq->value = val;
+		frq->disabled = (val >= 2346);
+		frq->fixed = 1;
+	}
+
+	dldwd_unlock(priv);
+	
+	return err;
+}
+
+static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+	int rate_ctrl = -1;
+	int brate;
+	int i;
+
+	dldwd_lock(priv);
+
+	brate = rrq->value / 500000;
+	if (! rrq->fixed) {
+		if (brate > 0)
+			brate = -brate;
+		else
+			brate = -22;
+	}
+	
+	for (i = 0; i < NUM_RATES; i++)
+		if (rate_list[i] == brate) {
+			rate_ctrl = i;
+			break;
+		}
+	
+	if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) )
+		err = -EINVAL;
+	else
+		priv->tx_rate_ctrl = rate_ctrl;
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t val;
+	int brate;
+
+	dldwd_lock(priv);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val);
+	if (err)
+		goto out;
+	
+	brate = rate_list[val];
+	
+	if (brate < 0) {
+		rrq->fixed = 0;
+
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
+		if (err)
+			goto out;
+
+		if (val == 6)
+			brate = 11;
+		else
+			brate = 2*val;
+	} else
+		rrq->fixed = 1;
+
+	rrq->value = brate * 500000;
+	rrq->disabled = 0;
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+	int mcast = 1;
+
+
+	dldwd_lock(priv);
+
+	if (prq->disabled) {
+		priv->pm_on = 0;
+	} else {
+		switch (prq->flags & IW_POWER_MODE) {
+		case IW_POWER_UNICAST_R:
+			mcast = 0;
+			break;
+		case IW_POWER_ALL_R:
+			mcast = 1;
+			break;
+		case IW_POWER_ON:
+			mcast = priv->pm_mcast;
+			break;
+		default:
+			err = -EINVAL;
+		}
+		if (err)
+			goto out;
+		
+		if (prq->flags & IW_POWER_TIMEOUT) {
+			err = -EINVAL;
+			goto out;
+		}
+
+		if (prq->flags & IW_POWER_PERIOD) {
+			priv->pm_on = 1;
+			priv->pm_mcast = mcast;
+			priv->pm_period = prq->value / 1000;
+		} else {
+			err = -EINVAL;
+			goto out;
+		}			
+
+	}
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t enable, period, mcast;
+
+	dldwd_lock(priv);
+	
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast);
+	if (err)
+		goto out;
+
+	prq->disabled = !enable;
+	prq->flags = IW_POWER_PERIOD;
+	if (mcast)
+		prq->flags |= IW_POWER_ALL_R;
+	else
+		prq->flags |= IW_POWER_UNICAST_R;
+	prq->value = period * 1000;
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int val = *( (int *) wrq->u.name );
+	int err = 0;
+
+	dldwd_lock(priv);
+	switch (val) {
+	case 0: /* Try to do IEEE ad-hoc mode */
+		if (! priv->has_ibss) {
+			err = -EINVAL;
+			break;
+		}
+		priv->prefer_port3 = 0;
+			
+		break;
+
+	case 1: /* Try to do Lucent proprietary ad-hoc mode */
+		if (! priv->has_port3) {
+			err = -EINVAL;
+			break;
+		}
+		priv->prefer_port3 = 1;
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int *val = (int *)wrq->u.name;
+
+	dldwd_lock(priv);
+	*val = priv->prefer_port3;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	dldwd_priv_t *priv = dev->priv;
+	struct iwreq *wrq = (struct iwreq *)rq;
+	int err = 0;
+	int changed = 0;
+
+	TRACE_ENTER(dev->name);
+
+	switch (cmd) {
+	case SIOCGIWNAME:
+		DEBUG(1, "%s: SIOCGIWNAME\n", dev->name);
+		strcpy(wrq->u.name, "IEEE 802.11-DS");
+		break;
+		
+	case SIOCGIWAP:
+		DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
+		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+		err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
+		break;
+
+	case SIOCGIWRANGE:
+		DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
+		err = dldwd_ioctl_getiwrange(dev, &wrq->u.data);
+		break;
+
+	case SIOCSIWMODE:
+		DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
+		dldwd_lock(priv);
+		switch (wrq->u.mode) {
+		case IW_MODE_ADHOC:
+			if (! (priv->has_ibss || priv->has_port3) )
+				err = -EINVAL;
+			else {
+				priv->iw_mode = IW_MODE_ADHOC;
+				changed = 1;
+			}
+			break;
+
+		case IW_MODE_INFRA:
+			priv->iw_mode = IW_MODE_INFRA;
+			changed = 1;
+			break;
+
+		default:
+			err = -EINVAL;
+			break;
+		}
+		set_port_type(priv);
+		dldwd_unlock(priv);
+		break;
+
+	case SIOCGIWMODE:
+		DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
+		dldwd_lock(priv);
+		wrq->u.mode = priv->iw_mode;
+		dldwd_unlock(priv);
+		break;
+
+	case SIOCSIWENCODE:
+		DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name);
+		if (! priv->has_wep) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+
+		err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWENCODE:
+		DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name);
+		if (! priv->has_wep) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+
+		err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding);
+		break;
+
+	case SIOCSIWESSID:
+		DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
+		err = dldwd_ioctl_setessid(dev, &wrq->u.essid);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWESSID:
+		DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
+		err = dldwd_ioctl_getessid(dev, &wrq->u.essid);
+		break;
+
+	case SIOCSIWNICKN:
+		DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
+		err = dldwd_ioctl_setnick(dev, &wrq->u.data);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWNICKN:
+		DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
+		err = dldwd_ioctl_getnick(dev, &wrq->u.data);
+		break;
+
+	case SIOCGIWFREQ:
+		DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
+		wrq->u.freq.m = dldwd_hw_get_freq(priv);
+		wrq->u.freq.e = 1;
+		break;
+
+	case SIOCSIWFREQ:
+		DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
+		err = dldwd_ioctl_setfreq(dev, &wrq->u.freq);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWSENS:
+		DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
+		err = dldwd_ioctl_getsens(dev, &wrq->u.sens);
+		break;
+
+	case SIOCSIWSENS:
+		DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
+		err = dldwd_ioctl_setsens(dev, &wrq->u.sens);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWRTS:
+		DEBUG(1, "%s: SIOCGIWRTS\n", dev->name);
+		wrq->u.rts.value = priv->rts_thresh;
+		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
+		wrq->u.rts.fixed = 1;
+		break;
+
+	case SIOCSIWRTS:
+		DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
+		err = dldwd_ioctl_setrts(dev, &wrq->u.rts);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCSIWFRAG:
+		DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
+		err = dldwd_ioctl_setfrag(dev, &wrq->u.frag);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWFRAG:
+		DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
+		err = dldwd_ioctl_getfrag(dev, &wrq->u.frag);
+		break;
+
+	case SIOCSIWRATE:
+		DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
+		err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWRATE:
+		DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
+		err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate);
+		break;
+
+	case SIOCSIWPOWER:
+		DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
+		err = dldwd_ioctl_setpower(dev, &wrq->u.power);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWPOWER:
+		DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
+		err = dldwd_ioctl_getpower(dev, &wrq->u.power);
+		break;
+
+	case SIOCGIWTXPOW:
+		DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name);
+		/* The card only supports one tx power, so this is easy */
+		wrq->u.txpower.value = 15; /* dBm */
+		wrq->u.txpower.fixed = 1;
+		wrq->u.txpower.disabled = 0;
+		wrq->u.txpower.flags = IW_TXPOW_DBM;
+		break;
+
+	case SIOCGIWPRIV:
+		DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
+		if (wrq->u.data.pointer) {
+			struct iw_priv_args privtab[] = {
+				{ SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" },
+				{ SIOCDEVPRIVATE + 0x2,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  0, "set_port3" },
+				{ SIOCDEVPRIVATE + 0x3, 0,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  "get_port3" }
+			};
+
+			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
+			if (err)
+				break;
+			
+			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
+			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
+				err = -EFAULT;
+		}
+		break;
+	       
+	case SIOCDEVPRIVATE + 0x0: /* force_reset */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+		
+		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+		dldwd_reset(priv);
+		break;
+
+	case SIOCDEVPRIVATE + 0x2: /* set_port3 */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+
+		err = dldwd_ioctl_setport3(dev, wrq);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCDEVPRIVATE + 0x3: /* get_port3 */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n",
+		      dev->name);
+		err = dldwd_ioctl_getport3(dev, wrq);
+		break;
+
+	default:
+		err = -EOPNOTSUPP;
+	}
+	
+	if (! err && changed && netif_running(dev)) {
+		err = dldwd_reset(priv);
+		if (err)
+			dldwd_stop(dev);
+	}		
+
+	TRACE_EXIT(dev->name);
+		
+	return err;
+}
+
+static int dldwd_change_mtu(struct net_device *dev, int new_mtu)
+{
+	TRACE_ENTER(dev->name);
+
+	if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) )
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	TRACE_EXIT(dev->name);
+
+	return 0;
+}
+
+static void __dldwd_set_multicast_list(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int promisc, allmulti, mc_count;
+
+	TRACE_ENTER(dev->name);
+
+	DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n",
+	      dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count);
+
+	/* The Hermes doesn't seem to have an allmulti mode, so we go
+	 * into promiscuous mode and let the upper levels deal. */
+	if ( (dev->flags & IFF_PROMISC) ) {
+		promisc = 1;
+		allmulti = 0;
+		mc_count = 0;
+	} else if ( (dev->flags & IFF_ALLMULTI) ||
+		    (dev->mc_count > HERMES_MAX_MULTICAST) ) {
+		promisc = 0;
+		allmulti = 1;
+		mc_count = HERMES_MAX_MULTICAST;
+	} else {
+		promisc = 0;
+		allmulti = 0;
+		mc_count = dev->mc_count;
+	}
+
+	DEBUG(3, "promisc=%d mc_count=%d\n",
+	      promisc, mc_count);
+
+	if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS,
+					   promisc);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n",
+			       dev->name, err, promisc);
+		} else 
+			priv->promiscuous = promisc;
+	}
+
+	if (allmulti) {
+		/* FIXME: This method of doing allmulticast reception
+		   comes from the NetBSD driver. Haven't actually
+		   tested whether it works or not. */
+		hermes_multicast_t mclist;
+
+		memset(&mclist, 0, sizeof(mclist));
+		err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist);
+		if (err)
+			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+			       dev->name, err);
+		else
+			priv->allmulti = 1;
+		       
+	} else if (mc_count || (! mc_count && priv->mc_count) ) {
+		struct dev_mc_list *p = dev->mc_list;
+		hermes_multicast_t mclist;
+		int i;
+
+		for (i = 0; i < mc_count; i++) {
+			/* First some paranoid checks */
+			if (! p) {
+				printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n",
+				       dev->name);
+				break;
+			}
+			if (p->dmi_addrlen != ETH_ALEN) {
+
+				printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n",
+				       dev->name, p->dmi_addrlen);
+				break;
+			}
+
+			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
+			p = p->next;
+		}
+
+		/* More paranoia */
+		if (p)
+			printk(KERN_ERR "%s: Multicast list longer than mc_count.\n",
+			       dev->name);
+
+		priv->mc_count = i;			
+
+		DEBUG(3, "priv->mc_count = %d\n", priv->mc_count);
+
+		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST,
+				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
+				       &mclist);
+		if (err)
+			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+			       dev->name, err);
+		else
+			priv->allmulti = 0;
+	}
+
+	/* Since we can set the promiscuous flag when it wasn't asked
+	   for, make sure the net_device knows about it. */
+	if (priv->promiscuous)
+		dev->flags |= IFF_PROMISC;
+	else
+		dev->flags &= ~IFF_PROMISC;
+
+	if (priv->allmulti)
+		dev->flags |= IFF_ALLMULTI;
+	else
+		dev->flags &= ~IFF_ALLMULTI;
+
+	TRACE_EXIT(dev->name);
+}
+
+/*
+ * procfs stuff
+ */
+
+static struct proc_dir_entry *dir_base = NULL;
+
+/*
+ * This function updates the total amount of data printed so far. It then
+ * determines if the amount of data printed into a buffer  has reached the
+ * offset requested. If it hasn't, then the buffer is shifted over so that
+ * the next bit of data can be printed over the old bit. If the total
+ * amount printed so far exceeds the total amount requested, then this
+ * function returns 1, otherwise 0.
+ */
+static int 
+
+shift_buffer(char *buffer, int requested_offset, int requested_len,
+	     int *total, int *slop, char **buf)
+{
+	int printed;
+	
+	printed = *buf - buffer;
+	if (*total + printed <= requested_offset) {
+		*total += printed;
+		*buf = buffer;
+	}
+	else {
+		if (*total < requested_offset) {
+			*slop = requested_offset - *total;
+		}
+		*total = requested_offset + printed - *slop;
+	}
+	if (*total > requested_offset + requested_len) {
+		return 1;
+	}
+	else {
+		return 0;
+	}
+}
+
+/*
+ * This function calculates the actual start of the requested data
+ * in the buffer. It also calculates actual length of data returned,
+ * which could be less that the amount of data requested.
+ */
+#define PROC_BUFFER_SIZE 4096
+#define PROC_SAFE_SIZE 3072
+
+static int
+calc_start_len(char *buffer, char **start, int requested_offset,
+	       int requested_len, int total, char *buf)
+{
+	int return_len, buffer_len;
+	
+	buffer_len = buf - buffer;
+	if (buffer_len >= PROC_BUFFER_SIZE - 1) {
+		printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n");
+	}
+	
+	/*
+	 * There may be bytes before and after the
+	 * chunk that was actually requested.
+	 */
+	return_len = total - requested_offset;
+	if (return_len < 0) {
+		return_len = 0;
+	}
+	*start = buf - return_len;
+	if (return_len > requested_len) {
+		return_len = requested_len;
+	}
+	return return_len;
+}
+
+static int
+dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset,
+			   int requested_len, int *eof, void *data)
+{
+	dldwd_priv_t *dev = (dldwd_priv_t *)data;
+	hermes_t *hw = &dev->hw;
+	char *buf;
+	int total = 0, slop = 0;
+
+	buf = page;
+
+#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name))
+
+	DHERMESREG(CMD);
+	DHERMESREG(PARAM0);
+	DHERMESREG(PARAM1);
+	DHERMESREG(PARAM2);
+	DHERMESREG(STATUS);
+	DHERMESREG(RESP0);
+	DHERMESREG(RESP1);
+	DHERMESREG(RESP2);
+	DHERMESREG(INFOFID);
+	DHERMESREG(RXFID);
+	DHERMESREG(ALLOCFID);
+	DHERMESREG(TXCOMPLFID);
+	DHERMESREG(SELECT0);
+	DHERMESREG(OFFSET0);
+	DHERMESREG(SELECT1);
+	DHERMESREG(OFFSET1);
+	DHERMESREG(EVSTAT);
+	DHERMESREG(INTEN);
+	DHERMESREG(EVACK);
+	DHERMESREG(CONTROL);
+	DHERMESREG(SWSUPPORT0);
+	DHERMESREG(SWSUPPORT1);
+	DHERMESREG(SWSUPPORT2);
+	DHERMESREG(AUXPAGE);
+	DHERMESREG(AUXOFFSET);
+	DHERMESREG(AUXDATA);
+#undef DHERMESREG
+
+	shift_buffer(page, requested_offset, requested_len, &total,
+		     &slop, &buf);
+	return calc_start_len(page, start, requested_offset, requested_len,
+			      total, buf);
+}
+
+struct {
+	uint16_t rid;
+	char *name;
+	int minlen, maxlen;
+	int displaytype;
+#define DISPLAY_WORDS	0
+#define DISPLAY_BYTES	1
+#define DISPLAY_STRING	2
+} record_table[] = {
+#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type }
+	RTCNFENTRY(PORTTYPE, DISPLAY_WORDS),
+	RTCNFENTRY(MACADDR, DISPLAY_BYTES),
+	RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING),
+	RTCNFENTRY(CHANNEL, DISPLAY_WORDS),
+	RTCNFENTRY(OWN_SSID, DISPLAY_STRING),
+	RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS),
+	RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS),
+	RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS),
+	RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS),
+	RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS),
+	RTCNFENTRY(NICKNAME, DISPLAY_STRING),
+	RTCNFENTRY(WEP_ON, DISPLAY_WORDS),
+	RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS),
+	RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES),
+	RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS),
+	RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS),
+	RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS),
+	RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS),
+	RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS),
+	RTCNFENTRY(KEYS, DISPLAY_BYTES),
+	RTCNFENTRY(TX_KEY, DISPLAY_WORDS),
+	RTCNFENTRY(TICKTIME, DISPLAY_WORDS),
+	RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS),
+	RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS),
+#undef RTCNFENTRY
+#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type }
+	RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS),
+	RTINFENTRY(STAIDENTITY, DISPLAY_WORDS),
+	RTINFENTRY(CURRENT_SSID, DISPLAY_STRING),
+	RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES),
+	RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS),
+	RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS),
+	RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS),
+	RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS),
+	RTINFENTRY(DATARATES, DISPLAY_BYTES),
+#undef RTINFENTRY
+};
+#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
+
+static int
+dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
+			   int requested_len, int *eof, void *data)
+{
+	dldwd_priv_t *dev = (dldwd_priv_t *)data;
+	hermes_t *hw = &dev->hw;
+	char *buf;
+	int total = 0, slop = 0;
+	int i;
+	uint16_t length;
+	int err;
+
+	buf = page;
+
+	/* print out all the config RIDs */
+	for (i = 0; i < NUM_RIDS; i++) {
+		uint16_t rid = record_table[i].rid;
+		int minlen = record_table[i].minlen;
+		int maxlen = record_table[i].maxlen;
+		int len;
+		uint8_t *val8;
+		uint16_t *val16;
+		int j;
+
+		val8 = kmalloc(maxlen + 2, GFP_KERNEL);
+		if (! val8)
+			return -ENOMEM;
+
+		err = hermes_read_ltv(hw, USER_BAP, rid, maxlen,
+				      &length, val8);
+		if (err) {
+			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
+			continue;
+		}
+		val16 = (uint16_t *)val8;
+
+		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
+			       rid, length, (length-1)*2);
+		len = MIN( MAX(minlen, (length-1)*2), maxlen);
+
+		switch (record_table[i].displaytype) {
+		case DISPLAY_WORDS:
+			for (j = 0; j < len / 2; j++) {
+				buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j]));
+			}
+			buf--;
+			break;
+
+		case DISPLAY_BYTES:
+		default:
+			for (j = 0; j < len; j++) {
+				buf += sprintf(buf, "%02X:", val8[j]);
+			}
+			buf--;
+			break;
+
+		case DISPLAY_STRING:
+			len = MIN(len, le16_to_cpu(val16[0])+2);
+			val8[len] = '\0';
+			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
+			break;
+		}
+
+		buf += sprintf(buf, "\n");
+
+		kfree(val8);
+
+		if (shift_buffer(page, requested_offset, requested_len,
+				 &total, &slop, &buf))
+			break;
+
+		if ( (buf - page) > PROC_SAFE_SIZE )
+			break;
+	}
+
+	return calc_start_len(page, start, requested_offset, requested_len,
+			      total, buf);
+}
+
+/* initialise the /proc subsystem for the hermes driver, creating the
+ * separate entries */
+static int
+dldwd_proc_init(void)
+{
+	int err = 0;
+
+	TRACE_ENTER("dldwd");
+
+	/* create the directory for it to sit in */
+	dir_base = create_proc_entry("dldwd", S_IFDIR, &proc_root);
+	if (dir_base == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/dldwd.\n");
+		dldwd_proc_cleanup();
+		err = -ENOMEM;
+	}
+
+	TRACE_EXIT("dldwd");
+
+	return err;
+}
+
+static int
+dldwd_proc_dev_init(dldwd_priv_t *dev)
+{
+	dev->dir_dev = NULL;
+	/* create the directory for it to sit in */
+	dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO,
+					 dir_base);
+	if (dev->dir_dev == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/dldwd/%s.\n",  dev->node.dev_name);
+		goto fail;
+	}
+
+	dev->dir_regs = NULL;
+	dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO,
+					       dev->dir_dev, dldwd_proc_get_hermes_regs, dev);
+	if (dev->dir_regs == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/dldwd/%s/regs.\n",  dev->node.dev_name);
+		goto fail;
+	}
+
+	dev->dir_recs = NULL;
+	dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
+					       dev->dir_dev, dldwd_proc_get_hermes_recs, dev);
+	if (dev->dir_recs == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/dldwd/%s/recs.\n",  dev->node.dev_name);
+		goto fail;
+	}
+
+	return 0;
+ fail:
+	dldwd_proc_dev_cleanup(dev);
+	return -ENOMEM;
+}
+
+static void
+dldwd_proc_dev_cleanup(dldwd_priv_t *priv)
+{
+	if (priv->dir_regs) {
+		remove_proc_entry("regs", priv->dir_dev);
+		priv->dir_regs = NULL;
+	}		
+	if (priv->dir_recs) {
+		remove_proc_entry("recs", priv->dir_dev);
+		priv->dir_recs = NULL;
+	}		
+	if (priv->dir_dev) {
+		remove_proc_entry(priv->node.dev_name, dir_base);
+		priv->dir_dev = NULL;
+	}
+}
+
+static void
+dldwd_proc_cleanup(void)
+{
+	TRACE_ENTER("dldwd");
+
+	if (dir_base) {
+		remove_proc_entry("dldwd", &proc_root);
+		dir_base = NULL;
+	}
+	
+	TRACE_EXIT("dldwd");
+}
+
+/*====================================================================*/
+
+/*
+ * From here on in, it's all PCMCIA junk, taken almost directly from
+ * dummy_cs.c
+ */
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "dldwd_cs";
+
+/*
+   A linked list of "instances" of the dummy device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+static int num_instances = 0;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+  dldwd_attach() creates an "instance" of the driver, allocating
+  local data structures for one device.  The device is registered
+  with Card Services.
+  
+  The dev_link structure is initialized, but we don't actually
+  configure the card at this point -- we wait until we receive a
+  card insertion event.
+  ======================================================================*/
+
+static dev_link_t *dldwd_attach(void)
+{
+	dldwd_priv_t *priv;
+	dev_link_t *link;
+	struct net_device *ndev;
+	client_reg_t client_reg;
+	int ret, i;
+
+	TRACE_ENTER("dldwd");
+
+	/* Allocate space for private device-specific data */
+	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	if (! priv) {
+		link = NULL;
+		goto out;
+	}
+
+	memset(priv, 0, sizeof(*priv));
+	priv->instance = num_instances++; /* FIXME: Racy? */
+	spin_lock_init(&priv->lock);
+
+	link = &priv->link;
+	ndev = &priv->ndev;
+	link->priv = ndev->priv = priv;
+
+	/* Initialize the dev_link_t structure */
+	link->release.function = &dldwd_release;
+	link->release.data = (u_long) link;
+
+	/* Interrupt setup */
+	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->irq.Handler = NULL;
+
+	/*
+	   General socket configuration defaults can go here.  In this
+	   client, we assume very little, and rely on the CIS for almost
+	   everything.  In most clients, many details (i.e., number, sizes,
+	   and attributes of IO windows) are fixed by the nature of the
+	   device, and can be hard-wired here.
+	 */
+	link->conf.Attributes = 0;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Set up the net_device */
+	ether_setup(ndev);
+	ndev->init = dldwd_init;
+	ndev->open = dldwd_open;
+	ndev->stop = dldwd_stop;
+	ndev->hard_start_xmit = dldwd_xmit;
+	ndev->tx_timeout = dldwd_tx_timeout;
+	ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */
+
+	ndev->get_stats = dldwd_get_stats;
+	ndev->get_wireless_stats = dldwd_get_wireless_stats;
+
+	ndev->do_ioctl = dldwd_ioctl;
+	
+	ndev->change_mtu = dldwd_change_mtu;
+	ndev->set_multicast_list = dldwd_set_multicast_list;
+
+	netif_stop_queue(ndev);
+
+	/* 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 = &dldwd_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);
+		dldwd_detach(link);
+		link = NULL;
+		goto out;
+	}
+
+ out:
+	TRACE_EXIT("dldwd");
+	return link;
+}				/* dldwd_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 dldwd_detach(dev_link_t * link)
+{
+	dev_link_t **linkp;
+	dldwd_priv_t *priv = link->priv;
+
+	TRACE_ENTER("dldwd");
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+	if (*linkp == NULL)
+		goto out;
+
+	/*
+	   If the device is currently configured and active, we won't
+	   actually delete it yet.  Instead, it is marked so that when
+	   the release() function is called, that will trigger a proper
+	   detach().
+	 */
+	if (link->state & DEV_CONFIG) {
+#ifdef PCMCIA_DEBUG
+		printk(KERN_DEBUG "dldwd_cs: detach postponed, '%s' "
+		       "still locked\n", link->dev->dev_name);
+#endif
+		link->state |= DEV_STALE_LINK;
+		goto out;
+	}
+
+	/* Break the link with Card Services */
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+
+	/* Unlink device structure, and free it */
+	*linkp = link->next;
+	DEBUG(0, "dldwd_cs: detach: link=%p link->dev=%p\n", link, link->dev);
+	if (link->dev) {
+		DEBUG(0, "dldwd_cs: About to unregister net device %p\n",
+		      &priv->ndev);
+		unregister_netdev(&priv->ndev);
+	}
+	kfree(priv);
+
+	num_instances--; /* FIXME: Racy? */
+
+ out:
+	TRACE_EXIT("dldwd");
+}				/* dldwd_detach */
+
+/*======================================================================
+  dldwd_config() is scheduled to run after a CARD_INSERTION event
+  is received, to configure the PCMCIA socket, and to make the
+  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
+
+static void dldwd_config(dev_link_t * link)
+{
+	client_handle_t handle = link->handle;
+	dldwd_priv_t *priv = link->priv;
+	hermes_t *hw = &priv->hw;
+	struct net_device *ndev = &priv->ndev;
+	tuple_t tuple;
+	cisparse_t parse;
+	int last_fn, last_ret;
+	u_char buf[64];
+	config_info_t conf;
+	cisinfo_t info;
+
+	TRACE_ENTER("dldwd");
+
+	CS_CHECK(ValidateCIS, handle, &info);
+
+	/*
+	   This reads the card's CONFIG tuple to find its configuration
+	   registers.
+	 */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	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;
+
+	/* Look up the current Vcc */
+	CS_CHECK(GetConfigurationInfo, handle, &conf);
+	link->conf.Vcc = conf.Vcc;
+
+	DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
+	      link->conf.ConfigBase, link->conf.Vcc);
+
+	/*
+	   In this loop, we scan the CIS for configuration table entries,
+	   each of which describes a valid card configuration, including
+	   voltage, IO window, memory window, and interrupt settings.
+
+	   We make no assumptions about the card to be configured: we use
+	   just the information available in the CIS.  In an ideal world,
+	   this would work for any PCMCIA card, but it requires a complete
+	   and accurate CIS.  In practice, a driver usually "knows" most of
+	   these things without consulting the CIS, and most client drivers
+	   will only use the CIS to fill in implementation-defined details.
+	 */
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	while (1) {
+		cistpl_cftable_entry_t dflt = { 0 };
+		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+		CFG_CHECK(GetTupleData, handle, &tuple);
+		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+		DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n",
+		      cfg->index, cfg->flags);
+
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+			dflt = *cfg;
+		if (cfg->index == 0)
+			goto next_entry;
+		link->conf.ConfigIndex = cfg->index;
+
+		/* Does this card need audio output? */
+		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+			link->conf.Attributes |= CONF_ENABLE_SPKR;
+			link->conf.Status = CCSR_AUDIO_ENA;
+		}
+
+		/* Use power settings for Vcc and Vpp if present */
+		/*  Note that the CIS values need to be rescaled */
+		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;
+		
+		DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n");
+
+		/* Do we need to allocate an interrupt? */
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+		/* IO window settings */
+		link->io.NumPorts1 = link->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+			cistpl_io_t *io =
+			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				link->io.Attributes1 =
+				    IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				link->io.Attributes1 =
+				    IO_DATA_PATH_WIDTH_8;
+			link->io.IOAddrLines =
+			    io->flags & CISTPL_IO_LINES_MASK;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				link->io.Attributes2 =
+				    link->io.Attributes1;
+				link->io.BasePort2 = io->win[1].base;
+				link->io.NumPorts2 = io->win[1].len;
+			}
+
+			/* This reserves IO space but doesn't actually enable it */
+			CFG_CHECK(RequestIO, link->handle, &link->io);
+		}
+
+
+		/* If we got this far, we're cool! */
+
+		break;
+		
+	next_entry:
+		if (link->io.NumPorts1)
+			CardServices(ReleaseIO, link->handle, &link->io);
+		CS_CHECK(GetNextTuple, handle, &tuple);
+	}
+
+	/*
+	   Allocate an interrupt line.  Note that this does not assign a
+	   handler to the interrupt, unless the 'Handler' member of the
+	   irq structure is initialized.
+	 */
+	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+		int i;
+
+		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 = dldwd_interrupt; 
+  		link->irq.Instance = priv; 
+		
+		CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	}
+
+	sprintf(priv->node.dev_name, "dldwd%d", priv->instance);
+	
+	/* We initialize the hermes structure before completing PCMCIA
+	   configuration just in case the interrupt handler gets
+	   called. */
+	hermes_struct_init(hw, link->io.BasePort1);
+
+	/*
+	   This actually configures the PCMCIA socket -- setting up
+	   the I/O windows and the interrupt mapping, and putting the
+	   card and host interface into "Memory and IO" mode.
+	 */
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+	/* Finally, report what we've done */
+	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	       priv->node.dev_name, link->conf.ConfigIndex,
+	       link->conf.Vcc / 10, link->conf.Vcc % 10);
+	if (link->conf.Vpp1)
+		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+		       link->conf.Vpp1 % 10);
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		printk(", irq %d", link->irq.AssignedIRQ);
+	if (link->io.NumPorts1)
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		       link->io.BasePort1 + link->io.NumPorts1 - 1);
+	if (link->io.NumPorts2)
+		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+		       link->io.BasePort2 + link->io.NumPorts2 - 1);
+	printk("\n");
+	
+	/* And give us the proc nodes for debugging */
+	if (dldwd_proc_dev_init(priv) != 0) {
+		printk(KERN_ERR "dldwd_cs: Failed to create /proc node for %s\n",
+		       priv->node.dev_name);
+		goto failed;
+	}
+	
+	ndev->base_addr = link->io.BasePort1;
+	ndev->irq = link->irq.AssignedIRQ;
+
+	strcpy(ndev->name, priv->node.dev_name);
+	if (register_netdev(ndev) != 0) {
+		printk(KERN_ERR "dldwd_cs: register_netdev() failed\n");
+		goto failed;
+	}
+
+	/*
+	   At this point, the dev_node_t structure(s) need to be
+	   initialized and arranged in a linked list at link->dev.
+	 */
+	priv->node.major = priv->node.minor = 0;
+	link->dev = &priv->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	TRACE_EXIT("dldwd");
+
+	return;
+
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+ failed:
+	dldwd_release((u_long) link);
+
+	TRACE_EXIT("dldwd");
+}				/* dldwd_config */
+
+/*======================================================================
+  After a card is removed, dldwd_release() will unregister the
+  device, and release the PCMCIA configuration.  If the device is
+  still open, this will be postponed until it is closed.
+  ======================================================================*/
+
+static void dldwd_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *) arg;
+	dldwd_priv_t *priv = link->priv;
+
+	TRACE_ENTER(link->dev->dev_name);
+
+	/*
+	   If the device is currently in use, we won't release until it
+	   is actually closed, because until then, we can't be sure that
+	   no one will try to access the device or its data structures.
+	 */
+	if (link->open) {
+		DEBUG(0, "dldwd_cs: release postponed, '%s' still open\n",
+		      link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	/*
+	   In a normal driver, additional code may be needed to release
+	   other kernel data structures associated with this device. 
+	 */
+
+	dldwd_proc_dev_cleanup(priv);
+
+	/* Don't bother checking to see if these succeed or not */
+	CardServices(ReleaseConfiguration, link->handle);
+	if (link->io.NumPorts1)
+		CardServices(ReleaseIO, link->handle, &link->io);
+	if (link->irq.AssignedIRQ)
+		CardServices(ReleaseIRQ, link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+
+	TRACE_EXIT(link->dev->dev_name);
+}				/* dldwd_release */
+
+/*======================================================================
+  The card status event handler.  Mostly, this schedules other
+  stuff to run after an event is received.
+
+  When a CARD_REMOVAL event is received, we immediately set a
+  private flag to block future accesses to this device.  All the
+  functions that actually access the device should check this flag
+  to make sure the card is still present.
+  ======================================================================*/
+
+static int dldwd_event(event_t event, int priority,
+		       event_callback_args_t * args)
+{
+	dev_link_t *link = args->client_data;
+	dldwd_priv_t *priv = (dldwd_priv_t *)link->priv;
+	struct net_device *dev = &priv->ndev;
+
+	TRACE_ENTER("dldwd");
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		dldwd_shutdown(priv);
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			netif_stop_queue(dev);
+			netif_device_detach(dev);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		dldwd_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		dldwd_shutdown(priv);
+		/* Mark the device as stopped, to block IO until later */
+
+		if (link->state & DEV_CONFIG) {
+			if (link->open) {
+				netif_stop_queue(dev);
+				netif_device_detach(dev);
+			}
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			CardServices(RequestConfiguration, link->handle,
+				     &link->conf);
+
+			if (link->open) {
+				if (dldwd_reset(priv) == 0) {
+					netif_device_attach(dev);
+					netif_start_queue(dev);
+				} else {
+					printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n",
+					       dev->name);
+					dldwd_stop(dev);
+				}
+			}
+		}
+		/*
+		   In a normal driver, additional code may go here to restore
+		   the device state and restart IO. 
+		 */
+		break;
+	}
+
+	TRACE_EXIT("dldwd");
+
+	return 0;
+}				/* dldwd_event */
+
+static int __init init_dldwd_cs(void)
+{
+	servinfo_t serv;
+	int err;
+	
+	TRACE_ENTER("dldwd");
+
+	printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n");
+
+	DEBUG(0, "%s\n", version);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "dldwd_cs: Card Services release "
+		       "does not match!\n");
+		return -1;
+	}
+	register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach);
+
+	
+	err = dldwd_proc_init();
+
+	TRACE_EXIT("dldwd");
+	return err;
+}
+
+static void __exit exit_dldwd_cs(void)
+{
+	TRACE_ENTER("dldwd");
+
+	dldwd_proc_cleanup();
+
+	unregister_pccard_driver(&dev_info);
+
+	if (dev_list)
+		DEBUG(0, "dldwd_cs: Removing leftover devices.\n");
+	while (dev_list != NULL) {
+		del_timer(&dev_list->release);
+		if (dev_list->state & DEV_CONFIG)
+			dldwd_release((u_long) dev_list);
+		dldwd_detach(dev_list);
+	}
+
+	TRACE_EXIT("dldwd");
+}
+
+module_init(init_dldwd_cs);
+module_exit(exit_dldwd_cs);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/pcnet_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/pcnet_cs.c	Fri Mar  2 11:02:15 2001
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    pcnet_cs.c 1.126 2000/10/02 20:38:23
+    pcnet_cs.c 1.132 2001/02/09 03:13:29
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -72,7 +72,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.126 2000/10/02 20:38:23 (David Hinds)";
+"pcnet_cs.c 1.132 2001/02/09 03:13:29 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -137,7 +137,7 @@
 #define HAS_IBM_MISC	0x08
 #define IS_DL10019	0x10
 #define IS_DL10022	0x20
-#define IS_AX88190	0x40
+#define HAS_MII		0x40
 #define USE_SHMEM	0x80	/* autodetected */
 
 static hw_info_t hw_info[] = {
@@ -204,8 +204,8 @@
 #define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
 
 static hw_info_t default_info = { 0, 0, 0, 0, 0 };
-static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019 };
-static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10019|IS_DL10022 };
+static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
+static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII };
 
 typedef struct pcnet_dev_t {
     struct net_device	dev;	/* so &dev == &pcnet_dev_t */
@@ -507,10 +507,10 @@
     if (link->conf.ConfigBase != 0x03c0)
 	return NULL;
 
-    outb_p(0x01, EN0_DCFG);	/* Set word-wide access. */
-    outb_p(0x00, EN0_RSARLO);	/* DMA starting at 0x0400. */
-    outb_p(0x04, EN0_RSARHI);
-    outb_p(E8390_RREAD+E8390_START, E8390_CMD);
+    outb_p(0x01, ioaddr + EN0_DCFG);	/* Set word-wide access. */
+    outb_p(0x00, ioaddr + EN0_RSARLO);	/* DMA starting at 0x0400. */
+    outb_p(0x04, ioaddr + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, ioaddr + E8390_CMD);
 
     for (i = 0; i < 6; i += 2) {
 	j = inw(ioaddr + PCNET_DATAPORT);
@@ -718,6 +718,7 @@
     info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
     if ((manfid == MANFID_SOCKET) &&
 	((prodid == PRODID_SOCKET_LPE) ||
+	 (prodid == PRODID_SOCKET_LPE_CF) ||
 	 (prodid == PRODID_SOCKET_EIO)))
 	info->flags &= ~USE_BIG_BUF;
     if (!use_big_buf)
@@ -746,13 +747,11 @@
     link->dev = &info->node;
     link->state &= ~DEV_CONFIG_PENDING;
 
-    if (info->flags & IS_DL10019) {
+    if (info->flags & (IS_DL10019|IS_DL10022)) {
 	dev->do_ioctl = &do_ioctl;
 	printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
 	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19),
 	       inb(dev->base_addr + 0x1a));
-    } else if (info->flags & IS_AX88190) {
-	printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name);
     } else
 	printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
     printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
@@ -1024,6 +1023,8 @@
 
     ei_status.txing = ei_status.dmaing = 0;
 
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, nic_base + E8390_CMD);
+
     outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
 
     for (i = 0; i < 100; i++) {
@@ -1092,10 +1093,17 @@
 	return;
     }
 
-    if (!(info->flags & IS_DL10019))
+    if (!(info->flags & HAS_MII))
+	goto reschedule;
+
+    link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1);
+    if (!link || (link == 0xffff)) {
+	printk(KERN_INFO "%s: MII is missing!\n", dev->name);
+	info->flags &= ~HAS_MII;
 	goto reschedule;
+    }
 
-    link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1) & 0x0004;
+    link &= 0x0004;
     if (link != info->link_status) {
 	u_short p = mdio_read(dev->base_addr + DLINK_GPIO, 0, 5);
 	printk(KERN_INFO "%s: %s link beat\n", dev->name,
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/ray_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/ray_cs.c	Fri Mar  2 11:02:15 2001
@@ -2219,9 +2219,9 @@
 
     skb->protocol = eth_type_trans(skb,dev);
     netif_rx(skb);
-
+    dev->last_rx = jiffies;
     local->stats.rx_packets++;
-    local->stats.rx_bytes += skb->len;
+    local->stats.rx_bytes += total_len;
 
     /* Gather signal strength per address */
 #ifdef WIRELESS_SPY
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/smc91c92_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/smc91c92_cs.c	Fri Mar  2 11:02:15 2001
@@ -8,7 +8,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    smc91c92_cs.c 1.104 2000/08/31 21:25:13
+    smc91c92_cs.c 1.106 2001/02/07 00:19:58
     
     This driver contains code written by Donald Becker
     (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au),
@@ -231,7 +231,7 @@
 	     RxEnable = 0x0100, RxStripCRC = 0x0200};
 #define  RCR_SOFTRESET	0x8000 	/* resets the chip */
 #define	 RCR_STRIP_CRC	0x200	/* strips CRC */
-#define  RCR_ENABLE	0x100	/* IFF this is set, we can recieve packets */
+#define  RCR_ENABLE	0x100	/* IFF this is set, we can receive packets */
 #define  RCR_ALMUL	0x4 	/* receive all multicast packets */
 #define	 RCR_PROMISC	0x2	/* enable promiscuous mode */
 
@@ -1617,8 +1617,9 @@
 	
 	skb->dev = dev;
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	smc->stats.rx_packets++;
-	smc->stats.rx_bytes += skb->len;
+	smc->stats.rx_bytes += packet_length;
 	if (rx_status & RS_MULTICAST)
 	    smc->stats.multicast++;
     } else {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h
--- v2.4.2/linux/drivers/net/pcmcia/wavelan.h	Wed Oct 20 21:33:12 1999
+++ linux/drivers/net/pcmcia/wavelan.h	Fri Mar  2 11:02:15 2001
@@ -7,11 +7,11 @@
  * Original copyright follow. See wavelan_cs.h for details.
  *
  * This file contain the declarations of the Wavelan hardware. Note that
- * the Pcmcia Wavelan include a i82593 controler (see definitions in
+ * the Pcmcia Wavelan include a i82593 controller (see definitions in
  * file i82593.h).
  *
  * The main difference between the pcmcia hardware and the ISA one is
- * the Ethernet Controler (i82593 instead of i82586). The i82593 allow
+ * the Ethernet Controller (i82593 instead of i82586). The i82593 allow
  * only one send buffer. The PSA (Parameter Storage Area : EEprom for
  * permanent storage of various info) is memory mapped, but not the
  * MMI (Modem Management Interface).
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.c	Thu Jan  4 12:50:12 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Tue Mar 20 12:05:00 2001
@@ -37,6 +37,12 @@
  * Apr 2 '98  made changes to bring the i82593 control/int handling in line
  *             with offical specs...
  *
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
+ * - reorganize kmallocs in wavelan_attach, checking all for failure
+ *   and releasing the previous allocations if one fails
+ *
+ *
  ****************************************************************************
  *   Copyright 1995
  *   Anthony D. Joseph
@@ -512,7 +518,7 @@
   /* Do not remove this unless you have a good reason */
   printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
 	 " device %s !\n", dev->name, dev->name);
-  printk(KERN_NOTICE "Roaming is currently an experimental unsuported feature"
+  printk(KERN_NOTICE "Roaming is currently an experimental unsupported feature"
 	 " of the Wavelan driver.\n");
   printk(KERN_NOTICE "It may work, but may also make the driver behave in"
 	 " erratic ways or crash.\n");
@@ -820,7 +826,7 @@
 
 /************************ I82593 SUBROUTINES *************************/
 /*
- * Usefull subroutines to manage the Ethernet controler
+ * Useful subroutines to manage the Ethernet controller
  */
 
 /*------------------------------------------------------------------*/
@@ -853,7 +859,7 @@
   /* We are waiting for command completion */
   wv_wait_completed = TRUE;
 
-  /* Issue the command to the controler */
+  /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
   /* If we don't have to check the result of the command */
@@ -1398,7 +1404,7 @@
 	  printk("2430.5");
 	  break;
 	default:
-	  printk("???");
+	  printk("unknown");
 	}
     }
 
@@ -1713,7 +1719,7 @@
 	 memcmp(dac, dac_verify, 2 * 2))
 	{
 #ifdef DEBUG_IOCTL_ERROR
-	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
 #endif
 	  return -EOPNOTSUPP;
 	}
@@ -1774,7 +1780,7 @@
 #if WIRELESS_EXT > 7
   const int	BAND_NUM = 10;	/* Number of bands */
   int		c = 0;		/* Channel number */
-#endif WIRELESS_EXT
+#endif /* WIRELESS_EXT */
 
   /* Read the frequency table */
   fee_read(base, 0x71 /* frequency table */,
@@ -1792,7 +1798,7 @@
 	      (c < BAND_NUM))
 	  c++;
 	list[i].i = c;	/* Set the list index */
-#endif WIRELESS_EXT
+#endif /* WIRELESS_EXT */
 
 	/* put in the list */
 	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
@@ -1962,7 +1968,7 @@
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody ??? - especially old cards...) */
+       * (does it work for everybody XXX - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
@@ -2524,11 +2530,12 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
+  if (lp == NULL) /* XXX will this ever occur? */
+    return NULL;
+
   /* Disable interrupts & save flags */
   spin_lock_irqsave (&lp->lock, flags);
 
-  if(lp == (net_local *) NULL)
-    return (iw_stats *) NULL;
   wstats = &lp->wstats;
 
   /* Get data from the mmc */
@@ -2727,8 +2734,9 @@
   netif_rx(skb);
 
   /* Keep stats up to date */
+  dev->last_rx = jiffies;
   lp->stats.rx_packets++;
-  lp->stats.rx_bytes += skb->len;
+  lp->stats.rx_bytes += sksize;
 
 #ifdef DEBUG_RX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
@@ -2949,7 +2957,7 @@
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the the harware is ready to accept
+ * In this routine, we check if the hardware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
@@ -2974,7 +2982,7 @@
 	 * In other words, prevent reentering this routine.
 	 */
 	if (1) {
-		/* If somebody has asked to reconfigure the controler, we can do it now */
+		/* If somebody has asked to reconfigure the controller, we can do it now */
 		if (lp->reconfig_82593) {
 			lp->reconfig_82593 = FALSE;
 			wv_82593_config (dev);
@@ -3144,7 +3152,7 @@
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody ??? - especially old cards...) */
+   * (does it work for everybody XXX - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3332,7 +3340,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * This routine does a standard config of the WaveLAN controler (i82593).
+ * This routine does a standard config of the WaveLAN controller (i82593).
  * In the ISA driver, this is integrated in wavelan_hardware_reset()
  * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit())
  */
@@ -3596,7 +3604,7 @@
   hacr_write_slow(base, HACR_RESET);
   hacr_write(base, HACR_DEFAULT);
 
-  /* Check if the the module has been powered up... */
+  /* Check if the module has been powered up... */
   if(hasr_read(base) & HASR_NO_CLK)
     {
 #ifdef DEBUG_CONFIG_ERRORS
@@ -3614,7 +3622,7 @@
   outb(OP0_RESET, LCCR(base));
   mdelay(1);	/* A bit crude ! */
 
-  /* Initialize the LAN controler */
+  /* Initialize the LAN controller */
   if((wv_82593_config(dev) == FALSE) ||
      (wv_diag(dev) == FALSE))
     {
@@ -3822,7 +3830,7 @@
       return FALSE;
     }
 
-  /* ???? Could you explain me this, Dave ? */
+  /* XXX Could you explain me this, Dave ? */
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3918,7 +3926,7 @@
  * This function is the interrupt handler for the WaveLAN card. This
  * routine will be called whenever: 
  *	1. A packet is received.
- *	2. A packet has successfully been transfered and the unit is
+ *	2. A packet has successfully been transferred and the unit is
  *	   ready to transmit another packet.
  *	3. A command has completed execution.
  */
@@ -4285,7 +4293,7 @@
       /* Power up (power up time is 250us) */
       hacr_write(base, HACR_DEFAULT);
 
-      /* Check if the the module has been powered up... */
+      /* Check if the module has been powered up... */
       if(hasr_read(base) & HASR_NO_CLK)
 	{
 #ifdef DEBUG_CONFIG_ERRORS
@@ -4424,7 +4432,24 @@
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  if (!link)
+	  return NULL;
+  
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev)
+	  goto fail_alloc_dev;
+  
+  /* Allocate the wavelan-specific data structure. */
+  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp)
+	  goto fail_alloc_dev_priv;
+  
+  memset(lp, 0, sizeof(net_local));
   memset(link, 0, sizeof(struct dev_link_t));
+  memset(dev, 0, sizeof(struct net_device));
+
+  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4454,15 +4479,8 @@
   link->next = dev_list;
   dev_list = link;
 
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
-  /* Allocate the wavelan-specific data structure. */
-  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  memset(lp, 0x00, sizeof(net_local));
-
   /* Init specific data */
   wv_wait_completed = 0;
   lp->status = FALSE;
@@ -4531,6 +4549,12 @@
 #endif
 
   return link;
+
+fail_alloc_dev_priv:
+  kfree(dev);
+fail_alloc_dev:
+  kfree(link);
+  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4683,7 +4707,7 @@
 	 * obliged to close nicely the wavelan here. David, could you
 	 * close the device before suspending them ? And, by the way,
 	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up ??? Thanks... */
+	 * ifconfig up XXX Thanks... */
 
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
@@ -4711,7 +4735,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
       	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
 	      {
 		wv_hw_reset(dev);
 		netif_device_attach(dev);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- v2.4.2/linux/drivers/net/pcmcia/wavelan_cs.h	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Fri Mar  2 11:02:15 2001
@@ -96,7 +96,7 @@
  *
  * wavelan.h :		Description of the hardware interface & structs
  *
- * i82593.h :		Description if the Ethernet controler
+ * i82593.h :		Description if the Ethernet controller
  */
 
 /* --------------------------- HISTORY --------------------------- */
@@ -225,7 +225,7 @@
  *	- wavelan_set_multicast_list : avoid reset
  *	- add wireless extensions (ioctl & get_wireless_stats)
  *	  get/set nwid/frequency on fly, info for /proc/net/wireless
- *	- Supress useless stuff from lp (net_local), but add link
+ *	- Suppress useless stuff from lp (net_local), but add link
  *	- More inlines
  *	- Lot of others minor details & cleanups
  *
@@ -315,7 +315,7 @@
  *		o Rename wavelan_release to wv_pcmcia_release & move up
  *		o move unregister_netdev to wavelan_detach()
  *		o wavelan_release() no longer call wavelan_detach()
- *		o Supress "release" timer
+ *		o Suppress "release" timer
  *		o Other cleanups & fixes
  *	- New MAC address in the probe
  *	- Reorg PSA_CRC code (endian neutral & cleaner)
@@ -430,14 +430,14 @@
 #undef DEBUG_CONFIG_INFO	/* What's going on... */
 #define DEBUG_CONFIG_ERRORS	/* Errors on configuration */
 #undef DEBUG_TX_TRACE		/* Transmission calls */
-#undef DEBUG_TX_INFO		/* Header of the transmited packet */
+#undef DEBUG_TX_INFO		/* Header of the transmitted packet */
 #undef DEBUG_TX_FAIL		/* Normal failure conditions */
 #define DEBUG_TX_ERROR		/* Unexpected conditions */
 #undef DEBUG_RX_TRACE		/* Transmission calls */
-#undef DEBUG_RX_INFO		/* Header of the transmited packet */
+#undef DEBUG_RX_INFO		/* Header of the transmitted packet */
 #undef DEBUG_RX_FAIL		/* Normal failure conditions */
 #define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen */
 #undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
 #undef DEBUG_IOCTL_INFO		/* Various debug info */
 #define DEBUG_IOCTL_ERROR	/* What's going wrong */
@@ -557,7 +557,7 @@
   en_stats	stats;		/* Ethernet interface statistics */
   int		nresets;	/* Number of hw resets */
   u_char	configured;	/* If it is configured */
-  u_char	reconfig_82593;	/* Need to reconfigure the controler */
+  u_char	reconfig_82593;	/* Need to reconfigure the controller */
   u_char	promiscuous;	/* Promiscuous mode */
   u_char	allmulticast;	/* All Multicast mode */
   int		mc_count;	/* Number of multicast addresses */
@@ -669,7 +669,7 @@
 		     char *,
 		     int);
 static inline void
-	wv_82593_reconfig(device *);	/* Reconfigure the controler */
+	wv_82593_reconfig(device *);	/* Reconfigure the controller */
 /* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
 static inline void
 	wv_init_info(device *);	/* display startup info */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- v2.4.2/linux/drivers/net/pcmcia/xirc2ps_cs.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Fri Mar  2 11:02:15 2001
@@ -125,7 +125,7 @@
 enum xirc_isr {
     TxBufOvr = 0x01,	/* TX Buffer Overflow */
     PktTxed  = 0x02,	/* Packet Transmitted */
-    MACIntr  = 0x04,	/* MAC Interrupt occured */
+    MACIntr  = 0x04,	/* MAC Interrupt occurred */
     TxResGrant = 0x08,	/* Tx Reservation Granted */
     RxFullPkt = 0x20,	/* Rx Full Packet */
     RxPktRej  = 0x40,	/* Rx Packet Rejected */
@@ -382,6 +382,7 @@
 static void do_powerdown(struct net_device *dev);
 static int do_stop(struct net_device *dev);
 
+
 /*=============== Helper functions =========================*/
 static void
 flush_stale_links(void)
@@ -1350,7 +1351,6 @@
 	     * packets */
 	    lp->stats.rx_dropped++;
 	    DEBUG(2, "%s: RX drop, too much done\n", dev->name);
-	    PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
 	} else if (rsr & PktRxOk) {
 	    struct sk_buff *skb;
 
@@ -1420,13 +1420,13 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		skb->dev = dev;
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
 		lp->stats.rx_bytes += pktlen;
 		if (!(rsr & PhyPkt))
 		    lp->stats.multicast++;
 	    }
-	    PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
-	} else {
+	} else { /* bad packet */
 	    DEBUG(5, "rsr=%#02x\n", rsr);
 	}
 	if (rsr & PktTooLong) {
@@ -1441,6 +1441,9 @@
 	    lp->stats.rx_fifo_errors++; /* okay ? */
 	    DEBUG(3, "%s: Alignment error\n", dev->name);
 	}
+	
+	/* clear the received/dropped/error packet */
+	PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
 
 	/* get the new ethernet status */
 	eth_status = GetByte(XIRCREG_ESR);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c
--- v2.4.2/linux/drivers/net/pcmcia/xircom_tulip_cb.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcmcia/xircom_tulip_cb.c	Tue Mar 20 12:05:00 2001
@@ -503,10 +503,11 @@
 }
 
 static struct net_device *tulip_probe1(struct pci_dev *pdev,
-				       struct net_device *dev, long ioaddr, int irq,
+				       long ioaddr, int irq,
 				       int chip_idx, int board_idx)
 {
 	static int did_version;			/* Already printed version info. */
+	struct net_device *dev;
 	struct tulip_private *tp;
 	/* See note below on the multiport cards. */
 	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
@@ -519,7 +520,9 @@
 	if (tulip_debug > 0  &&  did_version++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	dev = init_etherdev(dev, 0);
+	dev = init_etherdev(NULL, 0);
+	if (!dev)
+		return NULL;
 
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
 	/* Bring the 21143 out of sleep mode.
@@ -3081,8 +3084,7 @@
 	if (pci_enable_device (pdev))
 		return -ENODEV;
 	pci_set_master (pdev);
-	dev = tulip_probe1(pdev, NULL,
-			   pci_resource_start (pdev, 0), pdev->irq,
+	dev = tulip_probe1(pdev, pci_resource_start (pdev, 0), pdev->irq,
 			   id->driver_data, board_idx++);
 	if (dev) {
 		pdev->driver_data = dev;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.4.2/linux/drivers/net/pcnet32.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pcnet32.c	Tue Mar 20 12:05:00 2001
@@ -12,6 +12,14 @@
  *
  *	This driver is for PCnet32 and PCnetPCI based ethercards
  */
+/**************************************************************************
+ *  23 Oct, 2000.
+ *  Fixed a few bugs, related to running the controller in 32bit mode.
+ *
+ *  Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *************************************************************************/
 
 static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n";
 
@@ -421,7 +429,7 @@
 static int pcnet32_dwio_check (unsigned long addr)
 {
     outl (88, addr+PCNET32_DWIO_RAP);
-    return (inl (addr+PCNET32_DWIO_RAP) == 88);
+    return ((inl (addr+PCNET32_DWIO_RAP) & 0xffff) == 88);
 }
 
 static struct pcnet32_access pcnet32_dwio = {
@@ -482,6 +490,12 @@
 
     printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
 
+    if ((err = pci_enable_device(pdev)) < 0) {
+	printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err);
+	return err;
+    }
+    pci_set_master(pdev);
+
     ioaddr = pci_resource_start (pdev, 0);
     printk(KERN_INFO "    ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
     if (!ioaddr) {
@@ -494,13 +508,6 @@
 	return -ENODEV;
     }
 
-    if ((err = pci_enable_device(pdev)) < 0) {
-	printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err);
-	return err;
-    }
-    
-    pci_set_master(pdev);
-    
     return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev);
 }
 
@@ -528,11 +535,13 @@
     pcnet32_dwio_reset(ioaddr);
     pcnet32_wio_reset(ioaddr);
 
-    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
-	a = &pcnet32_wio;
+    /* Important to do the check for dwio mode first. */
+    if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+        a = &pcnet32_dwio;
     } else {
-	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
-	    a = &pcnet32_dwio;
+        if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && 
+	    pcnet32_wio_check(ioaddr)) {
+	    a = &pcnet32_wio;
 	} else
 	    return -ENODEV;
     }
@@ -624,10 +633,35 @@
 
     printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
 
-    /* There is a 16 byte station address PROM at the base address.
-       The first six bytes are the station address. */
+    /* In most chips, after a chip reset, the ethernet address is read from the
+     * station address PROM at the base address and programmed into the
+     * "Physical Address Registers" CSR12-14.
+     * As a precautionary measure, we read the PROM values and complain if
+     * they disagree with the CSRs.  Either way, we use the CSR values, and
+     * double check that they are valid.
+     */
+    for (i = 0; i < 3; i++) {
+	unsigned int val;
+	val = a->read_csr(ioaddr, i+12) & 0x0ffff;
+	/* There may be endianness issues here. */
+	dev->dev_addr[2*i] = val & 0x0ff;
+	dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff;
+    }
+    {
+	u8 promaddr[6];
+	for (i = 0; i < 6; i++) {
+	    promaddr[i] = inb(ioaddr + i);
+	}
+	if( memcmp( promaddr, dev->dev_addr, 6) )
+	    printk(" warning: PROM address does not match CSR address");
+    }
+    /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
+    if( !is_valid_ether_addr(dev->dev_addr) )
+	for (i = 0; i < 6; i++)
+	    dev->dev_addr[i]=0;
+
     for (i = 0; i < 6; i++)
-	printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+	printk(" %2.2x", dev->dev_addr[i] );
 
     if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */
 	i = a->read_csr(ioaddr, 80) & 0x0C00;  /* Check tx_start_pt */
@@ -775,6 +809,10 @@
 	return -EAGAIN;
     }
 
+    /* Check for a valid station address */
+    if( !is_valid_ether_addr(dev->dev_addr) )
+	return -EINVAL;
+
     /* Reset the PCNET32 */
     lp->a.reset (ioaddr);
 
@@ -818,6 +856,12 @@
 	if (lp->options & PORT_100)
 	    val |= 0x08;
 	lp->a.write_bcr (ioaddr, 32, val);
+    } else {
+	if (lp->options & PORT_ASEL) {  /* enable auto negotiate, setup, disable fd */
+		val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
+		val |= 0x20;
+		lp->a.write_bcr(ioaddr, 32, val);
+	}
     }
 
 #ifdef DO_DXSUFLO 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/pppoe.c linux/drivers/net/pppoe.c
--- v2.4.2/linux/drivers/net/pppoe.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/pppoe.c	Tue Mar  6 19:44:35 2001
@@ -737,7 +737,7 @@
 		err = 0;
 		break;
 
-	default:
+	default:;
 	};
 
 	return err;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/rclanmtl.h linux/drivers/net/rclanmtl.h
--- v2.4.2/linux/drivers/net/rclanmtl.h	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/rclanmtl.h	Tue Mar  6 19:28:34 2001
@@ -97,7 +97,7 @@
 typedef void (*PFNTXCALLBACK)(U32  Status,
                               U16  PcktCount,
                               PU32 BufferContext,
-                              U16  AdaterID);
+                              struct net_device *);
 
  /* 
  ** type PFNRXCALLBACK 
@@ -445,7 +445,7 @@
  /*
  ** Disable and Enable I2O interrupts.  I2O interrupts are enabled at Init time
  ** but can be disabled and re-enabled through these two function calls.
- ** Packets will still be put into any posted recieved buffers and packets will
+ ** Packets will still be put into any posted received buffers and packets will
  ** be sent through RCI2OSendPacket() functions.  Disabling I2O interrupts
  ** will prevent hardware interrupt to host even though the outbound I2O msg
  ** queue is not emtpy.
diff -u --recursive --new-file v2.4.2/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.4.2/linux/drivers/net/rcpci45.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/rcpci45.c	Tue Mar 20 12:05:01 2001
@@ -119,7 +119,7 @@
 
 static void __exit rcpci45_remove_one(struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	PDPA pDpa = dev->priv;
 
         if (!dev) {
@@ -134,10 +134,12 @@
   	unregister_netdev(dev);
 	free_irq(dev->irq, dev); 
 	iounmap((void *)dev->base_addr);
+	pci_release_regions(pdev);
 	kfree(pDpa->PLanApiPA);
 	kfree(pDpa->pPab);
 	kfree(pDpa);
 	kfree(dev);
+	pci_set_drvdata(pdev, NULL);
 }
 
 static int RCinit(struct net_device *dev)
@@ -156,12 +158,10 @@
 {
     unsigned long *vaddr;
     PDPA pDpa;
-    int error = -ENOMEM;
+    int error;
     static int card_idx = -1;
     struct net_device *dev;
-    unsigned long pci_start = pci_resource_start(pdev,0);
-    unsigned long pci_len = pci_resource_len(pdev,0);
-    
+    unsigned long pci_start, pci_len;
 
     card_idx++;
 
@@ -177,10 +177,20 @@
     dev = init_etherdev(NULL, sizeof(*pDpa));
     if (!dev) {
 	printk(KERN_ERR "(rcpci45 driver:) unable to allocate in init_etherdev\n");
+        error = -ENOMEM;
+	goto err_out;
+    }
+
+    error = pci_enable_device(pdev);
+    if (error) {
+        printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx);
 	goto err_out;
     }
+    error = -ENOMEM;
+    pci_start = pci_resource_start(pdev,0);
+    pci_len = pci_resource_len(pdev,0);
 
-    pdev->driver_data = dev;
+    pci_set_drvdata(pdev, dev);
     
     pDpa = dev->priv;
     pDpa->id = card_idx;
@@ -188,6 +198,7 @@
 
     if (!pci_start || !(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
 	printk(KERN_ERR "(rcpci45 driver:) No PCI memory resources! Aborting.\n");
+	error = -EBUSY;
 	goto err_out_free_dev;
     }    
 
@@ -214,20 +225,14 @@
      * I/O read/write.  Thus, we need to map it to some virtual address
      * area in order to access the registers as normal memory.
      */
-    if (request_mem_region(pci_start, pci_len, dev->name) == NULL) {
-        printk(KERN_ERR "(rcpci45 driver:) %d: resource 0x%lx @ 0x%lx busy, aborting\n",card_idx, pci_start, pci_len);
-	goto err_out_free_msgbuf;
-    }
-
-    if (pci_enable_device(pdev)) {
-        printk(KERN_ERR "(rcpci45 driver:) %d: unable to enable pci device, aborting\n",card_idx);
-	goto err_out_free_msgbuf;
-    }
+    error = pci_request_regions(pdev, dev->name);
+    if (error)
+    	goto err_out_free_msgbuf;
 
     vaddr = (ulong *) ioremap (pci_start, pci_len); 
     if (!vaddr) {
         printk(KERN_ERR "(rcpci45 driver:) Unable to remap address range from %lu to %lu\n", pci_start, pci_start+pci_len);
-	goto err_out_free_msgbuf;
+	goto err_out_free_region;
     }
 
     dprintk("rcpci45_init_one: 0x%x, priv = 0x%x, vaddr = 0x%x\n", 
@@ -239,13 +244,14 @@
 
     return 0; /* success */
 
-
+ err_out_free_region:
+    pci_release_regions(pdev);
  err_out_free_msgbuf:
     kfree(pDpa->msgbuf);
  err_out_free_dev:
+    unregister_netdev(dev);
     kfree(dev);
  err_out:
-    unregister_netdev(dev);
     card_idx--;
     return error;
 }
@@ -278,8 +284,8 @@
     dprintk("(rcpci45 driver:) RCopen\n");
 
     /* Request a shared interrupt line. */
-    if ( (error=request_irq(dev->irq, (void *)RCinterrupt,
-                     SA_INTERRUPT|SA_SHIRQ, "RedCreek VPN Adapter", dev)) ) {
+    error=request_irq(dev->irq, RCinterrupt, SA_SHIRQ, dev->name, dev);
+    if (error) {
         printk(KERN_ERR "(rcpci45 driver:) %s: unable to get IRQ %d\n", dev->name, dev->irq );
 	goto err_out;
     }
@@ -384,7 +390,7 @@
 
     /* 
      * we'll get the context when the adapter interrupts us to tell us that
-     * the transmision is done. At that time, we can free skb.
+     * the transmission is done. At that time, we can free skb.
      */
     ptcb->b.context = (U32)skb;    
     ptcb->b.scount = 1;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c
--- v2.4.2/linux/drivers/net/rtl8129.c	Sun Sep 17 09:41:29 2000
+++ linux/drivers/net/rtl8129.c	Wed Dec 31 16:00:00 1969
@@ -1,1483 +0,0 @@
-/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */
-/*
-	Written 1997-1999 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU Public License, incorporated herein by reference.
-    All other rights reserved.
-
-	This driver is for boards based on the RTL8129 PCI ethernet chip.
-
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
-	Support and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html
-
-	Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.
-*/
-
-static const char *version =
-"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
-
-/* A few user-configurable values. */
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-#define rtl8129_debug debug
-static int rtl8129_debug = 1;
-
-/* 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;
-
-/* Used to pass the full-duplex flag, etc. */
-#define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Size of the in-memory receive ring. */
-#define RX_BUF_LEN_IDX	3			/* 0==8K, 1==16K, 2==32K, 3==64K */
-#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
-/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
-#define TX_BUF_SIZE	1536
-
-/* PCI Tuning Parameters
-   Threshold is bytes transferred to chip before transmission starts. */
-#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
-
-/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */
-#define RX_FIFO_THRESH	4		/* Rx buffer level before first PCI xfer.  */
-#define RX_DMA_BURST	4		/* Maximum PCI burst, '4' is 256 bytes */
-#define TX_DMA_BURST	4		/* Calculate as 16<<val. */
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (4*HZ)
-
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#include <linux/delay.h>
-
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define	net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-
-/* The I/O extent. */
-#define RTL8129_TOTAL_SIZE 0x80
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver is designed for the RealTek RTL8129, the RealTek Fast
-Ethernet controllers for PCI.  This chip is used on a few clone boards.
-
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS will assign the
-PCI INTA signal to a (preferably otherwise unused) system IRQ line.
-Note: Kernel versions earlier than 1.3.73 do not support shared PCI
-interrupt lines.
-
-III. Driver operation
-
-IIIa. Rx Ring buffers
-
-The receive unit uses a single linear ring buffer rather than the more
-common (and more efficient) descriptor-based architecture.  Incoming frames
-are sequentially stored into the Rx region, and the host copies them into
-skbuffs.
-
-Comment: While it is theoretically possible to process many frames in place,
-any delay in Rx processing would cause us to drop frames.  More importantly,
-the Linux protocol stack is not designed to operate in this manner.
-
-IIIb. Tx operation
-
-The RTL8129 uses a fixed set of four Tx descriptors in register space.
-In a stunningly bad design choice, Tx frames must be 32 bit aligned.  Linux
-aligns the IP header on word boundaries, and 14 byte ethernet header means
-that almost all frames will need to be copied to an alignment buffer.
-
-IVb. References
-
-http://www.realtek.com.tw/cn/cn.html
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-
-IVc. Errata
-
-*/
-
-
-/* This table drives the PCI probe routines.  It's mostly boilerplate in all
-   of the drivers, and will likely be provided by some future kernel.
-   Note the matching code -- the first table entry matchs all 56** cards but
-   second only the 1234 card.
-*/
-enum pci_flags_bit {
-	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-struct pci_id_info {
-	const char *name;
-	u16	vendor_id, device_id, device_id_mask, flags;
-	int io_size;
-	struct net_device *(*probe1)(struct pci_dev *pdev, int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-};
-
-static struct net_device * rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
-										  int pci_devfn, long ioaddr,
-										  int irq, int chp_idx, int fnd_cnt);
-
-static struct pci_id_info pci_tbl[] =
-{{ "RealTek RTL8129 Fast Ethernet",
-   0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
-#ifdef USE_8139_SUPPORT_ALSO
- { "RealTek RTL8139 Fast Ethernet",
-   0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
-   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
- { "Accton MPX5030 (RealTek RTL8139)",
-   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
-#endif
- {0,},						/* 0 terminated list. */
-};
-
-/* The capability table matches the chip table above. */
-enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
-static int rtl_cap_tbl[] = {
-	HAS_MII_XCVR, HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
-};
-
-
-/* The rest of these values should never change. */
-#define NUM_TX_DESC	4			/* Number of Tx descriptor registers. */
-
-/* Symbolic offsets to registers. */
-enum RTL8129_registers {
-	MAC0=0,						/* Ethernet hardware address. */
-	MAR0=8,						/* Multicast filter. */
-	TxStatus0=0x10,				/* Transmit status (Four 32bit registers). */
-	TxAddr0=0x20,				/* Tx descriptors (also four 32bit). */
-	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,
-	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,
-	IntrMask=0x3C, IntrStatus=0x3E,
-	TxConfig=0x40, RxConfig=0x44,
-	Timer=0x48,					/* A general-purpose counter. */
-	RxMissed=0x4C,				/* 24 bits valid, write clears. */
-	Cfg9346=0x50, Config0=0x51, Config1=0x52,
-	FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,
-	MultiIntr=0x5C, TxSummary=0x60,
-	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,
-	NWayExpansion=0x6A,
-	/* Undocumented registers, but required for proper operation. */
-	FIFOTMS=0x70,	/* FIFO Test Mode Select */
-	CSCR=0x74,	/* Chip Status and Configuration Register. */
-	PARA78=0x78, PARA7c=0x7c,	/* Magic transceiver parameter register. */
-};
-
-enum ChipCmdBits {
-	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
-	PCIErr=0x8000, PCSTimeout=0x4000,
-	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,
-	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,
-};
-enum TxStatusBits {
-	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,
-	TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,
-};
-enum RxStatusBits {
-	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,
-	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,
-	RxBadAlign=0x0002, RxStatusOK=0x0001,
-};
-
-/* Twister tuning parameters from RealTek.
-   Completely undocumented, but required to tune bad links. */
-enum CSCRBits {
-	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,
-	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,
-	CSCR_LinkDownCmd=0x0f3c0,
-};
-static const unsigned long param[4][4]={
-	{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},
-	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
-	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},
-	{0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}
-};
-
-struct ring_info {
-	struct sk_buff *skb;
-	dma_addr_t mapping;
-};
-
-struct rtl8129_private {
-	char devname[8];			/* Used only for kernel debugging. */
-	const char *product_name;
-	struct net_device *next_module;
-	struct pci_dev *pdev;
-	int chip_id;
-	int chip_revision;
-	unsigned char pci_bus, pci_devfn;
-	struct net_device_stats stats;
-	struct timer_list timer;	/* Media selection timer. */
-	unsigned int cur_rx;		/* Index into the Rx buffer of next Rx pkt. */
-	unsigned int cur_tx, dirty_tx, tx_flag;
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	struct ring_info tx_info[NUM_TX_DESC];
-	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
-	unsigned char *rx_ring;
-	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
-	dma_addr_t rx_ring_dma;
-	dma_addr_t tx_bufs_dma;
-	char phys[4];						/* MII device addresses. */
-	char twistie, twist_cnt;			/* Twister tune state. */
-	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 default_port:4;		/* Last dev->if_port value. */
-	unsigned int media2:4;				/* Secondary monitored media port. */
-	unsigned int medialock:1;			/* Don't sense media type. */
-	unsigned int mediasense:1;			/* Media sensing in progress. */
-};
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(multicast_filter_limit, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(debug, "i");
-
-static int rtl8129_open(struct net_device *dev);
-static int read_eeprom(long ioaddr, int location);
-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 val);
-static void rtl8129_timer(unsigned long data);
-static void rtl8129_tx_timeout(struct net_device *dev);
-static void rtl8129_init_ring(struct net_device *dev);
-static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int rtl8129_rx(struct net_device *dev);
-static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int rtl8129_close(struct net_device *dev);
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *rtl8129_get_stats(struct net_device *dev);
-static inline u32 ether_crc(int length, unsigned char *data);
-static void set_rx_mode(struct net_device *dev);
-
-
-/* A list of all installed RTL8129 devices, for removing the driver module. */
-static struct net_device *root_rtl8129_dev = NULL;
-
-/* Ideally we would detect all network cards in slot order.  That would
-   be best done a central PCI probe dispatch, which wouldn't work
-   well when dynamically adding drivers.  So instead we detect just the
-   Rtl81*9 cards in slot order. */
-
-static int __init rtl8129_probe(void)
-{
-	int cards_found = 0;
-	int pci_index = 0;
-	unsigned char pci_bus, pci_device_fn;
-	struct net_device *dev;
-
-	if ( ! pcibios_present())
-		return -ENODEV;
-
-	for (; pci_index < 0xff; pci_index++) {
-		struct pci_dev *pdev;
-		u16 vendor, device, pci_command, new_command;
-		int chip_idx, irq;
-		long ioaddr;
-
-		if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-								&pci_bus, &pci_device_fn)
-			!= PCIBIOS_SUCCESSFUL)
-			break;
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_VENDOR_ID, &vendor);
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_DEVICE_ID, &device);
-
-		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-			if (vendor == pci_tbl[chip_idx].vendor_id
-				&& (device & pci_tbl[chip_idx].device_id_mask) ==
-				pci_tbl[chip_idx].device_id)
-				break;
-		if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
-			continue;
-
-		pdev = pci_find_slot(pci_bus, pci_device_fn);
-
-		ioaddr = pci_resource_start(pdev, 0);
-		irq = pdev->irq;
-
-		if (pci_enable_device(pdev))
-			continue;
-
-		if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
-			check_region(ioaddr, pci_tbl[chip_idx].io_size))
-			continue;
-
-		/* Activate the card: fix for brain-damaged Win98 BIOSes. */
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_COMMAND, &pci_command);
-		new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled the"
-				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_bus, pci_device_fn, pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-									  PCI_COMMAND, new_command);
-		}
-
-		dev = pci_tbl[chip_idx].probe1(pdev, pci_bus, pci_device_fn, ioaddr, irq, chip_idx, cards_found);
-
-		if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
-			u8 pci_latency;
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < 32) {
-				printk(KERN_NOTICE "  PCI latency timer (CFLT) is "
-					   "unreasonably low at %d.  Setting to 64 clocks.\n",
-					   pci_latency);
-				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										  PCI_LATENCY_TIMER, 64);
-			}
-		}
-		dev = 0;
-		cards_found++;
-	}
-
-	return cards_found ? 0 : -ENODEV;
-}
-
-static struct net_device *rtl8129_probe1(struct pci_dev *pdev, int pci_bus,
-										 int pci_devfn, long ioaddr,
-										 int irq, int chip_idx, int found_cnt)
-{
-	static int did_version = 0;			/* Already printed version info. */
-	struct rtl8129_private *tp;
-	int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;
-	struct net_device *dev;
-
-	if (rtl8129_debug > 0  &&  did_version++ == 0)
-		printk(KERN_INFO "%s", version);
-
-	dev = init_etherdev(NULL, 0);
-	if (dev == NULL)
-		goto out;
-
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-		   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);
-
-	/* Bring the chip out of low-power mode. */
-	outb(0x00, ioaddr + Config1);
-
-	if (read_eeprom(ioaddr, 0) != 0xffff) {
-		for (i = 0; i < 3; i++) {
-			((u16 *)(dev->dev_addr))[i] =
-				le16_to_cpu(read_eeprom(ioaddr, i + 7));
-		}
-	} else {
-		for (i = 0; i < 6; i++)
-			dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
-	}
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x.\n", dev->dev_addr[i]);
-
-	/* We do a request_region() to register /proc/ioports info. */
-	if (!request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name))
-		goto out_free_dev;
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	/* Some data structures must be quadword aligned. */
-	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);
-	if (tp == NULL)
-		goto out_release_region;
-
-	memset(tp, 0, sizeof(*tp));
-	dev->priv = tp;
-
-	tp->next_module = root_rtl8129_dev;
-	root_rtl8129_dev = dev;
-
-	tp->pdev = pdev;
-	tp->chip_id = chip_idx;
-	tp->pci_bus = pci_bus;
-	tp->pci_devfn = pci_devfn;
-
-	/* Find the connected MII xcvrs.
-	   Doing this in open() would allow detecting external xcvrs later, but
-	   takes too much time. */
-	if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) {
-		int phy, phy_idx;
-		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
-			 phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
-			if (mii_status != 0xffff  && mii_status != 0x0000) {
-				tp->phys[phy_idx++] = phy;
-				printk(KERN_INFO "%s: MII transceiver found at address %d.\n",
-					   dev->name, phy);
-			}
-		}
-		if (phy_idx == 0) {
-			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
-				   "transceiver.\n",
-				   dev->name);
-			tp->phys[0] = -1;
-		}
-	} else
-		tp->phys[0] = 32;
-
-	/* Put the chip into low-power mode. */
-	outb(0xC0, ioaddr + Cfg9346);
-	outb(0x03, ioaddr + Config1);
-	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
-
-	/* The lower four bits are the media type. */
-	if (option > 0) {
-		tp->full_duplex = (option & 0x200) ? 1 : 0;
-		tp->default_port = option & 15;
-		if (tp->default_port)
-			tp->medialock = 1;
-	}
-
-	if (found_cnt < MAX_UNITS  &&  full_duplex[found_cnt] > 0)
-		tp->full_duplex = full_duplex[found_cnt];
-
-	if (tp->full_duplex) {
-		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
-		mdio_write(dev, tp->phys[0], 4, 0x141);
-		tp->duplex_lock = 1;
-	}
-
-	/* The Rtl8129-specific entries in the device structure. */
-	dev->open = &rtl8129_open;
-	dev->hard_start_xmit = &rtl8129_start_xmit;
-	dev->tx_timeout = &rtl8129_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->stop = &rtl8129_close;
-	dev->get_stats = &rtl8129_get_stats;
-	dev->set_multicast_list = &set_rx_mode;
-	dev->do_ioctl = &mii_ioctl;
-	return dev;
-
-out_release_region:
-	release_region(ioaddr, pci_tbl[chip_idx].io_size);
-out_free_dev:
-	unregister_netdev(dev);
-	kfree(dev);
-out:
-	return NULL;
-}
-
-/* Serial EEPROM section. */
-
-/*  EEPROM_Ctrl bits. */
-#define EE_SHIFT_CLK	0x04	/* EEPROM shift clock. */
-#define EE_CS			0x08	/* EEPROM chip select. */
-#define EE_DATA_WRITE	0x02	/* EEPROM chip data in. */
-#define EE_WRITE_0		0x00
-#define EE_WRITE_1		0x02
-#define EE_DATA_READ	0x01	/* EEPROM chip data out. */
-#define EE_ENB			(0x80 | EE_CS)
-
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
- */
-
-#define eeprom_delay()	inl(ee_addr)
-
-/* The EEPROM commands include the alway-set leading bit. */
-#define EE_WRITE_CMD	(5 << 6)
-#define EE_READ_CMD		(6 << 6)
-#define EE_ERASE_CMD	(7 << 6)
-
-static int read_eeprom(long ioaddr, int location)
-{
-	int i;
-	unsigned retval = 0;
-	long ee_addr = ioaddr + Cfg9346;
-	int read_cmd = location | EE_READ_CMD;
-
-	outb(EE_ENB & ~EE_CS, ee_addr);
-	outb(EE_ENB, ee_addr);
-
-	/* Shift the read command bits out. */
-	for (i = 10; i >= 0; i--) {
-		int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-		outb(EE_ENB | dataval, ee_addr);
-		eeprom_delay();
-		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
-	}
-	outb(EE_ENB, ee_addr);
-	eeprom_delay();
-
-	for (i = 16; i > 0; i--) {
-		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
-		retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
-		outb(EE_ENB, ee_addr);
-		eeprom_delay();
-	}
-
-	/* Terminate the EEPROM access. */
-	outb(~EE_CS, ee_addr);
-	return retval;
-}
-
-/* MII serial management: mostly bogus for now. */
-/* Read and write the MII management registers using software-generated
-   serial MDIO protocol.
-   The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues. */
-#define MDIO_DIR		0x80
-#define MDIO_DATA_OUT	0x04
-#define MDIO_DATA_IN	0x02
-#define MDIO_CLK		0x01
-#define MDIO_WRITE0 (MDIO_DIR)
-#define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
-
-#define mdio_delay()	inb(mdio_addr)
-
-static char mii_2_8139_map[8] = {MII_BMCR, MII_BMSR, 0, 0, NWayAdvert,
-								 NWayLPAR, NWayExpansion, 0 };
-
-/* Syncronize the MII management interface by shifting 32 one bits out. */
-static void mdio_sync(long mdio_addr)
-{
-	int i;
-
-	for (i = 32; i >= 0; i--) {
-		outb(MDIO_WRITE1, mdio_addr);
-		mdio_delay();
-		outb(MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return;
-}
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	long mdio_addr = dev->base_addr + MII_SMI;
-	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	int retval = 0;
-	int i;
-
-	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		return location < 8 && mii_2_8139_map[location] ?
-			inw(dev->base_addr + mii_2_8139_map[location]) : 0;
-	}
-	mdio_sync(mdio_addr);
-	/* Shift the read command bits out. */
-	for (i = 15; i >= 0; i--) {
-		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
-
-		outb(MDIO_DIR | dataval, mdio_addr);
-		mdio_delay();
-		outb(MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outb(0, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inb(mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
-		outb(MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	long mdio_addr = dev->base_addr + MII_SMI;
-	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-	int i;
-
-	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		if (location < 8  &&  mii_2_8139_map[location])
-			outw(value, dev->base_addr + mii_2_8139_map[location]);
-		return;
-	}
-	mdio_sync(mdio_addr);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-		outb(dataval, mdio_addr);
-		mdio_delay();
-		outb(dataval | MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Clear out extra bits. */
-	for (i = 2; i > 0; i--) {
-		outb(0, mdio_addr);
-		mdio_delay();
-		outb(MDIO_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return;
-}
-
-
-static int
-rtl8129_open(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int i, retval;
-
-	MOD_INC_USE_COUNT;
-
-	/* Soft reset the chip. */
-	outb(CmdReset, ioaddr + ChipCmd);
-
-	if ((retval = request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev))) {
-		MOD_DEC_USE_COUNT;
-		return retval;
-	}
-
-	tp->tx_bufs = pci_alloc_consistent(tp->pdev,
-									   TX_BUF_SIZE * NUM_TX_DESC,
-									   &tp->tx_bufs_dma);
-	tp->rx_ring = pci_alloc_consistent(tp->pdev,
-									   RX_BUF_LEN + 16,
-									   &tp->rx_ring_dma);
-	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {
-		free_irq(dev->irq, dev);
-		if (tp->tx_bufs)
-			pci_free_consistent(tp->pdev,
-								TX_BUF_SIZE * NUM_TX_DESC,
-								tp->tx_bufs, tp->tx_bufs_dma);
-		if (tp->rx_ring)
-			pci_free_consistent(tp->pdev,
-								RX_BUF_LEN + 16,
-								tp->rx_ring, tp->rx_ring_dma);
-		if (rtl8129_debug > 0)
-			printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
-				   dev->name, RX_BUF_LEN);
-		MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-	rtl8129_init_ring(dev);
-
-	/* Check that the chip has finished the reset. */
-	for (i = 1000; i > 0; i--)
-		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
-			break;
-
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
-
-	/* Must enable Tx/Rx before setting transfer thresholds! */
-	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
-		 ioaddr + RxConfig);
-	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
-	tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;
-
-	tp->full_duplex = tp->duplex_lock;
-	if (tp->phys[0] >= 0  ||  (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) {
-		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-		if (mii_reg5 == 0xffff)
-			;					/* Not there */
-		else if ((mii_reg5 & 0x0100) == 0x0100
-				 || (mii_reg5 & 0x00C0) == 0x0040)
-			tp->full_duplex = 1;
-		if (rtl8129_debug > 1)
-			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
-				   " auto-negotiated partner ability %4.4x.\n", dev->name,
-				   mii_reg5 == 0 ? "" :
-				   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
-				   tp->full_duplex ? "full" : "half", mii_reg5);
-	}
-
-	outb(0xC0, ioaddr + Cfg9346);
-	outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-	outb(0x00, ioaddr + Cfg9346);
-
-	outl(tp->rx_ring_dma, ioaddr + RxBuf);
-
-	/* Start the chip's Tx and Rx process. */
-	outl(0, ioaddr + RxMissed);
-	set_rx_mode(dev);
-
-	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-
-	/* Enable all known interrupts by setting the interrupt mask. */
-	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
-
-	if (rtl8129_debug > 1)
-		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
-			   " GP Pins %2.2x %s-duplex.\n",
-			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
-			   tp->full_duplex ? "full" : "half");
-
-	/* Set the timer to switch to check for link beat and perhaps switch
-	   to an alternate media type. */
-	init_timer(&tp->timer);
-	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
-	tp->timer.data = (unsigned long)dev;
-	tp->timer.function = &rtl8129_timer;
-	add_timer(&tp->timer);
-
-	return 0;
-}
-
-static void rtl8129_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int next_tick = 60*HZ;
-	int mii_reg5 = mdio_read(dev, tp->phys[0], 5);
-
-	if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {
-		int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
-		if (tp->full_duplex != duplex) {
-			tp->full_duplex = duplex;
-			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
-				   " partner ability of %4.4x.\n", dev->name,
-				   tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);
-			outb(0xC0, ioaddr + Cfg9346);
-			outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-			outb(0x00, ioaddr + Cfg9346);
-		}
-	}
-	/* Check for bogusness. */
-	if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
-		int status = inw(ioaddr + IntrStatus);
-		if (status & (TxOK | RxOK)) {	/* Double check */
-			printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n",
-				   dev->name, status);
-			rtl8129_interrupt(dev->irq, dev, 0);
-		}
-	}
-	if (netif_queue_stopped(dev) &&
-		(jiffies - dev->trans_start) >= 2*TX_TIMEOUT)
-		rtl8129_tx_timeout(dev);
-
-#if 0
-	if (tp->twistie) {
-		unsigned int CSCRval = inw(ioaddr + CSCR);		/* Read link status. */
-		if (tp->twistie == 1) {
-			if (CSCRval & CSCR_LinkOKBit) {
-				outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);
-				tp->twistie = 2;
-				next_tick = HZ/10;
-			} else {
-				outw(CSCR_LinkDownCmd, ioaddr + CSCR);
-				outl(FIFOTMS_default,ioaddr + FIFOTMS);
-				outl(PARA78_default ,ioaddr + PARA78);
-				outl(PARA7c_default ,ioaddr + PARA7c);
-				tp->twistie = 0;
-			}
-		} else if (tp->twistie == 2) {
-			int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12;
-			int row;
-			if (linkcase >= 0x7000) row = 3;
-			else if (linkcase >= 0x3000) row = 2;
-			else if (linkcase >= 0x1000) row = 1;
-			else row = 0;
-			tp->twistie == row + 3;
-			outw(0,ioaddr+FIFOTMS);
-			outl(param[row][0], ioaddr+PARA7c);
-			tp->twist_cnt = 1;
-		} else {
-			outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c);
-			if (++tp->twist_cnt < 4) {
-				next_tick = HZ/10;
-			} else if (tp->twistie-3 == 3) {
-				if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) {
-					outl(PARA7c_xxx, ioaddr+PARA7c);
-					next_tick = HZ/10; 		/* 100ms. */
-					outl(FIFOTMS_default, ioaddr+FIFOTMS);
-					outl(PARA78_default,  ioaddr+PARA78);
-					outl(PARA7c_default,  ioaddr+PARA7c);
-					tp->twistie == 3 + 3;
-					outw(0,ioaddr+FIFOTMS);
-					outl(param[3][0], ioaddr+PARA7c);
-					tp->twist_cnt = 1;
-				}
-			}
-		}
-	}
-#endif
-
-	if (rtl8129_debug > 2) {
-		if (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)
-			printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",
-				   dev->name, inb(ioaddr + GPPinData));
-		else
-			printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",
-				   dev->name, inw(ioaddr + NWayLPAR));
-		printk(KERN_DEBUG"%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
-			   " RxStatus %4.4x.\n",
-			   dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),
-			   inl(ioaddr + RxEarlyStatus));
-		printk(KERN_DEBUG"%s:  Chip config %2.2x %2.2x.\n",
-			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));
-	}
-
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
-}
-
-static void rtl8129_tx_timeout(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int mii_reg, i;
-
-	if (rtl8129_debug > 0)
-		printk(KERN_WARNING "%s: Transmit timeout, status %2.2x %4.4x "
-			   "media %2.2x.\n",
-			   dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),
-			   inb(ioaddr + GPPinData));
-
-	/* Disable interrupts by clearing the interrupt mask. */
-	outw(0x0000, ioaddr + IntrMask);
-	/* Emit info to figure out what went wrong. */
-	printk("%s: Tx queue start entry %d  dirty entry %d.\n",
-		   dev->name, tp->cur_tx, tp->dirty_tx);
-	for (i = 0; i < NUM_TX_DESC; i++)
-		printk(KERN_DEBUG"%s:  Tx descriptor %d is %8.8x.%s\n",
-			   dev->name, i, inl(ioaddr + TxStatus0 + i*4),
-			   i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");
-	printk(KERN_DEBUG"%s: MII #%d registers are:", dev->name, tp->phys[0]);
-	for (mii_reg = 0; mii_reg < 8; mii_reg++)
-		printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));
-	printk(".\n");
-
-	/* Soft reset the chip. */
-	outb(CmdReset, ioaddr + ChipCmd);
-	/* Check that the chip has finished the reset. */
-	for (i = 1000; i > 0; i--)
-		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
-			break;
-	for (i = 0; i < 6; i++)
-		outb(dev->dev_addr[i], ioaddr + MAC0 + i);
-
-	outb(0x00, ioaddr + Cfg9346);
-	tp->cur_rx = 0;
-	/* Must enable Tx/Rx before setting transfer thresholds! */
-	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
-		 ioaddr + RxConfig);
-	outl((TX_DMA_BURST<<8), ioaddr + TxConfig);
-	set_rx_mode(dev);
-	{							/* Save the unsent Tx packets. */
-		struct sk_buff *saved_skb[NUM_TX_DESC], *skb;
-		int j;
-		for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) {
-			struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC];
-
-			saved_skb[j] = rp->skb;
-			if (rp->mapping != 0) {
-				pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);
-				rp->mapping = 0;
-			}
-		}
-		tp->dirty_tx = tp->cur_tx = 0;
-
-		for (i = 0; i < j; i++) {
-			skb = tp->tx_info[i].skb = saved_skb[i];
-			if ((long)skb->data & 3) {		/* Must use alignment buffer. */
-				memcpy(tp->tx_buf[i], skb->data, skb->len);
-				outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs),
-					 ioaddr + TxAddr0 + i*4);
-			} else {
-				tp->tx_info[i].mapping =
-					pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-				outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);
-			}
-			/* Note: the chip doesn't have auto-pad! */
-			outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-				 ioaddr + TxStatus0 + i*4);
-		}
-		tp->cur_tx = i;
-		while (i < NUM_TX_DESC) {
-			tp->tx_info[i].skb = NULL;
-			tp->tx_info[i].mapping = 0;
-			i++;
-		}
-		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */
-			netif_wake_queue(dev);
-			tp->tx_full = 0;
-		} else {
-			tp->tx_full = 1;
-			netif_stop_queue(dev);
-		}
-	}
-
-	dev->trans_start = jiffies;
-	tp->stats.tx_errors++;
-	/* Enable all known interrupts by setting the interrupt mask. */
-	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
-		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);
-	return;
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void
-rtl8129_init_ring(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	int i;
-
-	tp->tx_full = 0;
-	tp->cur_rx = 0;
-	tp->dirty_tx = tp->cur_tx = 0;
-
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];
-		tp->tx_info[i].skb = NULL;
-		tp->tx_info[i].mapping = 0;
-	}
-}
-
-static int
-rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	int entry;
-
-	netif_stop_queue(dev);
-
-	/* Calculate the next Tx descriptor entry. */
-	entry = tp->cur_tx % NUM_TX_DESC;
-
-	tp->tx_info[entry].skb = skb;
-	if ((long)skb->data & 3) {			/* Must use alignment buffer. */
-		tp->tx_info[entry].mapping = 0;
-		memcpy(tp->tx_buf[entry], skb->data, skb->len);
-		outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs),
-			 ioaddr + TxAddr0 + entry*4);
-	} else {
-		tp->tx_info[entry].mapping =
-			pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-		outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4);
-	}
-	/* Note: the chip doesn't have auto-pad! */
-	outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),
-		 ioaddr + TxStatus0 + entry*4);
-
-	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {	/* Typical path */
-		netif_start_queue(dev);
-	} else {
-		tp->tx_full = 1;
-	}
-
-	dev->trans_start = jiffies;
-	if (rtl8129_debug > 4)
-		printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",
-			   dev->name, skb->data, (int)skb->len, entry);
-
-	return 0;
-}
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct net_device *dev = (struct net_device *)dev_instance;
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	int boguscnt = max_interrupt_work;
-	int status, link_changed = 0;
-	long ioaddr = dev->base_addr;
-
-	do {
-		status = inw(ioaddr + IntrStatus);
-		/* Acknowledge all of the current interrupt sources ASAP, but
-		   an first get an additional status bit from CSCR. */
-		if ((status & RxUnderrun)  &&  inw(ioaddr+CSCR) & CSCR_LinkChangeBit)
-			link_changed = 1;
-		outw(status, ioaddr + IntrStatus);
-
-		if (rtl8129_debug > 4)
-			printk(KERN_DEBUG"%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",
-				   dev->name, status, inw(ioaddr + IntrStatus));
-
-		if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver
-					   |TxErr|TxOK|RxErr|RxOK)) == 0)
-			break;
-
-		if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */
-			rtl8129_rx(dev);
-
-		if (status & (TxOK | TxErr)) {
-			unsigned int dirty_tx = tp->dirty_tx;
-
-			while (tp->cur_tx - dirty_tx > 0) {
-				int entry = dirty_tx % NUM_TX_DESC;
-				int txstatus = inl(ioaddr + TxStatus0 + entry*4);
-
-				if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))
-					break;			/* It still hasn't been Txed */
-
-				/* Note: TxCarrierLost is always asserted at 100mbps. */
-				if (txstatus & (TxOutOfWindow | TxAborted)) {
-					/* There was an major error, log it. */
-					if (rtl8129_debug > 1)
-						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",
-							   dev->name, txstatus);
-					tp->stats.tx_errors++;
-					if (txstatus&TxAborted) {
-						tp->stats.tx_aborted_errors++;
-						outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);
-					}
-					if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;
-					if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-					if ((txstatus & 0x0f000000) == 0x0f000000)
-						tp->stats.collisions16++;
-#endif
-				} else {
-					if (txstatus & TxUnderrun) {
-						/* Add 64 to the Tx FIFO threshold. */
-						if (tp->tx_flag <  0x00300000)
-							tp->tx_flag += 0x00020000;
-						tp->stats.tx_fifo_errors++;
-					}
-					tp->stats.collisions += (txstatus >> 24) & 15;
-#if LINUX_VERSION_CODE > 0x20119
-					tp->stats.tx_bytes += txstatus & 0x7ff;
-#endif
-					tp->stats.tx_packets++;
-				}
-
-				if (tp->tx_info[entry].mapping != 0) {
-					pci_unmap_single(tp->pdev,
-									 tp->tx_info[entry].mapping,
-									 tp->tx_info[entry].skb->len,
-									 PCI_DMA_TODEVICE);
-					tp->tx_info[entry].mapping = 0;
-				}
-
-				/* Free the original skb. */
-				dev_kfree_skb_irq(tp->tx_info[entry].skb);
-				tp->tx_info[entry].skb = NULL;
-				if (tp->tx_full) {
-					/* The ring is no longer full, wake the queue. */
-					tp->tx_full = 0;
-					netif_wake_queue(dev);
-				}
-				dirty_tx++;
-			}
-
-#ifndef final_version
-			if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-				printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
-				dirty_tx += NUM_TX_DESC;
-			}
-#endif
-			tp->dirty_tx = dirty_tx;
-		}
-
-		/* Check uncommon events with one test. */
-		if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver
-					  |TxErr|RxErr)) {
-			if (rtl8129_debug > 2)
-				printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",
-					   dev->name, status);
-
-			if (status == 0xffffffff)
-				break;
-			/* Update the error count. */
-			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-			outl(0, ioaddr + RxMissed);
-
-			if ((status & RxUnderrun)  &&  link_changed  &&
-				(rtl_cap_tbl[tp->chip_id] & HAS_LNK_CHNG)) {
-				/* Really link-change on new chips. */
-				int lpar = inw(ioaddr + NWayLPAR);
-				int duplex = (lpar&0x0100)||(lpar & 0x01C0) == 0x0040; 
-				if (tp->full_duplex != duplex) {
-					tp->full_duplex = duplex;
-					outb(0xC0, ioaddr + Cfg9346);
-					outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
-					outb(0x00, ioaddr + Cfg9346);
-				}
-				status &= ~RxUnderrun;
-			}
-			if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
-				tp->stats.rx_errors++;
-
-			if (status & (PCSTimeout)) tp->stats.rx_length_errors++;
-			if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;
-			if (status & RxOverflow) {
-				tp->stats.rx_over_errors++;
-				tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;
-				outw(tp->cur_rx - 16, ioaddr + RxBufPtr);
-			}
-			if (status & PCIErr) {
-				u32 pci_cmd_status;
-				pcibios_read_config_dword(tp->pci_bus, tp->pci_devfn,
-										  PCI_COMMAND, &pci_cmd_status);
-
-				printk(KERN_ERR "%s: PCI Bus error %4.4x.\n",
-					   dev->name, pci_cmd_status);
-			}
-		}
-		if (--boguscnt < 0) {
-			printk(KERN_WARNING"%s: Too much work at interrupt, "
-				   "IntrStatus=0x%4.4x.\n",
-				   dev->name, status);
-			/* Clear all interrupt sources. */
-			outw(0xffff, ioaddr + IntrStatus);
-			break;
-		}
-	} while (1);
-
-	if (rtl8129_debug > 3)
-		printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",
-			   dev->name, inl(ioaddr + IntrStatus));
-	return;
-}
-
-/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the
-   field alignments and semantics. */
-static int rtl8129_rx(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-	unsigned char *rx_ring = tp->rx_ring;
-	u16 cur_rx = tp->cur_rx;
-
-	if (rtl8129_debug > 4)
-		printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"
-			   " free to %4.4x, Cmd %2.2x.\n",
-			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
-			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
-
-	while ((inb(ioaddr + ChipCmd) & 1) == 0) {
-		int ring_offset = cur_rx % RX_BUF_LEN;
-		u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset));
-		int rx_size = rx_status >> 16;
-
-		if (rtl8129_debug > 4) {
-			int i;
-			printk(KERN_DEBUG"%s:  rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",
-				   dev->name, rx_status, rx_size, cur_rx);
-			printk(KERN_DEBUG"%s: Frame contents ", dev->name);
-			for (i = 0; i < 70; i++)
-				printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i]));
-			printk(".\n");
-		}
-		if (rx_status & RxTooLong) {
-			if (rtl8129_debug > 0)
-				printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",
-					   dev->name, rx_status);
-			tp->stats.rx_length_errors++;
-		} else if (rx_status &
-				   (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {
-			if (rtl8129_debug > 1)
-				printk(KERN_DEBUG"%s: Ethernet frame had errors,"
-					   " status %4.4x.\n", dev->name, rx_status);
-			tp->stats.rx_errors++;
-			if (rx_status & (RxBadSymbol|RxBadAlign))
-				tp->stats.rx_frame_errors++;
-			if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;
-			if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
-			/* Reset the receiver, based on RealTek recommendation. (Bug?) */
-			tp->cur_rx = 0;
-			outb(CmdTxEnb, ioaddr + ChipCmd);
-			outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
-			outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |
-				 (RX_DMA_BURST<<8), ioaddr + RxConfig);
-		} else {
-			/* Malloc up new buffer, compatible with net-2e. */
-			/* Omit the four octet CRC from the length. */
-			struct sk_buff *skb;
-			int pkt_size = rx_size - 4;
-
-			skb = dev_alloc_skb(pkt_size + 2);
-			if (skb == NULL) {
-				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++;
-				break;
-			}
-			skb->dev = dev;
-			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */
-			if (ring_offset+rx_size > RX_BUF_LEN) {
-				int semi_count = RX_BUF_LEN - ring_offset - 4;
-				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
-					   semi_count);
-				memcpy(skb_put(skb, pkt_size-semi_count), rx_ring,
-					   pkt_size-semi_count);
-				if (rtl8129_debug > 4) {
-					int i;
-					printk(KERN_DEBUG"%s:  Frame wrap @%d",
-						   dev->name, semi_count);
-					for (i = 0; i < 16; i++)
-						printk(" %2.2x", le32_to_cpu(rx_ring[i]));
-					printk(".\n");
-					memset(rx_ring, 0xcc, 16);
-				}
-			} else {
-#if 1  /* USE_IP_COPYSUM */
-				eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],
-								 pkt_size, 0);
-				skb_put(skb, pkt_size);
-#else
-				memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4],
-					   pkt_size);
-#endif
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-#if LINUX_VERSION_CODE > 0x20119
-			tp->stats.rx_bytes += pkt_size;
-#endif
-			tp->stats.rx_packets++;
-		}
-
-		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
-		outw(cur_rx - 16, ioaddr + RxBufPtr);
-	}
-	if (rtl8129_debug > 4)
-		printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"
-			   " free to %4.4x, Cmd %2.2x.\n",
-			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),
-			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));
-	tp->cur_rx = cur_rx;
-	return 0;
-}
-
-static int
-rtl8129_close(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	int i;
-
-	netif_stop_queue(dev);
-
-	del_timer_sync(&tp->timer);
-
-	if (rtl8129_debug > 1)
-		printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",
-			   dev->name, inw(ioaddr + IntrStatus));
-
-	/* Disable interrupts by clearing the interrupt mask. */
-	outw(0x0000, ioaddr + IntrMask);
-
-	/* Stop the chip's Tx and Rx DMA processes. */
-	outb(0x00, ioaddr + ChipCmd);
-
-	/* Update the error counts. */
-	tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-	outl(0, ioaddr + RxMissed);
-
-	free_irq(dev->irq, dev);
-
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		struct sk_buff *skb = tp->tx_info[i].skb;
-		dma_addr_t mapping = tp->tx_info[i].mapping;
-
-		if (skb) {
-			if (mapping)
-				pci_unmap_single(tp->pdev, mapping, skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb(skb);
-		}
-		tp->tx_info[i].skb = NULL;
-		tp->tx_info[i].mapping = 0;
-	}
-	pci_free_consistent(tp->pdev, RX_BUF_LEN + 16,
-						tp->rx_ring, tp->rx_ring_dma);
-	pci_free_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC,
-						tp->tx_bufs, tp->tx_bufs_dma);
-	tp->rx_ring = NULL;
-	tp->tx_bufs = NULL;
-
-	/* Green! Put the chip in low-power mode. */
-	outb(0xC0, ioaddr + Cfg9346);
-	outb(0x03, ioaddr + Config1);
-	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */
-
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
-
-static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	u16 *data = (u16 *)&rq->ifr_data;
-
-	switch(cmd) {
-	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = tp->phys[0] & 0x3f;
-		/* Fall Through */
-	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		data[3] = mdio_read(dev, data[0], data[1] & 0x1f);
-		return 0;
-	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-static struct net_device_stats *
-rtl8129_get_stats(struct net_device *dev)
-{
-	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
-	long ioaddr = dev->base_addr;
-
-	if (netif_running(dev)) {
-		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);
-		outl(0, ioaddr + RxMissed);
-	}
-
-	return &tp->stats;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   This routine is not state sensitive and need not be SMP locked. */
-
-static unsigned const ethernet_polynomial = 0x04c11db7U;
-static inline u32 ether_crc(int length, unsigned char *data)
-{
-    int crc = -1;
-
-    while (--length >= 0) {
-		unsigned char current_octet = *data++;
-		int bit;
-		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
-    }
-    return crc;
-}
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
-	AcceptErr=0x20, AcceptRunt=0x10, AcceptBroadcast=0x08,
-	AcceptMulticast=0x04, AcceptMyPhys=0x02, AcceptAllPhys=0x01,
-};
-
-static void set_rx_mode(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	u32 mc_filter[2];		 /* Multicast hash filter */
-	int i, rx_mode;
-
-	if (rtl8129_debug > 3)
-		printk(KERN_DEBUG"%s:   set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
-			   dev->name, dev->flags, inl(ioaddr + RxConfig));
-
-	/* Note: do not reorder, GCC is clever about common statements. */
-	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 | AcceptMulticast | AcceptMyPhys;
-		mc_filter[1] = mc_filter[0] = 0;
-		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next)
-			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
-	}
-	/* We can safely update without stopping the chip. */
-	outb(rx_mode, ioaddr + RxConfig);
-	outl(mc_filter[0], ioaddr + MAR0 + 0);
-	outl(mc_filter[1], ioaddr + MAR0 + 4);
-	return;
-}
-
-
-static void __exit rtl8129_cleanup (void)
-{
-	struct net_device *next_dev;
-
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_rtl8129_dev) {
-		struct rtl8129_private *tp =
-			(struct rtl8129_private *)root_rtl8129_dev->priv;
-		next_dev = tp->next_module;
-		unregister_netdev(root_rtl8129_dev);
-		release_region(root_rtl8129_dev->base_addr,
-					   pci_tbl[tp->chip_id].io_size);
-		kfree(tp);
-		kfree(root_rtl8129_dev);
-		root_rtl8129_dev = next_dev;
-	}
-}
-
-module_init(rtl8129_probe);
-module_exit(rtl8129_cleanup);
-
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sb1000.c linux/drivers/net/sb1000.c
--- v2.4.2/linux/drivers/net/sb1000.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/sb1000.c	Tue Mar  6 19:44:36 2001
@@ -137,6 +137,14 @@
 static inline int sb1000_rx(struct net_device *dev);
 static inline void sb1000_error_dpc(struct net_device *dev);
 
+static struct isapnp_device_id id_table[] = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('G','I','C'), ISAPNP_FUNCTION(0x1000), 0 },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
 /* probe for SB1000 using Plug-n-Play mechanism */
 int
 sb1000_probe(struct net_device *dev)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c
--- v2.4.2/linux/drivers/net/sgiseeq.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/sgiseeq.c	Tue Mar  6 19:28:35 2001
@@ -149,7 +149,7 @@
 #define RCNTCFG_INIT  (HPCDMA_OWN | HPCDMA_EORP | HPCDMA_XIE)
 #define RCNTINFO_INIT (RCNTCFG_INIT | (PKT_BUF_SZ & HPCDMA_BCNT))
 
-static void seeq_init_ring(struct net_device *dev)
+static int seeq_init_ring(struct net_device *dev)
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
 	volatile struct sgiseeq_init_block *ib = &sp->srings;
@@ -173,6 +173,8 @@
 			unsigned long buffer;
 
 			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
+			if (!buffer)
+				return -ENOMEM;
 			ib->tx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
 			ib->tx_desc[i].tdma.pbuf = PHYSADDR(buffer);
 //			flush_cache_all();
@@ -186,6 +188,8 @@
 			unsigned long buffer;
 
 			buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL);
+			if (!buffer)
+				return -ENOMEM;
 			ib->rx_desc[i].buf_vaddr = KSEG1ADDR(buffer);
 			ib->rx_desc[i].rdma.pbuf = PHYSADDR(buffer);
 //			flush_cache_all();
@@ -193,6 +197,7 @@
 		ib->rx_desc[i].rdma.cntinfo = (RCNTINFO_INIT);
 	}
 	ib->rx_desc[i - 1].rdma.cntinfo |= (HPCDMA_EOR);
+	return 0;
 }
 
 #ifdef DEBUG
@@ -242,13 +247,16 @@
 #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2)
 #define RDMACFG_INIT    (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ)
 
-static void init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
+static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
 		      volatile struct sgiseeq_regs *sregs)
 {
 	volatile struct hpc3_ethregs *hregs = sp->hregs;
+	int err;
 
 	reset_hpc3_and_seeq(hregs, sregs);
-	seeq_init_ring(dev);
+	err = seeq_init_ring(dev);
+	if (err)
+		return err;
 
 	/* Setup to field the proper interrupt types. */
 	if (sp->is_edlc) {
@@ -265,6 +273,7 @@
 	hregs->tx_ndptr = PHYSADDR(&sp->srings.tx_desc[0]);
 
 	seeq_go(sp, hregs, sregs);
+	return 0;
 }
 
 static inline void record_rx_errors(struct sgiseeq_private *sp,
@@ -440,6 +449,7 @@
 	struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv;
 	volatile struct sgiseeq_regs *sregs = sp->sregs;
 	unsigned long flags;
+	int err;
 
 	save_flags(flags); cli();
 	if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) {
@@ -448,7 +458,9 @@
 		return -EAGAIN;
 	}
 
-	init_seeq(dev, sp, sregs);
+	err = init_seeq(dev, sp, sregs);
+	if (err)
+		return err;
 
 	netif_start_queue(dev);
 	restore_flags(flags);
@@ -474,8 +486,11 @@
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
 	volatile struct sgiseeq_regs *sregs = sp->sregs;
+	int err;
 
-	init_seeq(dev, sp, sregs);
+	err = init_seeq(dev, sp, sregs);
+	if (err)
+		return err;
 
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- v2.4.2/linux/drivers/net/sis900.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/sis900.c	Tue Mar 20 12:04:58 2001
@@ -18,6 +18,7 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   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
@@ -60,7 +61,7 @@
 #include "sis900.h"
 
 static const char *version =
-"sis900.c: v1.07.08  1/8/2001\n";
+"sis900.c: v1.07.09  2/9/2001\n";
 
 static int max_interrupt_work = 20;
 static int multicast_filter_limit = 128;
@@ -252,24 +253,29 @@
 static int __devinit sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
 	struct sis900_private *sis_priv;
-	long ioaddr = pci_resource_start(pci_dev, 0);
+	long ioaddr;
 	struct net_device *net_dev;
-	int irq = pci_dev->irq;
-	int i, ret = 0;
+	int irq;
+	int i, ret;
 	u8 revision;
 	char *card_name = card_names[pci_id->driver_data];
 
-	if (!pci_dma_supported(pci_dev, SIS900_DMA_MASK)) {
+	/* setup various bits in PCI command register */
+	ret = pci_enable_device (pci_dev);
+	if (ret) return ret;
+
+	i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK);
+	if (i) {
 		printk(KERN_ERR "sis900.c: architecture does not support "
 		       "32bit PCI busmaster DMA\n");
-		return -ENODEV;
+		return i;
 	}
 
-	/* setup various bits in PCI command register */
-	if (pci_enable_device (pci_dev))
-		return -ENODEV;
 	pci_set_master(pci_dev);
 
+	irq = pci_dev->irq;
+	ioaddr = pci_resource_start(pci_dev, 0);
+
 	net_dev = init_etherdev(NULL, sizeof(struct sis900_private));
 	if (!net_dev)
 		return -ENOMEM;
@@ -315,8 +321,7 @@
 		goto err_out_region;
 	}
 
-	pci_dev->driver_data = net_dev;
-	pci_dev->dma_mask = SIS900_DMA_MASK;
+	pci_set_drvdata(pci_dev, net_dev);
 
 	/* The SiS900-specific entries in the device structure. */
 	net_dev->open = &sis900_open;
@@ -1469,14 +1474,14 @@
 		tx_status = sis_priv->tx_ring[entry].cmdsts;
 
 		if (tx_status & OWN) {
-			/* The packet is not transmited yet (owned by hardware) !
+			/* The packet is not transmitted yet (owned by hardware) !
 			   Note: the interrupt is generated only when Tx Machine
 			   is idle, so this is an almost impossible case */
 			break;
 		}
 
 		if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
-			/* packet unsuccessfully transmited */
+			/* packet unsuccessfully transmitted */
 			if (sis900_debug > 3)
 				printk(KERN_INFO "%s: Transmit "
 				       "error, Tx status %8.8x.\n",
@@ -1491,7 +1496,7 @@
 			if (tx_status & OWCOLL)
 				sis_priv->stats.tx_window_errors++;
 		} else {
-			/* packet successfully transmited */
+			/* packet successfully transmitted */
 			sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
 			sis_priv->stats.tx_bytes += tx_status & DSIZE;
 			sis_priv->stats.tx_packets++;
@@ -1838,11 +1843,12 @@
 
 static void __devexit sis900_remove(struct pci_dev *pci_dev)
 {
-	struct net_device *net_dev = pci_dev->driver_data;
+	struct net_device *net_dev = pci_get_drvdata(pci_dev);
 		
 	unregister_netdev(net_dev);
 	release_region(net_dev->base_addr, SIS900_TOTAL_SIZE);
 	kfree(net_dev);
+	pci_set_drvdata(pci_dev, NULL);
 }
 
 #define SIS900_MODULE_NAME "sis900"
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/h/lm80.h linux/drivers/net/sk98lin/h/lm80.h
--- v2.4.2/linux/drivers/net/sk98lin/h/lm80.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/lm80.h	Tue Mar 20 12:04:59 2001
@@ -126,7 +126,7 @@
 #define LM80_IS_BTI		(1<<1)	/* state of BTI# pin */
 #define LM80_IS_FAN1		(1<<2)	/* count limit exceeded for Fan 1 */
 #define LM80_IS_FAN2		(1<<3)	/* count limit exceeded for Fan 2 */
-#define LM80_IS_CI		(1<<4)	/* Chassis Intrusion occured */
+#define LM80_IS_CI		(1<<4)	/* Chassis Intrusion occurred */
 #define LM80_IS_OS		(1<<5)	/* OS temperature limit exceeded */
 	/* bit 6 and 7 are reserved in LM80_ISRC_2 */
 #define LM80_IS_HT_IRQ_MD	(1<<6)	/* Hot temperature interrupt mode */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/h/skgehw.h linux/drivers/net/sk98lin/h/skgehw.h
--- v2.4.2/linux/drivers/net/sk98lin/h/skgehw.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/skgehw.h	Tue Mar 20 12:04:59 2001
@@ -499,7 +499,7 @@
 /*
  * The HW-Spec. call this registers Timeout Value 0..11. But this names are
  * not usable in SW. Please notice these are NOT real timeouts, these are
- * the number of qWords transfered continously.
+ * the number of qWords transferred continously.
  */
 #define B3_RI_WTO_R1	0x0190	/* 8 bit RAM Iface WR Timeout Queue R1	(TO0) */
 #define B3_RI_WTO_XA1	0x0191	/* 8 bit RAM Iface WR Timeout Queue XA1	(TO1) */
@@ -984,7 +984,7 @@
 
 /*	B3_RI_TEST	 8 bit	RAM Iface Test Register */
 				/* Bit 15..4:	reserved */
-#define RI_T_EV		(1<<3)	/* Bit	3:	Timeout Event occured */
+#define RI_T_EV		(1<<3)	/* Bit	3:	Timeout Event occurred */
 #define RI_T_ON		(1<<2)	/* Bit	2:	Timeout Timer Test On */
 #define RI_T_OFF	(1<<1)	/* Bit	1:	Timeout Timer Test Off */
 #define RI_T_STEP	(1<<0)	/* Bit	0:	Timeout Timer Step */
@@ -1034,19 +1034,19 @@
 /*	B3_MA_RC_TEST	16 bit	MAC Arbiter Recovery Test Reg */
 /*	B3_PA_TEST	16 bit	Packet Arbiter Test Register */
 /*			Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
-#define TX2_T_EV	(1<<15)	/* Bit 15: 	TX2 Timeout/Recv Event occured*/
+#define TX2_T_EV	(1<<15)	/* Bit 15: 	TX2 Timeout/Recv Event occurred*/
 #define TX2_T_ON	(1<<14)	/* Bit 14:	TX2 Timeout/Recv Timer Test On*/
 #define TX2_T_OFF	(1<<13)	/* Bit 13:	TX2 Timeout/Recv Timer Tst Off*/
 #define TX2_T_STEP	(1<<12)	/* Bit 12:	TX2 Timeout/Recv Timer Step */
-#define TX1_T_EV	(1<<11)	/* Bit 11:	TX1 Timeout/Recv Event occured*/
+#define TX1_T_EV	(1<<11)	/* Bit 11:	TX1 Timeout/Recv Event occurred*/
 #define TX1_T_ON	(1<<10)	/* Bit 10:	TX1 Timeout/Recv Timer Test On*/
 #define TX1_T_OFF	(1<<9)	/* Bit	9:	TX1 Timeout/Recv Timer Tst Off*/
 #define TX1_T_STEP	(1<<8)	/* Bit	8:	TX1 Timeout/Recv Timer Step */
-#define RX2_T_EV	(1<<7)	/* Bit	7:	RX2 Timeout/Recv Event occured*/
+#define RX2_T_EV	(1<<7)	/* Bit	7:	RX2 Timeout/Recv Event occurred*/
 #define RX2_T_ON	(1<<6)	/* Bit	6:	RX2 Timeout/Recv Timer Test On*/
 #define RX2_T_OFF	(1<<5)	/* Bit	5:	RX2 Timeout/Recv Timer Tst Off*/
 #define RX2_T_STEP	(1<<4)	/* Bit	4:	RX2 Timeout/Recv Timer Step */
-#define RX1_T_EV	(1<<3)	/* Bit	3:	RX1 Timeout/Recv Event occured*/
+#define RX1_T_EV	(1<<3)	/* Bit	3:	RX1 Timeout/Recv Event occurred*/
 #define RX1_T_ON	(1<<2)	/* Bit	2:	RX1 Timeout/Recv Timer Test On*/
 #define RX1_T_OFF	(1<<1)	/* Bit	1:	RX1 Timeout/Recv Timer Tst Off*/
 #define RX1_T_STEP	(1<<0)	/* Bit	0:	RX1 Timeout/Recv Timer Step */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/h/xmac_ii.h linux/drivers/net/sk98lin/h/xmac_ii.h
--- v2.4.2/linux/drivers/net/sk98lin/h/xmac_ii.h	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/h/xmac_ii.h	Tue Mar 20 12:04:59 2001
@@ -277,7 +277,7 @@
  * XMAC Bit Definitions
  *
  * If the bit access behaviour differs from the register access behaviour
- * (r/w, ro) this is docomented after the bit number. The following bit
+ * (r/w, ro) this is documented after the bit number. The following bit
  * access behaviours are used:
  *	(sc)	self clearing
  *	(ro)	read only
@@ -412,7 +412,7 @@
 #define XM_ST_BC	(1L<<7)		/* Bit	7:	Broadcast packet */
 #define XM_ST_MC	(1L<<6)		/* Bit	6:	Multicast packet */
 #define XM_ST_UC	(1L<<5)		/* Bit	5:	Unicast packet */
-#define XM_ST_TX_UR	(1L<<4)		/* Bit	4:	FIFO Underrun occured */
+#define XM_ST_TX_UR	(1L<<4)		/* Bit	4:	FIFO Underrun occurred */
 #define XM_ST_CS_ERR	(1L<<3)		/* Bit	3:	Carrier Sense Error */
 #define XM_ST_LAT_COL	(1L<<2)		/* Bit	2:	Late Collision Error */
 #define XM_ST_MUL_COL	(1L<<1)		/* Bit	1:	Multiple Collisions */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.4.2/linux/drivers/net/sk98lin/skge.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skge.c	Tue Mar  6 19:28:34 2001
@@ -109,7 +109,7 @@
  *	Transmit descriptor polling was not reenabled after SkGePortInit.
  *	
  *	Revision 1.16  1999/07/27 15:17:29  cgoos
- *	Added some "\n" in output strings (removed while debuging...).
+ *	Added some "\n" in output strings (removed while debugging...).
  *	
  *	Revision 1.15  1999/07/23 12:09:30  cgoos
  *	Performance optimization, rx checksumming, large frame support.
@@ -260,7 +260,7 @@
 #define VER_STRING	"3.05"
 
 
-/* for debuging on x86 only */
+/* for debugging on x86 only */
 /* #define BREAKPOINT() asm(" int $3"); */
 
 /* use of a transmit complete interrupt */
@@ -518,6 +518,12 @@
 } /* FreeResources */
 
 
+static struct pci_device_id skge_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
+
 MODULE_AUTHOR("Christoph Goos <cgoos@syskonnect.de>");
 MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
 MODULE_PARM(AutoNeg_A,  "1-" __MODULE_STRING(SK_MAX_CARD_PARAM) "s");
@@ -2616,7 +2622,7 @@
  * Description:
  *	This function is called if an ioctl is issued on the device.
  *	There are three subfunction for reading, writing and test-writing
- *	the private MIB data structure (usefull for SysKonnect-internal tools).
+ *	the private MIB data structure (useful for SysKonnect-internal tools).
  *
  * Returns:
  *	0, if everything is ok
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skgeinit.c linux/drivers/net/sk98lin/skgeinit.c
--- v2.4.2/linux/drivers/net/sk98lin/skgeinit.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skgeinit.c	Tue Mar 20 12:04:59 2001
@@ -122,7 +122,7 @@
  *	chg: Default is autosensing with AUTOFULL mode
  *
  *	Revision 1.31  1998/11/25 15:36:16  gklug
- *	fix: do NOT stop LED Timer when port should be stoped
+ *	fix: do NOT stop LED Timer when port should be stopped
  *
  *	Revision 1.30  1998/11/24 13:15:28  gklug
  *	add: Init PCkeckPar struct member
@@ -1118,10 +1118,10 @@
  *
  *	Dir =	SK_STOP_TX 	Stops the transmit path only and resets
  *				the XMAC. The receive queue is still and
- *				the pending rx frames may still transfered
+ *				the pending rx frames may still transferred
  *				into the RxD.
  *		SK_STOP_RX	Stop the receive path. The tansmit path
- *				has to be stoped once before.
+ *				has to be stopped once before.
  *		SK_STOP_ALL	SK_STOP_TX + SK_STOP_RX
  *
  *	RstMode=SK_SOFT_RST	Resets the XMAC. The PHY is still alive.
@@ -1129,7 +1129,7 @@
  *
  * Example:
  *	1) A Link Down event was signaled for a port. Therefore the activity
- *	of this port should be stoped and a hardware reset should be issued
+ *	of this port should be stopped and a hardware reset should be issued
  *	to enable the workaround of XMAC errata #2. But the received frames
  *	should not be discarded.
  *		...
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skgepnmi.c linux/drivers/net/sk98lin/skgepnmi.c
--- v2.4.2/linux/drivers/net/sk98lin/skgepnmi.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skgepnmi.c	Tue Mar 20 12:04:59 2001
@@ -149,7 +149,7 @@
  *	Fixed: Couldnot delete VPD keys on UNIX.
  *	
  *	Revision 1.48  1998/12/09 14:11:10  mhaveman
- *	-Add: Debugmessage for XMAC_RESET supressed to minimize output.
+ *	-Add: Debugmessage for XMAC_RESET suppressed to minimize output.
  *	-Fixed: RlmtChangeThreshold will now be initialized.
  *	-Fixed: VPD_ENTRIES_LIST extended value with unnecessary space char.
  *	-Fixed: On VPD key creation an invalid key name could be created
@@ -206,7 +206,7 @@
  *	-Fixed bug for RX counters. On an RX overflow interrupt the high
  *	 words of all RX counters were incremented.
  *	-SET operations on FLOWCTRL_MODE and LINK_MODE accept now the
- *	 value 0, which has no effect. It is usefull for multiple instance
+ *	 value 0, which has no effect. It is useful for multiple instance
  *	 SETs.
  *	
  *	Revision 1.37  1998/11/20 08:02:04  mhaveman
@@ -1600,7 +1600,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
  *	                         the data.
  *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
@@ -1632,13 +1632,13 @@
  * Description:
  *	Calls a general sub-function for all this stuff. The preset does
  *	the same as a set, but returns just before finally setting the
- *	new value. This is usefull to check if a set might be successfull.
+ *	new value. This is useful to check if a set might be successful.
  *	If as instance a -1 is passed, an array of values is supposed and
  *	all instance of the OID will be set.
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1674,13 +1674,13 @@
  * Description:
  *	Calls a general sub-function for all this stuff. The preset does
  *	the same as a set, but returns just before finally setting the
- *	new value. This is usefull to check if a set might be successfull.
+ *	new value. This is useful to check if a set might be successful.
  *	If as instance a -1 is passed, an array of values is supposed and
  *	all instance of the OID will be set.
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1723,7 +1723,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
  *	                         the data.
  */
@@ -1884,7 +1884,7 @@
  * Description:
  *	Calls a general sub-function for all this set stuff. The preset does
  *	the same as a set, but returns just before finally setting the
- *	new value. This is usefull to check if a set might be successfull.
+ *	new value. This is useful to check if a set might be successful.
  *	The sub-function runs through the IdTable, checks which OIDs are able
  *	to set, and calls the handler function of the OID to perform the
  *	preset. The return value of the function will also be stored in
@@ -1893,7 +1893,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -1929,7 +1929,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -2816,7 +2816,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -2883,7 +2883,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3017,7 +3017,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3159,7 +3159,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3299,7 +3299,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3509,7 +3509,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3628,7 +3628,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -3872,7 +3872,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -4352,7 +4352,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -4956,7 +4956,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -5264,7 +5264,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -5449,7 +5449,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -6052,7 +6052,7 @@
  *
  * Returns:
  *	SK_PNMI_ERR_OK           The request was successfully performed.
- *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occurred.
  *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
  *	                         the correct data (e.g. a 32bit value is
  *	                         needed, but a 16 bit value was passed).
@@ -6502,7 +6502,7 @@
  *
  * Description:
  *	The COMMON module only tells us if the mode is half or full duplex.
- *	But in the decade of auto sensing it is usefull for the user to
+ *	But in the decade of auto sensing it is useful for the user to
  *	know if the mode was negotiated or forced. Therefore we have a
  *	look to the mode, which was last used by the negotiation process.
  *
@@ -6764,7 +6764,7 @@
 
 		/*
 		 * It is an auto-clearing register. If the command bits
-		 * went to zero again, the statistics are transfered.
+		 * went to zero again, the statistics are transferred.
 		 * Normally the command should be executed immediately.
 		 * But just to be sure we execute a loop.
 		 */
@@ -7037,7 +7037,7 @@
  *
  * Description:
  *	The trap buffer stores various events. A user application somehow
- *	gets notified that an event occured and retrieves the trap buffer
+ *	gets notified that an event occurred and retrieves the trap buffer
  *	contens (or simply polls the buffer). The buffer is organized as
  *	a ring which stores the newest traps at the beginning. The oldest
  *	traps are overwritten by the newest ones. Each trap entry has a
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skgesirq.c linux/drivers/net/sk98lin/skgesirq.c
--- v2.4.2/linux/drivers/net/sk98lin/skgesirq.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skgesirq.c	Tue Mar 20 12:04:59 2001
@@ -695,14 +695,14 @@
 	/* Check whether XMACs are correctly initialized */
 	if ((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) &&
 	    !pAC->GIni.GP[MAC_1].PState) {
-		/* XMAC was not initialized but Packet timeout occured */
+		/* XMAC was not initialized but Packet timeout occurred */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
 			SKERR_SIRQ_E004MSG) ;
 	}
 
 	if ((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) &&
 	    !pAC->GIni.GP[MAC_2].PState) {
-		/* XMAC was not initialized but Packet timeout occured */
+		/* XMAC was not initialized but Packet timeout occurred */
 		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
 			SKERR_SIRQ_E005MSG) ;
 	}
@@ -1012,7 +1012,7 @@
 			 */
 			/*
 			 * we received a bunch of frames or no
-			 * CRC error occured on the network ->
+			 * CRC error occurred on the network ->
 			 * ok.
 			 */
 			pPrt->PPrevRx = RxCts;
@@ -1255,7 +1255,7 @@
 			SkHWLinkUp(pAC, IoC, Port) ;
 			Done = SkXmAutoNegDone(pAC,IoC,Port);
 			if (Done != SK_AND_OK) {
-				/* Get PHY parameters, for debuging only */
+				/* Get PHY parameters, for debugging only */
 				PHY_READ(IoC, pPrt, Port, PHY_XMAC_AUNE_LP,
 					&LpAb);
 				PHY_READ(IoC, pPrt, Port, PHY_XMAC_RES_ABI,
@@ -1294,7 +1294,7 @@
 		pPrt->PAutoNegTimeOut ++;
 		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
 			/*
-			 * Timeout occured.
+			 * Timeout occurred.
 			 * What do we need now?
 			 */
 			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
@@ -1304,7 +1304,7 @@
 			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
 				/*
-				 * Timeout occured
+				 * Timeout occurred
 				 * Set Link manually up.
 				 */
 				SkHWSenseSetNext(pAC, IoC, Port,
@@ -1445,7 +1445,7 @@
 			SkHWLinkUp(pAC, IoC, Port);
 			Done = SkXmAutoNegDone(pAC,IoC,Port);
 			if (Done != SK_AND_OK) {
-				/* Get PHY parameters, for debuging only */
+				/* Get PHY parameters, for debugging only */
 				PHY_READ(IoC, pPrt, Port,
 					PHY_BCOM_AUNE_LP,
 					&LpAb);
@@ -1583,7 +1583,7 @@
 			SkHWLinkUp(pAC, IoC, Port) ;
 			Done = SkXmAutoNegDone(pAC,IoC,Port);
 			if (Done != SK_AND_OK) {
-				/* Get PHY parameters, for debuging only */
+				/* Get PHY parameters, for debugging only */
 				PHY_READ(IoC, pPrt, Port,
 					PHY_LONE_AUNE_LP,
 					&LpAb);
@@ -1624,7 +1624,7 @@
 		pPrt->PAutoNegTimeOut ++;
 		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
 			/*
-			 * Timeout occured.
+			 * Timeout occurred.
 			 * What do we need now?
 			 */
 			SK_DBG_MSG(pAC,SK_DBGMOD_HWM,
@@ -1634,7 +1634,7 @@
 			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
 				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
 				/*
-				 * Timeout occured
+				 * Timeout occurred
 				 * Set Link manually up.
 				 */
 				SkHWSenseSetNext(pAC, IoC, Port,
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/ski2c.c linux/drivers/net/sk98lin/ski2c.c
--- v2.4.2/linux/drivers/net/sk98lin/ski2c.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/ski2c.c	Tue Mar 20 12:04:59 2001
@@ -1000,7 +1000,7 @@
 	/* Get the current time */
 	CurrTime = SkOsGetTime(pAC);
 
-	/* Set para to the most usefull setting:
+	/* Set para to the most useful setting:
 	 * The current sensor.
 	 */
 	ParaLocal.Para64 = (SK_U64) pAC->I2c.CurrSens;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skqueue.c linux/drivers/net/sk98lin/skqueue.c
--- v2.4.2/linux/drivers/net/sk98lin/skqueue.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skqueue.c	Tue Mar 20 12:04:59 2001
@@ -147,7 +147,7 @@
  *		send command to state machine
  *	end
  *	return error reported by individual Event function
- *		0 if no error occured.
+ *		0 if no error occurred.
  */
 int	SkEventDispatcher(
 SK_AC	*pAC,	/* Adapters Context */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c
--- v2.4.2/linux/drivers/net/sk98lin/skxmac2.c	Fri Sep 15 14:34:19 2000
+++ linux/drivers/net/sk98lin/skxmac2.c	Tue Mar 20 12:04:59 2001
@@ -278,7 +278,7 @@
  *	 o don't set XMR_FS_ERR in frame	SK_BIG_PK_OK_ON/OFF
  *	   status for frames > 1514 bytes
  *
- *	for incomming packets may be enabled/disabled by this function.
+ *	for incoming packets may be enabled/disabled by this function.
  *	Additional modes may be added later.
  *	Multiple modes can be enabled/disabled at the same time.
  *	The new configuration is stored into the HWAC port configuration
@@ -755,8 +755,8 @@
 
 	/*
 	 * configure the XMACs Station Address
-	 * B2_MAC_2 = xx xx xx xx xx x1 is programed to XMAC A
-	 * B2_MAC_3 = xx xx xx xx xx x2 is programed to XMAC B
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
 	 */
 	for (i = 0; i < 3; i++) {
 		/*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v2.4.2/linux/drivers/net/sk_g16.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/sk_g16.c	Tue Mar 20 12:05:00 2001
@@ -218,9 +218,9 @@
  *
  */ 
 
-#define SK_IOREG        (board->ioreg) /* LANCE data registers.     */ 
-#define SK_PORT         (board->port)  /* Control, Status register  */
-#define SK_IOCOM        (board->iocom) /* I/O Command               */
+#define SK_IOREG        (&board->ioreg) /* LANCE data registers.     */ 
+#define SK_PORT         (&board->port)  /* Control, Status register  */
+#define SK_IOCOM        (&board->iocom) /* I/O Command               */
 
 /* 
  * SK_G16 Status/Control Register bits
@@ -1102,7 +1102,7 @@
 	writel((unsigned long) p->tmdbufs[i], tmdp->u.buffer); /* assign buffer */
 	
 	/* Mark TMD as start and end of packet */
-	writeb(TX_STP | TX_ENP, tmdp->u.s.status);
+	writeb(TX_STP | TX_ENP, &tmdp->u.s.status);
     }
 
 
@@ -1122,32 +1122,32 @@
 	 * receiving packets, set status and release RMD 
 	 */
 
-	writeb(RX_OWN, rmdp->u.s.status);
+	writeb(RX_OWN, &rmdp->u.s.status);
 
-	writew(-PKT_BUF_SZ, rmdp->blen); /* Buffer Size (two's complement) */
+	writew(-PKT_BUF_SZ, &rmdp->blen); /* Buffer Size (two's complement) */
 
-	writeb(0, rmdp->mlen);           /* init message length */       
+	writeb(0, &rmdp->mlen);           /* init message length */       
 	
     }
 
     /* Fill LANCE Initialize Block */
 
-    writew(mode, (p->ram)->ib.mode); /* Set operation mode */
+    writew(mode, (&((p->ram)->ib.mode))); /* Set operation mode */
 
     for (i = 0; i < ETH_ALEN; i++)   /* Set physical address */
     {
-	writeb(dev->dev_addr[i], (p->ram)->ib.paddr[i]); 
+	writeb(dev->dev_addr[i], (&((p->ram)->ib.paddr[i]))); 
     }
 
     for (i = 0; i < 8; i++)          /* Set multicast, logical address */
     {
-	writeb(0, (p->ram)->ib.laddr[i]); /* We do not use logical addressing */
+	writeb(0, (&((p->ram)->ib.laddr[i]))); /* We do not use logical addressing */
     } 
 
     /* Set ring descriptor pointers and set number of descriptors */
 
-    writel((int)p->rmdhead | RMDNUMMASK, (p->ram)->ib.rdrp);
-    writel((int)p->tmdhead | TMDNUMMASK, (p->ram)->ib.tdrp);
+    writel((int)p->rmdhead | RMDNUMMASK, (&((p->ram)->ib.rdrp)));
+    writel((int)p->tmdhead | TMDNUMMASK, (&((p->ram)->ib.tdrp)));
 
     /* Prepare LANCE Control and Status Registers */
 
@@ -1281,7 +1281,7 @@
 
 	memcpy_toio((tmdp->u.buffer & 0x00ffffff), skb->data, skb->len);
 
-	writew(-len, tmdp->blen);            /* set length to transmit */
+	writew(-len, &tmdp->blen);            /* set length to transmit */
 
 	/* 
 	 * Packet start and end is always set because we use the maximum
@@ -1289,7 +1289,7 @@
 	 * Relinquish ownership to LANCE
 	 */
 
-	writeb(TX_OWN | TX_STP | TX_ENP, tmdp->u.s.status);
+	writeb(TX_OWN | TX_STP | TX_ENP, &tmdp->u.s.status);
 	
 	/* Start Demand Transmission */
 	SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA);
@@ -1301,7 +1301,7 @@
 	p->tmdnum &= TMDNUM-1; 
 
 	/* Do we own the next transmit buffer ? */
-	if (! (readb((p->tmdhead + p->tmdnum)->u.s.status) & TX_OWN) )
+	if (! (readb(&((p->tmdhead + p->tmdnum)->u.s.status)) & TX_OWN) )
 	{
 	   /* 
 	    * We own next buffer and are ready to transmit, so
@@ -1421,7 +1421,7 @@
     p->tmdlast++;
     p->tmdlast &= TMDNUM-1;
 
-    tmdstat = readb(tmdp->u.s.status);
+    tmdstat = readb(&tmdp->u.s.status);
 
     /* 
      * We check status of transmitted packet.
@@ -1429,7 +1429,7 @@
      */
     if (tmdstat & TX_ERR) /* Error occurred */
     {
-	int stat2 = readw(tmdp->status2);
+	int stat2 = readw(&tmdp->status2);
 
 	printk("%s: TX error: %04x %04x\n", dev->name, tmdstat, stat2);
 
@@ -1458,7 +1458,7 @@
 	
 	p->stats.tx_errors++;
 
-	writew(0, tmdp->status2);             /* Clear error flags */
+	writew(0, &tmdp->status2);             /* Clear error flags */
     }
     else if (tmdstat & TX_MORE)        /* Collisions occurred ? */
     {
@@ -1534,7 +1534,7 @@
      * it up to higher layer 
      */
 
-    while (!( (rmdstat = readb(rmdp->u.s.status)) & RX_OWN))
+    while (!( (rmdstat = readb(&rmdp->u.s.status)) & RX_OWN))
     {
 	/* 
          * Start and end of packet must be set, because we use 
@@ -1564,7 +1564,7 @@
 	     * packets. 
 	     */
 
-	    writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */ 
+	    writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */ 
 
 	}
 	else if (rmdstat & RX_ERR)          /* Receive Error ? */
@@ -1576,13 +1576,13 @@
 	    if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++;
 	    if (rmdstat & RX_CRC)  p->stats.rx_crc_errors++;
 
-	    writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */
+	    writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */
 
 	}
 	else /* We have a packet which can be queued for the upper layers */
 	{
 
-	    int len = readw(rmdp->mlen) & 0x0fff;  /* extract message length from receive buffer */
+	    int len = readw(&rmdp->mlen) & 0x0fff;  /* extract message length from receive buffer */
 	    struct sk_buff *skb;
 
 	    skb = dev_alloc_skb(len+2); /* allocate socket buffer */ 
@@ -1595,7 +1595,7 @@
 		 * to Lance, update statistics and go ahead.
 		 */
 
-		writeb(RX_OWN, rmdp->u.s.status); /* Relinquish ownership to LANCE */
+		writeb(RX_OWN, &rmdp->u.s.status); /* Relinquish ownership to LANCE */
 		printk("%s: Couldn't allocate sk_buff, deferring packet.\n",
 		       dev->name);
 		p->stats.rx_dropped++;
@@ -1633,7 +1633,7 @@
 	     * free our descriptor and update statistics 
 	     */
 
-	    writeb(RX_OWN, rmdp->u.s.status);
+	    writeb(RX_OWN, &rmdp->u.s.status);
 	    dev->last_rx = jiffies;
 	    p->stats.rx_packets++;
 	    p->stats.rx_bytes += len;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/drvfbi.c linux/drivers/net/skfp/drvfbi.c
--- v2.4.2/linux/drivers/net/skfp/drvfbi.c	Sun Mar 12 19:11:17 2000
+++ linux/drivers/net/skfp/drvfbi.c	Tue Mar 20 12:04:59 2001
@@ -849,7 +849,7 @@
 
 #ifdef	EISA
 
-/*arrays with io adresses of dma controller length and adress registers*/
+/*arrays with io addresses of dma controller length and address registers*/
 static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
 static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
 static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/fplustm.c linux/drivers/net/skfp/fplustm.c
--- v2.4.2/linux/drivers/net/skfp/fplustm.c	Wed Jul  5 10:56:13 2000
+++ linux/drivers/net/skfp/fplustm.c	Tue Mar 20 12:04:59 2001
@@ -87,7 +87,7 @@
 
 
 /*
- * usefull interrupt bits
+ * useful interrupt bits
  */
 static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ;
 static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0|
@@ -1381,7 +1381,7 @@
 			CHECK_CAM() ;
 
 			/*
-			 * wirte the multicast addres into the CAM
+			 * write the multicast address into the CAM
 			 */
 			outpw(FM_A(FM_AFCOMP2),
 				(u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/h/smc.h linux/drivers/net/skfp/h/smc.h
--- v2.4.2/linux/drivers/net/skfp/h/smc.h	Fri Feb 18 14:55:53 2000
+++ linux/drivers/net/skfp/h/smc.h	Tue Mar 20 12:05:00 2001
@@ -297,7 +297,7 @@
 #define RS_NORINGOP	(1<< 5)			/* no ring op */
 #define RS_VERSION	(1<< 4)			/* SMT version mismatch */
 #define RS_STUCKBYPASSS	(1<< 3)			/* stuck bypass */
-#define RS_EVENT	(1<< 2)			/* FDDI event occured */
+#define RS_EVENT	(1<< 2)			/* FDDI event occurred */
 #define RS_RINGOPCHANGE	(1<< 1)			/* ring op changed */
 #define RS_RES0		(1<< 0)			/* reserved */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/pcmplc.c linux/drivers/net/skfp/pcmplc.c
--- v2.4.2/linux/drivers/net/skfp/pcmplc.c	Fri Feb 18 14:55:53 2000
+++ linux/drivers/net/skfp/pcmplc.c	Tue Mar 20 12:05:00 2001
@@ -1722,7 +1722,7 @@
 	}
 	if (cmd & PL_EBUF_ERR) {	/* elastic buff. det. over-|underflow*/
 		/*
-		 * Check whether the SRF Condition occured.
+		 * Check whether the SRF Condition occurred.
 		 */
 		if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
 			/*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c
--- v2.4.2/linux/drivers/net/skfp/skfddi.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/skfp/skfddi.c	Tue Mar  6 19:28:34 2001
@@ -182,12 +182,17 @@
 extern void enable_tx_irq(struct s_smc *smc, u_short queue);
 extern void mac_drv_clear_txd(struct s_smc *smc);
 
+static struct pci_device_id skfddi_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);
 
 // Define module-wide (static) variables
 
-static int num_boards = 0;	/* total number of adapters configured */
-static int num_fddi = 0;
-static int autoprobed = 0;
+static int num_boards;	/* total number of adapters configured */
+static int num_fddi;
+static int autoprobed;
 
 #ifdef MODULE
 int init_module(void);
@@ -195,7 +200,7 @@
 static struct net_device *unlink_modules(struct net_device *p);
 static int loading_module = 1;
 #else
-static int loading_module = 0;
+static int loading_module;
 #endif				// MODULE
 
 #ifdef DRIVERDEBUG
@@ -1632,7 +1637,7 @@
  *	This function is called by the hardware dependent module.
  *	It allocates the memory for the RxD and TxD descriptors.
  *
- *	This memory must be non-cached, non-movable and non-swapable.
+ *	This memory must be non-cached, non-movable and non-swappable.
  *	This memory should start at a physical page boundary.
  * Args
  *	smc - A pointer to the SMT context struct.
diff -u --recursive --new-file v2.4.2/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v2.4.2/linux/drivers/net/slhc.c	Thu Jul  6 19:27:48 2000
+++ linux/drivers/net/slhc.c	Tue Mar  6 22:44:16 2001
@@ -81,8 +81,6 @@
 #include <net/checksum.h>
 #include <asm/unaligned.h>
 
-int last_retran;
-
 static unsigned char *encode(unsigned char *cp, unsigned short n);
 static long decode(unsigned char **cpp);
 static unsigned char * put16(unsigned char *cp, unsigned short x);
@@ -256,8 +254,7 @@
 	ip = (struct iphdr *) icp;
 
 	/* Bail if this packet isn't TCP, or is an IP fragment */
-	if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
-				       (ip->frag_off & 32)){
+	if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
 		/* Send as regular IP */
 		if(ip->protocol != IPPROTO_TCP)
 			comp->sls_o_nontcp++;
@@ -351,10 +348,9 @@
 	 */
 	oth = &cs->cs_tcp;
 
-	if(last_retran
-	 || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
+	if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
 	 || ip->tos != cs->cs_ip.tos
-	 || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64)
+	 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
 	 || ip->ttl != cs->cs_ip.ttl
 	 || th->doff != cs->cs_tcp.doff
 	 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/smc-mca.c linux/drivers/net/smc-mca.c
--- v2.4.2/linux/drivers/net/smc-mca.c	Mon Dec 11 13:38:29 2000
+++ linux/drivers/net/smc-mca.c	Sun Mar  4 14:05:04 2001
@@ -213,7 +213,7 @@
 	dev->mem_start = 0;
 	num_pages      = 40;
 
-	switch (j) {	/* 'j' = card-# in const array above [hs] */
+	switch (adapter) {	/* card-# in const array above [hs] */
 		case _61c8_SMC_Ethercard_PLUS_Elite_A_BNC_AUI_WD8013EP_A:
 		case _61c9_SMC_Ethercard_PLUS_Elite_A_UTP_AUI_WD8013EP_A:
 		{
@@ -373,9 +373,9 @@
 
 #ifdef notdef
 	/* Officially this is what we are doing, but the readl() is faster */
-	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 #else
-	((unsigned int*)hdr)[0] = readl(hdr_start);
+	((unsigned int*)hdr)[0] = isa_readl(hdr_start);
 #endif
 }
 
@@ -390,12 +390,12 @@
 	if (xfer_start + count > dev->rmem_end) {
 		/* We must wrap the input move. */
 		int semi_count = dev->rmem_end - xfer_start;
-		memcpy_fromio(skb->data, xfer_start, semi_count);
+		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
-		eth_io_copy_and_sum(skb, xfer_start, count, 0);
+		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
 	}
 
 }
@@ -405,7 +405,7 @@
 {
 	unsigned long shmem = dev->mem_start + ((start_page - START_PG) << 8);
 
-	memcpy_toio(shmem, buf, count);
+	isa_memcpy_toio(shmem, buf, count);
 }
 
 static int ultramca_close_card(struct net_device *dev)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c
--- v2.4.2/linux/drivers/net/smc-ultra.c	Wed Feb 21 18:20:28 2001
+++ linux/drivers/net/smc-ultra.c	Tue Mar 20 12:05:00 2001
@@ -20,6 +20,7 @@
 
 		ultra_probe()	 	Detecting and initializing the card.
 		ultra_probe1()
+		ultra_probe_isapnp()
 
 		ultra_open()		The card-specific details of starting, stopping
 		ultra_reset_8390()	and resetting the 8390 NIC core.
@@ -43,11 +44,19 @@
 	Paul Gortmaker	: multiple card support for module users.
 	Donald Becker	: 4/17/96 PIO support, minor potential problems avoided.
 	Donald Becker	: 6/6/96 correctly set auto-wrap bit.
+	Alexander Sotirov : 1/20/01 Added support for ISAPnP cards
+
+	Note about the ISA PnP support:
+
+	This driver can not autoprobe for more than one SMC EtherEZ PnP card.
+	You have to configure the second card manually through the /proc/isapnp
+	interface and then load the module with an explicit io=0x___ option.
 */
 
 static const char *version =
 	"smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -55,6 +64,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -69,6 +79,10 @@
 int ultra_probe(struct net_device *dev);
 static int ultra_probe1(struct net_device *dev, int ioaddr);
 
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static int ultra_probe_isapnp(struct net_device *dev);
+#endif
+
 static int ultra_open(struct net_device *dev);
 static void ultra_reset_8390(struct net_device *dev);
 static void ultra_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
@@ -85,6 +99,17 @@
 							 const unsigned char *buf, const int start_page);
 static int ultra_close_card(struct net_device *dev);
 
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static struct isapnp_device_id ultra_device_ids[] __initdata = {
+        {       ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416),
+                ISAPNP_VENDOR('S','M','C'), ISAPNP_FUNCTION(0x8416),
+                (long) "SMC EtherEZ (8416)" },
+        { }	/* terminate list */
+};
+
+MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
+#endif
+
 
 #define START_PG		0x00	/* First page of TX buffer */
 
@@ -114,6 +139,14 @@
 	else if (base_addr != 0)	/* Don't probe at all. */
 		return -ENXIO;
 
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+	/* Look for any installed ISAPnP cards */
+	if (isapnp_present() && (ultra_probe_isapnp(dev) == 0))
+		return 0;
+
+	printk(KERN_NOTICE "smc-ultra.c: No ISAPnP cards found, trying standard ones...\n");
+#endif
+
 	for (i = 0; ultra_portlist[i]; i++)
 		if (ultra_probe1(dev, ultra_portlist[i]) == 0)
 			return 0;
@@ -245,6 +278,48 @@
 	return retval;
 }
 
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+static int __init ultra_probe_isapnp(struct net_device *dev)
+{
+        int i;
+
+        for (i = 0; ultra_device_ids[i].vendor != 0; i++) {
+                struct pci_dev *idev = NULL;
+
+                while ((idev = isapnp_find_dev(NULL,
+                                               ultra_device_ids[i].vendor,
+                                               ultra_device_ids[i].function,
+                                               idev))) {
+                        /* Avoid already found cards from previous calls */
+                        if (idev->prepare(idev))
+                                continue;
+                        if (idev->activate(idev))
+                                continue;
+                        /* if no irq, search for next */
+                        if (idev->irq_resource[0].start == 0)
+                                continue;
+                        /* found it */
+                        dev->base_addr = idev->resource[0].start;
+                        dev->irq = idev->irq_resource[0].start;
+                        printk(KERN_INFO "smc-ultra.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
+                                (char *) ultra_device_ids[i].driver_data,
+
+                                dev->base_addr, dev->irq);
+                        if (ultra_probe1(dev, dev->base_addr) != 0) {      /* Shouldn't happen. */
+                                printk(KERN_ERR "smc-ultra.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr);                                return -ENXIO;
+                        }
+                        ei_status.priv = (unsigned long)idev;
+                        break;
+                }
+                if (!idev)
+                        continue;
+                return 0;
+        }
+
+        return -ENODEV;
+}
+#endif
+
 static int
 ultra_open(struct net_device *dev)
 {
@@ -465,6 +540,13 @@
 		if (dev->priv != NULL) {
 			/* NB: ultra_close_card() does free_irq */
 			int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET;
+
+#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+			struct pci_dev *idev = (struct pci_dev *)ei_status.priv;
+			if (idev)
+				idev->deactivate(idev);
+#endif
+
 			unregister_netdev(dev);
 			release_region(ioaddr, ULTRA_IO_EXTENT);
 			kfree(dev->priv);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/smc9194.c linux/drivers/net/smc9194.c
--- v2.4.2/linux/drivers/net/smc9194.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/smc9194.c	Tue Mar 20 12:05:01 2001
@@ -238,12 +238,12 @@
  . This is a separate procedure to handle the receipt of a packet, to
  . leave the interrupt code looking slightly cleaner
 */
-inline static void smc_rcv( struct net_device *dev );
+static inline void smc_rcv( struct net_device *dev );
 /*
  . This handles a TX interrupt, which is only called when an error
  . relating to a packet is sent.
 */
-inline static void smc_tx( struct net_device * dev );
+static inline void smc_tx( struct net_device * dev );
 
 /*
  ------------------------------------------------------------
@@ -616,7 +616,7 @@
 	if ( packet_no & 0x80 ) {
 		/* or isn't there?  BAD CHIP! */
 		printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
-		dev_kfree_skb_irq(skb);
+		dev_kfree_skb_any(skb);
 		lp->saved_skb = NULL;
 		netif_wake_queue(dev);
 		return;
@@ -679,7 +679,7 @@
 	PRINTK2((CARDNAME": Sent packet of length %d \n",length));
 
 	lp->saved_skb = NULL;
-	dev_kfree_skb_irq (skb);
+	dev_kfree_skb_any (skb);
 
 	dev->trans_start = jiffies;
 
@@ -1341,9 +1341,9 @@
 		skb = dev_alloc_skb( packet_length + 5);
 
 		if ( skb == NULL ) {
-			printk(KERN_NOTICE CARDNAME
-			": Low memory, packet dropped.\n");
+			printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
 			lp->stats.rx_dropped++;
+			goto done;
 		}
 
 		/*
@@ -1396,11 +1396,10 @@
 			lp->stats.rx_length_errors++;
 		if ( status & RS_BADCRC)	lp->stats.rx_crc_errors++;
 	}
+
+done:
 	/*  error or good, tell the card to get rid of this packet */
 	outw( MC_RELEASE, ioaddr + MMU_CMD );
-
-
-	return;
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sonic.h linux/drivers/net/sonic.h
--- v2.4.2/linux/drivers/net/sonic.h	Tue Jul 11 11:12:24 2000
+++ linux/drivers/net/sonic.h	Sat Mar  3 10:55:47 2001
@@ -445,7 +445,7 @@
 struct sonic_local {
     sonic_cda_t   cda;                     /* virtual CPU address of CDA */
     sonic_td_t    tda[SONIC_NUM_TDS];      /* transmit descriptor area */
-    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource arrea */
+    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource area */
     sonic_rd_t    rda[SONIC_NUM_RDS];      /* receive descriptor area */
     struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
     unsigned int  tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.4.2/linux/drivers/net/sun3lance.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/sun3lance.c	Tue Mar  6 19:28:35 2001
@@ -148,9 +148,9 @@
      	int new_rx, new_tx;	/* The next free ring entry */
 	int old_tx, old_rx;     /* ring entry to be processed */
 	struct net_device_stats stats;
-/* These two must be ints for set_bit() */
-	int					tx_full;
-	int					lock;
+/* These two must be longs for set_bit() */
+	long					tx_full;
+	long					lock;
 };
 
 /* I/O register access macros */
@@ -303,8 +303,11 @@
 	}
 
 	init_etherdev( dev, sizeof(struct lance_private) );
-	if (!dev->priv)
+	if (!dev->priv) {
 		dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL );
+		if (!dev->priv)
+			return 0;
+	}
 	lp = (struct lance_private *)dev->priv;
 	MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct
 							     lance_memory)); 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.4.2/linux/drivers/net/sunbmac.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/sunbmac.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.23 2001/01/20 03:36:40 davem Exp $
+/* $Id: sunbmac.c,v 1.25 2001/02/18 08:10:21 davem Exp $
  * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -902,19 +902,15 @@
 static int bigmac_open(struct net_device *dev)
 {
 	struct bigmac *bp = (struct bigmac *) dev->priv;
-	int res;
+	int ret;
 
-	if (request_irq(dev->irq, &bigmac_interrupt,
-			SA_SHIRQ, "BIG MAC", (void *) bp)) {
+	ret = request_irq(dev->irq, &bigmac_interrupt, SA_SHIRQ, dev->name, bp);
+	if (ret) {
 		printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);
-		return -EAGAIN;
+		return ret;
 	}
 	init_timer(&bp->bigmac_timer);
-	res = bigmac_init(bp, 0);
-	if (!res) {
-		MOD_INC_USE_COUNT;
-	}
-	return res;
+	return bigmac_init(bp, 0);
 }
 
 static int bigmac_close(struct net_device *dev)
@@ -928,7 +924,6 @@
 	bigmac_stop(bp);
 	bigmac_clean_rings(bp);
 	free_irq(dev->irq, (void *)bp);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1058,7 +1053,10 @@
 	int i;
 
 	/* Get a new device struct for this interface. */
-	dev = init_etherdev(0, sizeof(struct bigmac));
+	dev = init_etherdev(NULL, sizeof(struct bigmac));
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
 
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -1075,7 +1073,7 @@
 	printk("\n");
 
 	/* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */
-	bp = (struct bigmac *) dev->priv;
+	bp = dev->priv;
 	bp->qec_sdev = qec_sdev;
 	bp->bigmac_sdev = qec_sdev->child;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sundance.c linux/drivers/net/sundance.c
--- v2.4.2/linux/drivers/net/sundance.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/sundance.c	Tue Mar  6 19:28:34 2001
@@ -314,6 +314,7 @@
 #define PRIV_ALIGN	15 	/* Required alignment mask */
 /* Use  __attribute__((aligned (L1_CACHE_BYTES)))  to maintain alignment
    within the structure. */
+#define MII_CNT		4
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
 	struct netdev_desc rx_ring[RX_RING_SIZE];
@@ -346,7 +347,7 @@
 	/* MII transceiver section. */
 	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
+	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 };
 
 /* The station address location in the EEPROM. */
@@ -379,7 +380,7 @@
 	struct netdev_private *np;
 	static int card_idx;
 	int chip_idx = ent->driver_data;
-	int irq = pdev->irq;
+	int irq;
 	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 	long ioaddr;
 
@@ -387,19 +388,20 @@
 		return -EIO;
 	pci_set_master(pdev);
 
+	irq = pdev->irq;
+
 	dev = init_etherdev(NULL, sizeof(*np));
 	if (!dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
 
+	if (pci_request_regions(pdev, dev->name))
+		goto err_out_netdev;
+
 #ifdef USE_IO_OPS
 	ioaddr = pci_resource_start(pdev, 0);
-	if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name))
-		goto err_out_netdev;
 #else
 	ioaddr = pci_resource_start(pdev, 1);
-	if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name))
-		goto err_out_netdev;
 	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
 	if (!ioaddr)
 		goto err_out_iomem;
@@ -456,7 +458,7 @@
 	if (1) {
 		int phy, phy_idx = 0;
 		np->phys[0] = 1;		/* Default setting */
-		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
@@ -485,8 +487,7 @@
 
 #ifndef USE_IO_OPS
 err_out_iomem:
-	release_mem_region(pci_resource_start(pdev, 1),
-			   pci_id_tbl[chip_idx].io_size);
+	pci_release_regions(pdev);
 #endif
 err_out_netdev:
 	unregister_netdev (dev);
@@ -604,7 +605,7 @@
 
 static int netdev_open(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -667,7 +668,7 @@
 
 static void check_duplex(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
 	int negotiated = mii_reg5 & np->advertising;
@@ -689,7 +690,7 @@
 static void netdev_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 
@@ -706,7 +707,7 @@
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out, status %2.2x,"
@@ -735,14 +736,16 @@
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-	return;
+
+	if (!np->tx_full)
+		netif_wake_queue(dev);
 }
 
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void init_ring(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	np->tx_full = 0;
@@ -784,7 +787,7 @@
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	struct netdev_desc *txdesc;
 	unsigned entry;
 
@@ -838,7 +841,7 @@
 	int boguscnt = max_interrupt_work;
 
 	ioaddr = dev->base_addr;
-	np = (struct netdev_private *)dev->priv;
+	np = dev->priv;
 	spin_lock(&np->lock);
 
 	do {
@@ -935,7 +938,7 @@
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 
@@ -1026,7 +1029,7 @@
 static void netdev_error(struct net_device *dev, int intr_status)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 
 	if (intr_status & IntrDrvRqst) {
 		/* Stop the down counter and turn interrupts back on. */
@@ -1055,7 +1058,7 @@
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	/* We should lock this segment of code for SMP eventually, although
@@ -1165,7 +1168,7 @@
 static int netdev_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	netif_stop_queue(dev);
@@ -1227,23 +1230,19 @@
 
 static void __devexit sundance_remove1 (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (dev) {
-		struct netdev_private *np = (void *)(dev->priv);
 		unregister_netdev(dev);
-#ifdef USE_IO_OPS
-		release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-#else
-		release_mem_region(pci_resource_start(pdev, 1),
-				   pci_id_tbl[np->chip_id].io_size);
+		pci_release_regions(pdev);
+#ifndef USE_IO_OPS
 		iounmap((char *)(dev->base_addr));
 #endif
 		kfree(dev);
 	}
 
-	pdev->driver_data = NULL;
+	pci_set_drvdata(pdev, NULL);
 }
 
 static struct pci_driver sundance_driver = {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.4.2/linux/drivers/net/sunlance.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/sunlance.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.105 2000/10/22 16:08:38 davem Exp $
+/* $Id: sunlance.c,v 1.107 2001/02/18 08:10:21 davem Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
@@ -965,9 +965,6 @@
 		sbus_writew(LE_C0_INEA | LE_C0_TDMD, lp->lregs + RDP);
 	}
 
-	if (!status)
-		MOD_INC_USE_COUNT;
-
 	return status;
 }
 
@@ -981,7 +978,6 @@
 	STOP_LANCE(lp);
 
 	free_irq(dev->irq, (void *) dev);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1467,6 +1463,7 @@
 	}
 
 	lp->dev = dev;
+	SET_MODULE_OWNER(dev);
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
 	dev->hard_start_xmit = &lance_start_xmit;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.4.2/linux/drivers/net/sunqe.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/sunqe.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.47 2000/10/22 16:08:38 davem Exp $
+/* $Id: sunqe.c,v 1.50 2001/02/18 08:10:21 davem Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
@@ -438,7 +438,7 @@
 						 len, 0);
 				skb->protocol = eth_type_trans(skb, qep->dev);
 				netif_rx(skb);
-				dev->last_rx = jiffies;
+				qep->dev->last_rx = jiffies;
 				qep->net_stats.rx_packets++;
 				qep->net_stats.rx_bytes += len;
 			}
@@ -503,16 +503,11 @@
 static int qe_open(struct net_device *dev)
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
-	int res;
 
 	qep->mconfig = (MREGS_MCONFIG_TXENAB |
 			MREGS_MCONFIG_RXENAB |
 			MREGS_MCONFIG_MBAENAB);
-	res = qe_init(qep, 0);
-	if (!res)
-		MOD_INC_USE_COUNT;
-
-	return res;
+	return qe_init(qep, 0);
 }
 
 static int qe_close(struct net_device *dev)
@@ -520,7 +515,6 @@
 	struct sunqe *qep = (struct sunqe *) dev->priv;
 
 	qe_stop(qep);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -882,6 +876,7 @@
 	}
 
 	for (i = 0; i < 4; i++) {
+		SET_MODULE_OWNER(qe_devs[i]);
 		qe_devs[i]->open = qe_open;
 		qe_devs[i]->stop = qe_close;
 		qe_devs[i]->hard_start_xmit = qe_start_xmit;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.4.2/linux/drivers/net/tlan.c	Mon Dec 11 13:38:29 2000
+++ linux/drivers/net/tlan.c	Tue Mar 20 12:05:00 2001
@@ -7,10 +7,10 @@
  *
  *  (C) 1997-1998 Caldera, Inc.
  *  (C) 1998 James Banks
- *  (C) 1999, 2000 Torben Mathiasen
+ *  (C) 1999-2001 Torben Mathiasen
  *
  *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
+ *  of the GNU General Public License, incorporated herein by reference.
  *
  ** This file is best viewed/edited with columns>=132.
  *
@@ -136,6 +136,28 @@
  *
  *	v1.12 Oct 12, 2000   - Minor fixes (memleak, init, etc.)
  *
+ * 	v1.13 Nov 28, 2000   - Stop flooding console with auto-neg issues
+ * 			       when link can't be established.
+ *			     - Added the bbuf option as a kernel parameter.
+ *			     - Fixed ioaddr probe bug.
+ *			     - Fixed stupid deadlock with MII interrupts.
+ *			     - Added support for speed/duplex selection with 
+ *			       multiple nics.
+ *			     - Added partly fix for TX Channel lockup with
+ *			       TLAN v1.0 silicon. This needs to be investigated
+ *			       further.
+ *
+ * 	v1.14 Dec 16, 2000   - Added support for servicing multiple frames per.
+ * 			       interrupt. Thanks goes to
+ * 			       Adam Keys <adam@ti.com>
+ * 			       Denis Beaudoin <dbeaudoin@ti.com>
+ * 			       for providing the patch.
+ * 			     - Fixed auto-neg output when using multiple
+ * 			       adapters.
+ * 			     - Converted to use new taskq interface.
+ *
+ * 	v1.14a Jan 6, 2001   - Minor adjustments (spinlocks, etc.)
+ *
  *******************************************************************************/
 
                                                                                 
@@ -159,17 +181,19 @@
 
 static	int		TLanDevicesInstalled;
 
-/* Force speed, duplex and aui settings */
-static	int		aui;
-static	int		duplex; 
-static	int		speed;
+/* Set speed, duplex and aui settings */
+static  int aui[MAX_TLAN_BOARDS];
+static  int duplex[MAX_TLAN_BOARDS];
+static  int speed[MAX_TLAN_BOARDS];
+static  int boards_found;
 
 MODULE_AUTHOR("Maintainer: Torben Mathiasen <torben.mathiasen@compaq.com>");
 MODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters");
-MODULE_PARM(aui, "i");
-MODULE_PARM(duplex, "i");
-MODULE_PARM(speed, "i");
+MODULE_PARM(aui, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i");
+MODULE_PARM(duplex, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i");
+MODULE_PARM(speed, "1-" __MODULE_STRING(MAX_TLAN_BOARDS) "i");
 MODULE_PARM(debug, "i");
+MODULE_PARM(bbuf, "i");
 EXPORT_NO_SYMBOLS;
 
 /* Define this to enable Link beat monitoring */
@@ -181,7 +205,7 @@
 static	int		bbuf;
 static	u8		*TLanPadBuffer;
 static	char		TLanSignature[] = "TLAN";
-static const char *tlan_banner = "ThunderLAN driver v1.12\n";
+static const char *tlan_banner = "ThunderLAN driver v1.14a\n";
 static int tlan_have_pci;
 static int tlan_have_eisa;
 
@@ -324,16 +348,19 @@
 TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type )
 {
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
+	unsigned long flags = 0;
+	
+	if (!in_irq())
+		spin_lock_irqsave(&priv->lock, flags);
 	if ( priv->timer.function != NULL &&
 		priv->timerType != TLAN_TIMER_ACTIVITY ) { 
-		spin_unlock_irqrestore(&priv->lock, flags);
+		if (!in_irq())
+			spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
 	priv->timer.function = &TLan_Timer;
-	spin_unlock_irqrestore(&priv->lock, flags);
+	if (!in_irq())
+		spin_unlock_irqrestore(&priv->lock, flags);
 
 	priv->timer.data = (unsigned long) dev;
 	priv->timerSetAt = jiffies;
@@ -375,7 +402,7 @@
 
 static void __devexit tlan_remove_one( struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata( pdev );
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 	
 	unregister_netdev( dev );
@@ -388,6 +415,7 @@
 	
 	kfree( dev );
 		
+	pci_set_drvdata( pdev, NULL );
 } 
 
 static struct pci_driver tlan_driver = {
@@ -404,7 +432,7 @@
 	printk(KERN_INFO "%s", tlan_banner);
 	
 	TLanPadBuffer = (u8 *) kmalloc(TLAN_MIN_FRAME_SIZE, 
-					(GFP_KERNEL | GFP_DMA));
+					GFP_KERNEL);
 
 	if (TLanPadBuffer == NULL) {
 		printk(KERN_ERR "TLAN: Could not allocate memory for pad buffer.\n");
@@ -426,18 +454,19 @@
 	printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d  EISA: %d\n", 
 		 TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s",
 		 tlan_have_pci, tlan_have_eisa);
-	
-	return ((TLanDevicesInstalled > 0) ? 0 : -ENODEV);
 
+	if (TLanDevicesInstalled == 0) {
+		kfree(TLanPadBuffer);
+		return -ENODEV;
+	}
+	return 0;
 }
 	
 
 static int __devinit tlan_init_one( struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
-	return TLan_probe1( pdev, pci_resource_start(pdev, 0), pdev->irq,
-			0, ent);
-
+	return TLan_probe1( pdev, -1, -1, 0, ent);
 }
 
 
@@ -468,6 +497,10 @@
 	TLanPrivateInfo    *priv;
 	u8		   pci_rev;
 	u16		   device_id;
+	int		   reg;
+
+	if (pdev && pci_enable_device(pdev))
+		return -EIO;
 
 	dev = init_etherdev(NULL, sizeof(TLanPrivateInfo));
 	if (dev == NULL) {
@@ -477,23 +510,35 @@
 	SET_MODULE_OWNER(dev);
 	
 	priv = dev->priv;
-		
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-	 
 
 	/* Is this a PCI device? */
 	if (pdev) {
+		u32 		   pci_io_base = 0;
+
 		priv->adapter = &board_info[ent->driver_data];
-		if (pci_enable_device(pdev)) {
+
+		pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev);
+
+		for ( reg= 0; reg <= 5; reg ++ ) {
+			if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) {
+				pci_io_base = pci_resource_start(pdev, reg);
+				TLAN_DBG( TLAN_DEBUG_GNRL, "IO mapping is available at %x.\n",
+						pci_io_base);
+				break;
+			}
+		}
+		if (!pci_io_base) {
+			printk(KERN_ERR "TLAN: No IO mappings available\n");
 			unregister_netdev(dev);
 			kfree(dev);
-			return -1;
+			return -ENODEV;
 		}
-		pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev);
+		
+		dev->base_addr = pci_io_base;
+		dev->irq = pdev->irq;
 		priv->adapterRev = pci_rev; 
 		pci_set_master(pdev);
-		pdev->driver_data = dev;
+		pci_set_drvdata(pdev, dev);
 
 	} else	{     /* EISA card */
 		/* This is a hack. We need to know which board structure
@@ -507,6 +552,8 @@
 			priv->adapter = &board_info[14];
 			priv->adapterRev = 10;			/* TLAN 1.0 */
 		}
+		dev->base_addr = ioaddr;
+		dev->irq = irq;
 	}
 
 	/* Kernel parameters */
@@ -522,21 +569,19 @@
 		}
 		debug = priv->debug = dev->mem_end;
 	} else {
-
-		if ( ( duplex != 1 ) && ( duplex != 2 ) ) 
-			duplex = 0;
-		
-		priv->duplex = duplex;
-
-		if ( ( speed != 10 ) && ( speed != 100 ) )
-			speed = 0;
-		
-		priv->aui   = aui;
-		priv->speed = speed;
+		priv->aui    = aui[boards_found];
+		priv->speed  = speed[boards_found];
+		priv->duplex = duplex[boards_found];
 		priv->debug = debug;
-		
 	}
 	
+	/* This will be used when we get an adapter error from
+	 * within our irq handler */
+	INIT_LIST_HEAD(&priv->tlan_tqueue.list);
+	priv->tlan_tqueue.sync = 0;
+	priv->tlan_tqueue.routine = (void *)(void*)TLan_tx_timeout;
+	priv->tlan_tqueue.data = dev;
+
 	spin_lock_init(&priv->lock);
 	
 	if (TLan_Init(dev)) {
@@ -547,6 +592,7 @@
 	} else {
 	
 	TLanDevicesInstalled++;
+	boards_found++;
 	
 	/* pdev is NULL if this is an EISA device */
 	if (pdev)
@@ -752,6 +798,7 @@
 	if ( priv->dmaStorage == NULL ) {
 		printk(KERN_ERR "TLAN:  Could not allocate lists and buffers for %s.\n",
 			dev->name );
+		release_region( dev->base_addr, 0x10 );
 		return -ENOMEM;
 	}
 	memset( priv->dmaStorage, 0, dma_size );
@@ -901,6 +948,7 @@
 	TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name);
 	
 	/* Ok so we timed out, lets see what we can do about it...*/
+	TLan_FreeLists( dev );
 	TLan_ResetLists( dev );		
 	TLan_ReadAndClearStats( dev, TLAN_IGNORE );
 	TLan_ResetAdapter( dev );
@@ -947,7 +995,7 @@
 	}
 
 	tail_list = priv->txList + priv->txTail;
-
+	
 	if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
 		netif_stop_queue(dev);
@@ -983,10 +1031,9 @@
 	tail_list->cStat = TLAN_CSTAT_READY;
 	if ( ! priv->txInProgress ) {
 		priv->txInProgress = 1;
-		outw( 0x4, dev->base_addr + TLAN_HOST_INT );
 		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Starting TX on buffer %d\n", priv->txTail );
 		outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM );
-		outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD );
+		outl( TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD );
 	} else {
 		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Adding buffer %d to TX channel\n", priv->txTail );
 		if ( priv->txTail == 0 ) {
@@ -1084,6 +1131,7 @@
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
 
 	netif_stop_queue(dev);
+	priv->neg_be_verbose = 0;
 
 	TLan_ReadAndClearStats( dev, TLAN_RECORD );
 	outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
@@ -1242,7 +1290,6 @@
 
 u32 TLan_HandleInvalid( struct net_device *dev, u16 host_int )
 {
-	host_int = 0;
 	/* printk( "TLAN:  Invalid interrupt on %s.\n", dev->name ); */
 	return 0;
 
@@ -1278,30 +1325,33 @@
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 	int		eoc = 0;
 	TLanList	*head_list;
-	u32		ack = 1;
-
+	u32		ack = 0;
+	u16		tmpCStat;
+	
 	TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
-	host_int = 0;
 	head_list = priv->txList + priv->txHead;
 
-	if ( ! bbuf ) {
-		dev_kfree_skb_irq( (struct sk_buff *) head_list->buffer[9].address );		
-		head_list->buffer[9].address = 0;
-	}
+	while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
+		ack++;
+		if ( ! bbuf ) {
+			dev_kfree_skb_any( (struct sk_buff *) head_list->buffer[9].address );
+			head_list->buffer[9].address = 0;
+		}
+	
+		if ( tmpCStat & TLAN_CSTAT_EOC )
+			eoc = 1;
+			
+		priv->stats.tx_bytes += head_list->frameSize;
 
-	if ( head_list->cStat & TLAN_CSTAT_EOC )
-		eoc = 1;
-	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
-		printk( "TLAN:  Received interrupt for uncompleted TX frame.\n" );
+		head_list->cStat = TLAN_CSTAT_UNUSED;
+		netif_start_queue(dev);		
+		CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS ); 
+		head_list = priv->txList + priv->txHead;
 	}
 
-	priv->stats.tx_bytes += head_list->frameSize;
-
-	head_list->cStat = TLAN_CSTAT_UNUSED;
+	if (!ack)
+		printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n");
 	
-	netif_start_queue(dev);
-	
-	CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
 	if ( eoc ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
 		head_list = priv->txList + priv->txHead;
@@ -1312,7 +1362,7 @@
 			priv->txInProgress = 0;
 		}
 	}
-
+	
 	if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
 		TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
 		if ( priv->timer.function == NULL ) {
@@ -1353,7 +1403,6 @@
 
 u32 TLan_HandleStatOverflow( struct net_device *dev, u16 host_int )
 {
-	host_int = 0;
 	TLan_ReadAndClearStats( dev, TLAN_RECORD );
 
 	return 1;
@@ -1384,87 +1433,95 @@
 	 *	of the list.  If the frame was the last in the Rx
 	 *	channel (EOC), the function restarts the receive channel
 	 *	by sending an Rx Go command to the adapter.  Then it
-	 *	activates/continues the the activity LED.
+	 *	activates/continues the activity LED.
 	 *
 	 **************************************************************/
 
 u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
-	u32		ack = 1;
+	u32		ack = 0;
 	int		eoc = 0;
 	u8		*head_buffer;
 	TLanList	*head_list;
 	struct sk_buff	*skb;
 	TLanList	*tail_list;
 	void		*t;
+	u32		frameSize;
+	u16		tmpCStat;
 
 	TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
-	host_int = 0;
 	head_list = priv->rxList + priv->rxHead;
-	tail_list = priv->rxList + priv->rxTail;
-
-	if ( head_list->cStat & TLAN_CSTAT_EOC ) {
-		eoc = 1;
-	}
+	
+	while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
+		frameSize = head_list->frameSize;
+		ack++;
+		if (tmpCStat & TLAN_CSTAT_EOC)
+			eoc = 1;
+		
+		if (bbuf) {
+			skb = dev_alloc_skb(frameSize + 7);
+			if (skb == NULL)
+				printk(KERN_INFO "TLAN: Couldn't allocate memory for received data.\n");
+			else {
+				head_buffer = priv->rxBuffer + (priv->rxHead * TLAN_MAX_FRAME_SIZE);
+				skb->dev = dev;
+				skb_reserve(skb, 2);
+				t = (void *) skb_put(skb, frameSize);
+		
+				priv->stats.rx_bytes += head_list->frameSize;
 
-	if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) {
-		printk( "TLAN:  Received interrupt for uncompleted RX frame.\n" );
-	} else if ( bbuf ) {
-		skb = dev_alloc_skb( head_list->frameSize + 7 );
-		if ( skb == NULL ) { 
-			printk( "TLAN:  Couldn't allocate memory for received data.\n" );
+				memcpy( t, head_buffer, frameSize );
+				skb->protocol = eth_type_trans( skb, dev );
+				netif_rx( skb );
+			}
 		} else {
-			head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE );
-			skb->dev = dev;
-			skb_reserve( skb, 2 );
-			t = (void *) skb_put( skb, head_list->frameSize );
-
-			priv->stats.rx_bytes += head_list->frameSize;
-
-			memcpy( t, head_buffer, head_list->frameSize );
-			skb->protocol = eth_type_trans( skb, dev );
-			netif_rx( skb );
-		}
-	} else {
-		struct sk_buff *new_skb;
+			struct sk_buff *new_skb;
 		
-		/*
-		 *	I changed the algorithm here. What we now do
-		 *	is allocate the new frame. If this fails we
-		 *	simply recycle the frame.
-		 */
+			/*
+		 	*	I changed the algorithm here. What we now do
+		 	*	is allocate the new frame. If this fails we
+		 	*	simply recycle the frame.
+		 	*/
 		
-		new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
-		if ( new_skb != NULL ) {
-			/* If this ever happened it would be a problem */
-			/* not any more - ac */
-			skb = (struct sk_buff *) head_list->buffer[9].address;
-			head_list->buffer[9].address = 0;
-			skb_trim( skb, head_list->frameSize );
+			new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
+			
+			if ( new_skb != NULL ) {
+				/* If this ever happened it would be a problem */
+				/* not any more - ac */
+				skb = (struct sk_buff *) head_list->buffer[9].address;
+				skb_trim( skb, frameSize );
+
+				priv->stats.rx_bytes += frameSize;
+
+				skb->protocol = eth_type_trans( skb, dev );
+				netif_rx( skb );
+	
+				new_skb->dev = dev;
+				skb_reserve( new_skb, 2 );
+				t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
+				head_list->buffer[0].address = virt_to_bus( t );
+				head_list->buffer[8].address = (u32) t;
+				head_list->buffer[9].address = (u32) new_skb;
+			} else 
+				printk(KERN_WARNING "TLAN:  Couldn't allocate memory for received data.\n" );
+		}
+
+		head_list->forward = 0;
+		head_list->cStat = 0;
+		tail_list = priv->rxList + priv->rxTail;
+		tail_list->forward = virt_to_bus( head_list );
 
-			priv->stats.rx_bytes += head_list->frameSize;
+		CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );
+		CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );
+		head_list = priv->rxList + priv->rxHead;
+	}
 
-			skb->protocol = eth_type_trans( skb, dev );
-			netif_rx( skb );
+	if (!ack)
+		printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n");
 	
-			new_skb->dev = dev;
-			skb_reserve( new_skb, 2 );
-			t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
-			head_list->buffer[0].address = virt_to_bus( t );
-			head_list->buffer[9].address = (u32) new_skb;
-		}
-		else
-			printk(KERN_WARNING "TLAN:  Couldn't allocate memory for received data.\n" );
-	}
 
-	head_list->forward = 0;
-	head_list->frameSize = TLAN_MAX_FRAME_SIZE;
-	head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
-	tail_list->forward = virt_to_bus( head_list );
 
-	CIRC_INC( priv->rxHead, TLAN_NUM_RX_LISTS );
-	CIRC_INC( priv->rxTail, TLAN_NUM_RX_LISTS );
 
 	if ( eoc ) { 
 		TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
@@ -1489,7 +1546,7 @@
 	}
 
 	dev->last_rx = jiffies;
-
+	
 	return ack;
 
 } /* TLan_HandleRxEOF */
@@ -1516,7 +1573,6 @@
 
 u32 TLan_HandleDummy( struct net_device *dev, u16 host_int )
 {
-	host_int = 0;
 	printk( "TLAN:  Test interrupt on %s.\n", dev->name );
 	return 1;
 
@@ -1549,13 +1605,14 @@
 {
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 	TLanList		*head_list;
-	u32				ack = 1;
-
+	u32			ack = 1;
+	
 	host_int = 0;
 	if ( priv->tlanRev < 0x30 ) {
 		TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT:  Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
 		head_list = priv->txList + priv->txHead;
 		if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) {
+			netif_stop_queue(dev);
 			outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM );
 			ack |= TLAN_HC_GO;
 		} else {
@@ -1602,14 +1659,16 @@
 	
 	ack = 1;
 	if ( host_int & TLAN_HI_IV_MASK ) {
+		netif_stop_queue( dev );
 		error = inl( dev->base_addr + TLAN_CH_PARM );
 		printk( "TLAN:  %s: Adaptor Error = 0x%x\n", dev->name, error );
 		TLan_ReadAndClearStats( dev, TLAN_RECORD );
 		outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
-		TLan_FreeLists( dev );
-		TLan_ResetLists( dev );
-		TLan_ResetAdapter( dev );
-		netif_start_queue(dev);
+		
+		queue_task(&priv->tlan_tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		
+		netif_wake_queue(dev);
 		ack = 0;
 	} else {
 		TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name );
@@ -1670,7 +1729,6 @@
 	TLanList	*head_list;
 	u32		ack = 1;
 
-	host_int = 0;
 	if (  priv->tlanRev < 0x30 ) {
 		TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE:  Handling RX EOC (Head=%d Tail=%d) -- IRQ\n", priv->rxHead, priv->rxTail );
 		head_list = priv->rxList + priv->rxHead;
@@ -1826,6 +1884,7 @@
 		}
 		list->buffer[2].count = 0;
 		list->buffer[2].address = 0;
+		list->buffer[9].address = 0;
 	}
 
 	priv->rxHead = 0;
@@ -1848,6 +1907,7 @@
 				t = (void *) skb_put( skb, TLAN_MAX_FRAME_SIZE );
 			}
 			list->buffer[0].address = virt_to_bus( t );
+			list->buffer[8].address = (u32) t;
 			list->buffer[9].address = (u32) skb;
 		}
 		list->buffer[1].count = 0;
@@ -1902,7 +1962,7 @@
 	 *		io_base		Base IO port of the device of
 	 *				which to print DIO registers.
 	 *
-	 *	This function prints out all the the internal (DIO)
+	 *	This function prints out all the internal (DIO)
 	 *	registers of a TLAN chip.
 	 *
 	 **************************************************************/
@@ -2091,8 +2151,8 @@
 
 /*  5.	Load Ld_Tmr and Ld_Thr in HOST_CMD. */
 
- 	outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD );
- 	outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD );
+ 	outl( TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD );
+ 	outl( TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD );
 
 /*  6.	Unreset the MII by setting NMRST (in NetSio) to 1. */
 
@@ -2108,6 +2168,7 @@
 	}
 	TLan_PhyDetect( dev );
 	data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
+	
 	if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) {
 		data |= TLAN_NET_CFG_BIT;
 		if ( priv->aui == 1 ) {
@@ -2119,6 +2180,7 @@
 			TLan_DioWrite8( dev->base_addr, TLAN_ACOMMIT, 0x08 );
 		}
 	}
+
 	if ( priv->phyNum == 0 ) {
 		data |= TLAN_NET_CFG_PHY_EN;
 	}
@@ -2161,7 +2223,7 @@
 		data |= TLAN_NET_MASK_MASK7; 
 	}
 	TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data );
-	TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, TLAN_MAX_FRAME_SIZE );
+	TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 );
 	TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 );
 	TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 );
 	
@@ -2576,7 +2638,12 @@
 		/* Wait for 8 sec to give the process
 		 * more time.  Perhaps we should fail after a while.
 		 */
-		printk( "TLAN: Giving autonegotiation more time.\n" );
+		 if (!priv->neg_be_verbose++) {
+			 printk(KERN_INFO "TLAN:  Giving autonegotiation more time.\n");
+		 	 printk(KERN_INFO "TLAN:  Please check that your adapter has\n");
+		 	 printk(KERN_INFO "TLAN:  been properly connected to a HUB or Switch.\n");
+			 printk(KERN_INFO "TLAN:  Trying to establish link in the background...\n");
+		 }
 		TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN );
 		return;
 	}
@@ -2720,8 +2787,9 @@
 	err = FALSE;
 	outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
 	sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
-
-	spin_lock_irqsave(&priv->lock, flags);
+	
+	if (!in_irq())
+		spin_lock_irqsave(&priv->lock, flags);
 
 	TLan_MiiSync(dev->base_addr);
 
@@ -2767,8 +2835,9 @@
 		TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
 
 	*val = tmp;
-
-	spin_unlock_irqrestore(&priv->lock, flags);
+	
+	if (!in_irq())
+		spin_unlock_irqrestore(&priv->lock, flags);
 
 	return err;
 
@@ -2885,8 +2954,9 @@
 
 	outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
 	sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
-
-	spin_lock_irqsave(&priv->lock, flags);
+	
+	if (!in_irq())
+		spin_lock_irqsave(&priv->lock, flags);
 
 	TLan_MiiSync( dev->base_addr );
 
@@ -2907,8 +2977,9 @@
 
 	if ( minten )
 		TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
-
-	spin_unlock_irqrestore(&priv->lock, flags);
+	
+	if (!in_irq())
+		spin_unlock_irqrestore(&priv->lock, flags);
 
 } /* TLan_MiiWriteReg */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tlan.h linux/drivers/net/tlan.h
--- v2.4.2/linux/drivers/net/tlan.h	Mon Dec 11 13:01:14 2000
+++ linux/drivers/net/tlan.h	Tue Mar 20 12:05:00 2001
@@ -8,10 +8,10 @@
  *  by James Banks
  *
  *  (C) 1997-1998 Caldera, Inc.
- *  (C) 1999-2000 Torben Mathiasen
+ *  (C) 1999-2001 Torben Mathiasen
  * 
  *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
+ *  of the GNU General Public License, incorporated herein by reference.
  *
  ** This file is best viewed/edited with tabstop=4, colums>=132
  *
@@ -36,11 +36,11 @@
 #define FALSE			0
 #define TRUE			1
 
-#define TLAN_MIN_FRAME_SIZE	60
-#define TLAN_MAX_FRAME_SIZE	1536
+#define TLAN_MIN_FRAME_SIZE	64
+#define TLAN_MAX_FRAME_SIZE	1600
 
-#define TLAN_NUM_RX_LISTS	4
-#define TLAN_NUM_TX_LISTS	8
+#define TLAN_NUM_RX_LISTS	32
+#define TLAN_NUM_TX_LISTS	64
 
 #define TLAN_IGNORE		0
 #define TLAN_RECORD		1
@@ -53,7 +53,7 @@
 #define TLAN_DEBUG_PROBE	0x0010
 
 #define TX_TIMEOUT		(10*HZ)	 /* We need time for auto-neg */
-
+#define MAX_TLAN_BOARDS		8	 /* Max number of boards installed at a time */
 
 
 	/*****************************************************************
@@ -209,6 +209,8 @@
 	spinlock_t		lock;
 	u8			link;
 	u8			is_eisa;
+	struct tq_struct	tlan_tqueue;
+	u8			neg_be_verbose;
 } TLanPrivateInfo;
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/Config.in linux/drivers/net/tokenring/Config.in
--- v2.4.2/linux/drivers/net/tokenring/Config.in	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/Config.in	Tue Mar  6 19:28:35 2001
@@ -5,21 +5,29 @@
 mainmenu_option next_comment
 comment 'Token Ring devices'
 
-bool 'Token Ring driver support' CONFIG_TR
+# So far, we only have PCI, ISA, and MCA token ring devices
+if [ "$CONFIG_PCI" = "y" -o "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+   bool 'Token Ring driver support' CONFIG_TR
+else
+   define_bool CONFIG_TR n
+fi
+
 if [ "$CONFIG_TR" != "n" ]; then
-   dep_tristate '  IBM Tropic chipset based adapter support' CONFIG_IBMTR $CONFIG_TR
-   dep_tristate '  IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR
-   dep_tristate '  IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR
-   dep_tristate '  Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR $CONFIG_TR
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+      tristate '  IBM Tropic chipset based adapter support' CONFIG_IBMTR
+   fi
+   dep_tristate '  IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR $CONFIG_PCI
+   dep_tristate '  IBM Lanstreamer chipset PCI adapter support' CONFIG_IBMLS $CONFIG_TR $CONFIG_PCI
+   tristate '  Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR
    if [ "$CONFIG_TMS380TR" != "n" ]; then
-      dep_tristate '    Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR
-      dep_tristate '    Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_TMS380TR
-      dep_tristate '    Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR
-      if [ "$CONFIG_MCA" = "y" ]; then 
-         dep_tristate '    Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR
-      fi
+      dep_tristate '    Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_PCI
+      dep_tristate '    Generic TMS380 ISA support' CONFIG_TMSISA $CONFIG_ISA
+      dep_tristate '    Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_PCI
+      dep_tristate '    Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_MCA
+   fi
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+      tristate '  SMC ISA/MCA adapter support' CONFIG_SMCTR
    fi
-   dep_tristate '  SMC ISA/MCA adapter support' CONFIG_SMCTR $CONFIG_TR
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.4.2/linux/drivers/net/tokenring/ibmtr.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/ibmtr.c	Tue Mar 20 12:05:00 2001
@@ -255,12 +255,16 @@
  *
  *	We expect ibmtr_probe to be called once for each device entry
  *	which references it.
+ *
+ *	Argument 'dev' should never be NULL.  If we are built into
+ *	the kernel, Space.c passed up a net_device.  If we are
+ *	-DMODULE, init_module allocates net_devices for us.
  */
  
 int __init ibmtr_probe(struct net_device *dev)
 {
         int i;
-        int base_addr = dev ? dev->base_addr : 0;
+        int base_addr = dev->base_addr;
 
         if (base_addr > 0x1ff) 
         { 
@@ -301,7 +305,7 @@
 
 #ifndef MODULE
 #ifndef PCMCIA
-	dev = init_trdev(dev,0);
+	dev = init_trdev(dev, 0);
 #endif
 #endif
 
@@ -1877,8 +1881,11 @@
 		mem[i] = 0;
 		dev_ibmtr[i] = NULL;
                 dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0);
-                if (dev_ibmtr[i] == NULL)
-                        return -ENOMEM;
+                if (dev_ibmtr[i] == NULL) {
+			if (i == 0)
+                        	return -ENOMEM;
+			break;
+		}
 
 	        dev_ibmtr[i]->base_addr = io[i];
 	        dev_ibmtr[i]->irq       = irq[i];
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/lanstreamer.c linux/drivers/net/tokenring/lanstreamer.c
--- v2.4.2/linux/drivers/net/tokenring/lanstreamer.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/lanstreamer.c	Tue Mar 20 12:04:59 2001
@@ -59,12 +59,10 @@
  *  03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing
  *		malloc free checks, reviewed code. <alan@redhat.com>
  *  03/13/00 - Added spinlocks for smp
+ *  03/08/01 - Added support for module_init() and module_exit()
  *  
  *  To Do:
  *
- *  1) Test Network Monitor Mode
- *  2) Add auto reset logic on adapter errors
- *  3) Test with varying options
  *
  *  If Problems do Occur
  *  Most problems can be rectified by either closing and opening the interface
@@ -123,7 +121,14 @@
  * Official releases will only have an a.b.c version number format.
  */
 
-static char *version = "LanStreamer.c v0.3.1 03/13/99 - Mike Sullivan";
+static char *version = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
+
+static struct pci_device_id streamer_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
+	{}	/* terminating entry */
+};
+MODULE_DEVICE_TABLE(pci,streamer_pci_tbl);
+
 
 static char *open_maj_error[] = {
 	"No error", "Lobe Media Test", "Physical Insertion",
@@ -170,8 +175,7 @@
 MODULE_PARM(message_level,
 	    "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");
 
-static int streamer_scan(struct net_device *dev);
-static int streamer_init(struct net_device *dev);
+static int streamer_reset(struct net_device *dev);
 static int streamer_open(struct net_device *dev);
 static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
 static int streamer_close(struct net_device *dev);
@@ -186,98 +190,190 @@
 static void streamer_asb_bh(struct net_device *dev);
 #if STREAMER_NETWORK_MONITOR
 #ifdef CONFIG_PROC_FS
+static int streamer_proc_info(char *buffer, char **start, off_t offset,
+			      int length, int *eof, void *data);
 static int sprintf_info(char *buffer, struct net_device *dev);
+struct streamer_private *dev_streamer=NULL;
 #endif
 #endif
 
-int __init streamer_probe(struct net_device *dev)
+static int __devinit streamer_init_one(struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
 {
-	int cards_found;
-
-	cards_found = streamer_scan(dev);
-	return cards_found ? 0 : -ENODEV;
-}
-
-static int __init streamer_scan(struct net_device *dev)
-{
-	struct pci_dev *pci_device = NULL;
+  struct net_device *dev=NULL;
 	struct streamer_private *streamer_priv;
-	int card_no = 0;
-	if (pci_present()) 
-	{
-		while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_TR, pci_device))) 
-		{
-			if (pci_enable_device(pci_device))
-				continue;
-			pci_set_master(pci_device);
+  __u32 pio_start, pio_end, pio_flags, pio_len;
+  __u32 mmio_start, mmio_end, mmio_flags, mmio_len;
+  int rc=0;
+  static int card_no=-1;
 
-			/* Check to see if io has been allocated, if so, we've already done this card,
-			   so continue on the card discovery loop  */
+#if STREAMER_DEBUG
+  printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev);
+#endif
 
-			if (check_region(pci_resource_start(pci_device,0), STREAMER_IO_SPACE)) 
-			{
 				card_no++;
-				continue;
-			}
-
-			streamer_priv = kmalloc(sizeof(struct streamer_private), GFP_KERNEL);
-			if(streamer_priv==NULL)
-			{
+  dev=init_trdev(dev, sizeof(*streamer_priv));
+  if(dev==NULL) {
 				printk(KERN_ERR "lanstreamer: out of memory.\n");
-				break;
-			}
-			memset(streamer_priv, 0, sizeof(struct streamer_private));
-			init_waitqueue_head(&streamer_priv->srb_wait);
-			init_waitqueue_head(&streamer_priv->trb_wait);
-#ifndef MODULE
-			dev = init_trdev(dev, 0);
-			if(dev==NULL)
-			{
-				kfree(streamer_priv);
-				printk(KERN_ERR "lanstreamer: out of memory.\n");
-				break;
+    return -ENOMEM;
 			}
 			SET_MODULE_OWNER(dev);
+  streamer_priv=dev->priv;
+
+#if STREAMER_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+  if (!dev_streamer) {
+    create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); 
+  }
+  streamer_priv->next=dev_streamer;
+  dev_streamer=streamer_priv;
 #endif
-			dev->priv = (void *) streamer_priv;
-#if STREAMER_DEBUG
-			printk("pci_device: %p, dev:%p, dev->priv: %p\n",
-			       pci_device, dev, dev->priv);
 #endif
-			dev->irq = pci_device->irq;
-			dev->base_addr = pci_resource_start(pci_device, 0);
-			dev->init = &streamer_init;
-			streamer_priv->streamer_card_name = (char *)pci_device->resource[0].name;
-			streamer_priv->streamer_mmio = 
-				ioremap(pci_resource_start(pci_device, 1), 256);
-
-			if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000))
-				streamer_priv->pkt_buf_sz = PKT_BUF_SZ;
-			else
-				streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no];
-
-			streamer_priv->streamer_ring_speed = ringspeed[card_no];
-			streamer_priv->streamer_message_level = message_level[card_no];
-
-			if (streamer_init(dev) == -1) {
-				unregister_netdevice(dev);
-				kfree(dev->priv);
-				return 0;
+  
+  if (pci_enable_device(pdev)) {
+    printk(KERN_ERR "lanstreamer: unable to enable pci device\n");
+    rc=-EIO;
+    goto err_out;
+  }
+  
+  pci_set_master(pdev);
+  
+  pio_start = pci_resource_start(pdev, 0);
+  pio_end = pci_resource_end(pdev, 0);
+  pio_flags = pci_resource_flags(pdev, 0);
+  pio_len = pci_resource_len(pdev, 0);
+  
+  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);
+  
+#if STREAMER_DEBUG
+  printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n",
+	 pio_start, pio_end, pio_len, pio_flags);
+  printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n",
+	 mmio_start, mmio_end, mmio_flags, mmio_len);
+#endif
+
+  if (!request_region(pio_start, pio_len, "lanstreamer")) {
+    printk(KERN_ERR "lanstreamer: unable to get pci io addr %x\n",pio_start);
+    rc= -EBUSY;
+    goto err_out;
+  }
+
+  if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) {
+    printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %x\n",mmio_start);
+    rc= -EBUSY;
+    goto err_out_free_pio;
+  }
+
+  streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len);
+  if (streamer_priv->streamer_mmio == NULL) {
+    printk(KERN_ERR "lanstreamer: unable to remap MMIO %x\n",mmio_start);
+    rc= -EIO;
+    goto err_out_free_mmio;
 			}
 
+  init_waitqueue_head(&streamer_priv->srb_wait);
+  init_waitqueue_head(&streamer_priv->trb_wait);
+
 			dev->open = &streamer_open;
 			dev->hard_start_xmit = &streamer_xmit;
 			dev->change_mtu = &streamer_change_mtu;
-
 			dev->stop = &streamer_close;
 			dev->do_ioctl = NULL;
 			dev->set_multicast_list = &streamer_set_rx_mode;
 			dev->get_stats = &streamer_get_stats;
 			dev->set_mac_address = &streamer_set_mac_address;
-			return 1;
+  dev->irq = pdev->irq;
+  dev->base_addr=pio_start;
+  
+  streamer_priv->streamer_card_name = (char *)pdev->resource[0].name;
+  streamer_priv->pci_dev=pdev;
+  
+  if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000))
+    streamer_priv->pkt_buf_sz = PKT_BUF_SZ;
+  else
+    streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no];
+  
+  streamer_priv->streamer_ring_speed = ringspeed[card_no];
+  streamer_priv->streamer_message_level = message_level[card_no];
+
+  pdev->driver_data=dev;
+
+  spin_lock_init(&streamer_priv->streamer_lock);
+  
+  printk("%s \n", version);
+  printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
+	 streamer_priv->streamer_card_name,
+	 (unsigned int) dev->base_addr,
+	 streamer_priv->streamer_mmio, 
+	 dev->irq);
+
+  if (!streamer_reset(dev)) {
+    return 0;
+  }
+
+  iounmap(streamer_priv->streamer_mmio);
+err_out_free_mmio:
+  release_mem_region(mmio_start, mmio_len);
+err_out_free_pio:
+  release_region(pio_start, pio_len);
+err_out:
+  unregister_trdev(dev);
+  kfree(dev);
+#if STREAMER_DEBUG
+  printk("lanstreamer: Exit error %x\n",rc);
+#endif
+  return rc;
+}
+
+static void __devexit streamer_remove_one(struct pci_dev *pdev) {
+  struct net_device *dev=pdev->driver_data;
+  struct streamer_private *streamer_priv;
+
+#if STREAMER_DEBUG
+  printk("lanstreamer::streamer_remove_one entry pdev %p\n",pdev);
+#endif
+
+  if (dev == NULL) {
+    printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev is NULL\n");
+    return;
 		}
+
+  streamer_priv=dev->priv;
+  if (streamer_priv == NULL) {
+    printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n");
+    return;
 	}
-	return 0;
+
+#if STREAMER_NETWORK_MONITOR
+#ifdef CONFIG_PROC_FS
+  {
+    struct streamer_private *slast;
+    struct streamer_private *scurrent;
+    if (streamer_priv == dev_streamer) {
+      dev_streamer=dev_streamer->next;
+    } else {
+      for(slast=scurrent=dev_streamer; dev_streamer; slast=scurrent, scurrent=scurrent->next) {
+	if (scurrent == streamer_priv) {
+	  slast->next=scurrent->next;
+	  break;
+	}
+      }
+    }
+    if (!dev_streamer) {
+      remove_proc_entry("net/streamer_tr", NULL);
+    }
+  }
+#endif
+#endif
+
+  unregister_trdev(dev);
+  release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0));
+  release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1));
+  kfree(dev);
+  pdev->driver_data=NULL;
 }
 
 
@@ -424,32 +520,6 @@
 	return 0;
 }
 
-static int __init streamer_init(struct net_device *dev) 
-{
-        struct streamer_private *streamer_priv;
-	__u8 *streamer_mmio;
-	int rc;
-  
-	streamer_priv=(struct streamer_private *)dev->priv;
-	streamer_mmio=streamer_priv->streamer_mmio;
-
-	spin_lock_init(&streamer_priv->streamer_lock);
-  
-	printk("%s \n", version);
-	printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
-	       streamer_priv->streamer_card_name,
-	       (unsigned int) dev->base_addr,
-	       streamer_priv->streamer_mmio, 
-	       dev->irq);
-
-	request_region(dev->base_addr, STREAMER_IO_SPACE, "streamer");
-
-	rc=streamer_reset(dev);
-	return rc;
-}
-  
-
-
 static int streamer_open(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
@@ -465,7 +535,7 @@
 	        rc=streamer_reset(dev);
 	}
 
-	if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "streamer", dev)) {
+	if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "lanstreamer", dev)) {
 		return -EAGAIN;
 	}
 #if STREAMER_DEBUG
@@ -563,7 +633,7 @@
 		 * timed out.
 		 */
 		writew(srb_open + 2, streamer_mmio + LAPA);
-		srb_word = ntohs(readw(streamer_mmio + LAPD)) & 0xFF;
+		srb_word = ntohs(readw(streamer_mmio + LAPD)) >> 8;
 		if (srb_word == STREAMER_CLEAR_RET_CODE) {
 			printk(KERN_WARNING "%s: Adapter Open time out or error.\n",
 			       dev->name);
@@ -1618,27 +1688,24 @@
 static int streamer_proc_info(char *buffer, char **start, off_t offset,
 			      int length, int *eof, void *data)
 {
+  struct streamer_private *sdev=NULL;
 	struct pci_dev *pci_device = NULL;
 	int len = 0;
 	off_t begin = 0;
 	off_t pos = 0;
 	int size;
 
-	struct device *dev;
-
+  struct net_device *dev;
 
 	size = sprintf(buffer, "IBM LanStreamer/MPC Chipset Token Ring Adapters\n");
 
 	pos += size;
 	len += size;
 
-	while ((pci_device = pci_find_device(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, pci_device))) 
-	{
+  for(sdev=dev_streamer; sdev; sdev=sdev->next) {
+    pci_device=sdev->pci_dev;
+    dev=pci_device->driver_data;
 
-		for (dev = dev_base; dev != NULL; dev = dev->next) 
-		{
-		        if (dev->base_addr == pci_device->resource[0].start) 
-			{       /* Yep, a Streamer device */
 				size = sprintf_info(buffer + len, dev);
 				len += size;
 				pos = begin + len;
@@ -1649,9 +1716,7 @@
 				}
 				if (pos > offset + length)
 					break;
-			}	/* if */
 		}		/* for */
-	}			/* While */
 
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin);	/* Start slop */
@@ -1743,66 +1808,34 @@
 #endif
 #endif
 
-#ifdef MODULE
-
-static struct net_device *dev_streamer[STREAMER_MAX_ADAPTERS];
-
-int init_module(void)
-{
-	int i;
-
-#if STREAMER_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-	create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); 
-#endif
+static void streamer_suspend(struct pci_dev *pdev) {
+#if STREAMER_DEBUG
+  printk("lanstreamer::streamer_suspend entry pdev %p\n",pdev);
 #endif
-	for (i = 0; (i < STREAMER_MAX_ADAPTERS); i++) 
-	{
-		dev_streamer[i] = NULL;
-		dev_streamer[i] = init_trdev(dev_streamer[i], 0);
-		SET_MODULE_OWNER(dev_streamer[i]);
-		if (dev_streamer[i] == NULL)
-			return -ENOMEM;
-
-		dev_streamer[i]->init = &streamer_probe;
-
-		if (register_trdev(dev_streamer[i]) != 0) {
-			kfree(dev_streamer[i]);
-			dev_streamer[i] = NULL;
-			if (i == 0) 
-			{
-				printk(KERN_INFO "Streamer: No IBM LanStreamer PCI Token Ring cards found in system.\n");
-				return -EIO;
-			} else {
-				printk(KERN_INFO "Streamer: %d IBM LanStreamer PCI Token Ring card(s) found in system.\n", i);
-				return 0;
-			}
-		}
-	}
+}
 
-	return 0;
+static void streamer_resume(struct pci_dev *pdev) {
+#if STREAMER_DEBUG
+  printk("lanstreamer::streamer_resume entry pdev %p\n",pdev);
+#endif
 }
 
-void cleanup_module(void)
-{
-	int i;
-	struct streamer_private *streamer_priv;
+static struct pci_driver streamer_pci_driver = {
+  name:       "lanstreamer",
+  id_table:   streamer_pci_tbl,
+  probe:      streamer_init_one,
+  remove:     streamer_remove_one,
+  suspend:    streamer_suspend,
+  resume:     streamer_resume,
+};
 
-	for (i = 0; i < STREAMER_MAX_ADAPTERS; i++)
-		if (dev_streamer[i]) {
-			unregister_trdev(dev_streamer[i]);
-			release_region(dev_streamer[i]->base_addr, STREAMER_IO_SPACE);
-			streamer_priv=(struct streamer_private *)dev_streamer[i]->priv;
-			kfree(streamer_priv->streamer_rx_ring);
-			kfree(streamer_priv->streamer_tx_ring);
-			kfree(dev_streamer[i]->priv);
-			kfree(dev_streamer[i]);
-			dev_streamer[i] = NULL;
-		}
-#if STREAMER_NETWORK_MONITOR
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("net/streamer_tr", NULL);
-#endif
-#endif
+static int __init streamer_init_module(void) {
+  return pci_module_init(&streamer_pci_driver);
 }
-#endif				/* MODULE */
+
+static void __exit streamer_cleanup_module(void) {
+  pci_unregister_driver(&streamer_pci_driver);
+}
+
+module_init(streamer_init_module);
+module_exit(streamer_cleanup_module);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/lanstreamer.h linux/drivers/net/tokenring/lanstreamer.h
--- v2.4.2/linux/drivers/net/tokenring/lanstreamer.h	Tue Mar 21 14:43:39 2000
+++ linux/drivers/net/tokenring/lanstreamer.h	Tue Mar 20 12:04:59 2001
@@ -257,6 +257,8 @@
 	__u16 arb;
 	__u16 asb;
 
+        struct streamer_private *next;
+        struct pci_dev *pci_dev;
 	__u8 *streamer_mmio;
         char *streamer_card_name;
  
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- v2.4.2/linux/drivers/net/tokenring/olympic.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/olympic.c	Tue Mar 20 12:05:00 2001
@@ -1,6 +1,6 @@
 /*
  *   olympic.c (c) 1999 Peter De Schrijver All Rights Reserved
- *		   1999 Mike Phillips (phillim@amtrak.com)
+ *		   1999 Mike Phillips (mikep@linuxtr.net)
  *
  *  Linux driver for IBM PCI tokenring cards based on the Pit/Pit-Phy/Olympic
  *  chipset. 
@@ -38,10 +38,11 @@
  *            Fixing the hardware descriptors was another matter,
  *            because they weren't going through read[wl](), there all
  *            the results had to be in memory in le32 values. kdaaker
- *
+ * 12/23/00 - Added minimal Cardbus support (Thanks Donald).
  *
  *  To Do:
- *
+ *           Complete full Cardbus / hot-swap support.
+ * 
  *  If Problems do Occur
  *  Most problems can be rectified by either closing and opening the interface
  *  (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult
@@ -99,7 +100,7 @@
  */
 
 static char *version = 
-"Olympic.c v0.5.0 3/10/00 - Peter De Schrijver & Mike Phillips" ; 
+"Olympic.c v0.5.C 12/23/00 - Peter De Schrijver & Mike Phillips" ; 
 
 static struct pci_device_id olympic_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR_WAKE, PCI_ANY_ID, PCI_ANY_ID, },
@@ -191,11 +192,9 @@
 			if (pci_enable_device(pci_device))
 				continue;
 
-			/* These lines are needed by the PowerPC, it appears
-that these flags
-			 * are not being set properly for the PPC, this may
-well be fixed with
-			 * the new PCI code */			
+			/* These lines are needed by the PowerPC, it appears that these flags
+			 * are not being set properly for the PPC, this may well be fixed with
+			 * the new PCI code */ 
 			pci_read_config_word(pci_device, PCI_COMMAND, &pci_command);
 			pci_command |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
 			pci_write_config_word(pci_device, PCI_COMMAND,pci_command);
@@ -216,7 +215,11 @@
 			init_waitqueue_head(&olympic_priv->srb_wait);
 			init_waitqueue_head(&olympic_priv->trb_wait);
 #ifndef MODULE
-			dev=init_trdev(dev, 0);
+			dev = init_trdev(NULL, 0);
+			if (!dev) {
+				kfree(olympic_priv);
+				return 0;
+			}
 #endif
 			dev->priv=(void *)olympic_priv;
 #if OLYMPIC_DEBUG  
@@ -224,8 +227,9 @@
 #endif
 			dev->irq=pci_device->irq;
 			dev->base_addr=pci_resource_start(pci_device, 0);
-			dev->init=&olympic_init;
+			dev->init=&olympic_init;	/* AKPM: Not needed */
 			olympic_priv->olympic_card_name = (char *)pci_device->resource[0].name ; 
+			/* FIXME: check ioremap return val, handle cleanup */
 			olympic_priv->olympic_mmio = 
 				ioremap(pci_resource_start(pci_device,1),256);
 			olympic_priv->olympic_lap = 
@@ -240,8 +244,11 @@
 			olympic_priv->olympic_message_level = message_level[card_no] ; 
 	
 			if(olympic_init(dev)==-1) {
-				unregister_netdevice(dev);
 				kfree(dev->priv);
+#ifndef MODULE
+				unregister_netdev(dev);
+				kfree(dev);
+#endif
 				return 0;
 			}				
 
@@ -288,6 +295,10 @@
 
 	spin_lock_init(&olympic_priv->olympic_lock) ; 
 
+	/* Needed for cardbus */
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR))
+		writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK);
+
 #if OLYMPIC_DEBUG
 	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
 	printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -1259,6 +1270,11 @@
 }
 #endif 
 		mac_frame = dev_alloc_skb(frame_len) ; 
+		if (!mac_frame) {
+			printk(KERN_WARNING "%s: Memory squeeze, dropping "
+			       "frame.\n", dev->name);
+			goto drop_frame;
+		}
 
 		/* Walk the buffer chain, creating the frame */
 
@@ -1281,6 +1297,7 @@
 		netif_rx(mac_frame) ; 	
 		dev->last_rx = jiffies ;
 
+drop_frame:
 		/* Now tell the card we have dealt with the received frame */
 
 		/* Set LISR Bit 1 */
@@ -1633,8 +1650,11 @@
         for (i = 0; (i<OLYMPIC_MAX_ADAPTERS); i++) {
 		dev_olympic[i] = NULL;
                 dev_olympic[i] = init_trdev(dev_olympic[i], 0);
-                if (dev_olympic[i] == NULL)
-                        return -ENOMEM;
+                if (dev_olympic[i] == NULL) {
+			if (i == 0)
+                        	return -ENOMEM;
+			break;
+		}
 
 		dev_olympic[i]->init      = &olympic_probe;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/olympic.h linux/drivers/net/tokenring/olympic.h
--- v2.4.2/linux/drivers/net/tokenring/olympic.h	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/olympic.h	Tue Mar  6 19:28:35 2001
@@ -1,6 +1,6 @@
 /*
  *  olympic.h (c) 1999 Peter De Schrijver All Rights Reserved
- *                1999 Mike Phillips (phillim@amtrak.com)
+ *                1999 Mike Phillips (mikep@linuxtr.net)
  *
  *  Linux driver for IBM PCI tokenring cards based on the olympic and the PIT/PHY chipset.
  *
@@ -19,6 +19,7 @@
 #define BCTL 0x70
 #define BCTL_SOFTRESET (1<<15)
 #define BCTL_MIMREB (1<<6)
+#define BCTL_MODE_INDICATOR (1<<5)
 
 #define GPR 0x4a
 #define GPR_OPTI_BF (1<<6)
@@ -124,6 +125,9 @@
 #define TXSTATQCNT_2 0xe4
 #define TXCSA_1 0xc8
 #define TXCSA_2 0xe8
+/* Cardbus */
+#define FERMASK 0xf4
+#define FERMASK_INT_BIT (1<<15)
 
 #define OLYMPIC_IO_SPACE 256
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- v2.4.2/linux/drivers/net/tokenring/smctr.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/smctr.c	Tue Mar 20 12:05:00 2001
@@ -4383,7 +4383,7 @@
         smctr_clear_trc_reset(ioaddr);
         mdelay(200); /* ~2 ms */
 
-        /* Remove any latched interrupts that occured prior to reseting the
+        /* Remove any latched interrupts that occurred prior to reseting the
          * adapter or possibily caused by line glitches due to the reset.
          */
         outb(tp->trc_mask | CSR_CLRTINT | CSR_CLRCBUSY, ioaddr + CSR);
@@ -4546,20 +4546,24 @@
                                 struct sk_buff *skb;
 
                                 skb = dev_alloc_skb(rx_size);
-                                skb_put(skb, rx_size);
+				if (skb) {
+                                	skb_put(skb, rx_size);
 
-                                memcpy(skb->data, pbuff, rx_size);
-                                sti();
+                                	memcpy(skb->data, pbuff, rx_size);
+                                	sti();
 
-                                /* Update Counters */
-                                tp->MacStat.rx_packets++;
-                                tp->MacStat.rx_bytes += skb->len;
-
-                                /* Kick the packet on up. */
-                                skb->dev = dev;
-                                skb->protocol = tr_type_trans(skb, dev);
-                                netif_rx(skb);
-				dev->last_rx = jiffies;
+                                	/* Update Counters */
+                                	tp->MacStat.rx_packets++;
+                                	tp->MacStat.rx_bytes += skb->len;
+
+                                	/* Kick the packet on up. */
+                                	skb->dev = dev;
+                                	skb->protocol = tr_type_trans(skb, dev);
+                                	netif_rx(skb);
+					dev->last_rx = jiffies;
+				} else {
+                                	sti();
+				}
                         }
                         else
                                 smctr_process_rx_packet((MAC_HEADER *)pbuff,
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c
--- v2.4.2/linux/drivers/net/tokenring/tms380tr.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/tms380tr.c	Sat Mar  3 10:55:47 2001
@@ -2203,6 +2203,7 @@
 				skb_trim(skb,Length);
 				skb->protocol = tr_type_trans(skb,dev);
 				netif_rx(skb);
+				dev->last_rx = jiffies;
 			}
 		}
 		else	/* Invalid frame */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/tms380tr.h linux/drivers/net/tokenring/tms380tr.h
--- v2.4.2/linux/drivers/net/tokenring/tms380tr.h	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/tms380tr.h	Tue Mar  6 19:28:34 2001
@@ -395,7 +395,7 @@
 /* OPEN Options (high-low) */
 #define WRAP_INTERFACE		0x0080	/* Inserting omitted for test
 					 * purposes; transmit data appears
-					 * as receive data. (usefull for
+					 * as receive data. (useful for
 					 * testing; change: CLOSE necessary)
 					 */
 #define DISABLE_HARD_ERROR	0x0040	/* On HARD_ERROR & TRANSMIT_BEACON
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tokenring/tmsisa.c linux/drivers/net/tokenring/tmsisa.c
--- v2.4.2/linux/drivers/net/tokenring/tmsisa.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tokenring/tmsisa.c	Tue Mar 20 12:05:00 2001
@@ -7,7 +7,7 @@
  *  Dedicated to my girlfriend Steffi Bopp
  *
  *  This software may be used and distributed according to the terms
- *  of the GNU Public License, incorporated herein by reference.
+ *  of the GNU General Public License, incorporated herein by reference.
  *
  *  This driver module supports the following cards:
  *	- SysKonnect TR4/16(+) ISA	(SK-4190)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/ChangeLog linux/drivers/net/tulip/ChangeLog
--- v2.4.2/linux/drivers/net/tulip/ChangeLog	Sat Feb  3 19:51:28 2001
+++ linux/drivers/net/tulip/ChangeLog	Fri Mar  2 11:02:14 2001
@@ -1,3 +1,54 @@
+2001-02-20  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* media.c (tulip_select_media): No need to initialize
+	new_csr6, all cases initialize it properly.
+
+2001-02-18  Manfred Spraul  <manfred@colorfullife.com>
+
+	* interrupt.c (tulip_refill_rx): Make public.
+	If PNIC chip stops due to lack of Rx buffers, restart it.
+	(tulip_interrupt): PNIC doesn't have a h/w timer, emulate
+	with software timers.
+	* pnic.c (pnic_check_duplex): New function, PNIC-specific
+	version of tulip_check_duplex.
+	(pnic_lnk_change): Call pnic_check_duplex.  If we use an
+	external MII, then we mustn't use the internal negotiation.
+	(pnic_timer): Support Rx refilling on work overflow in
+	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>
+
+	* tulip_core.c (tulip_init_one): Call pci_enable_device
+	to ensure wakeup/resource assignment before checking those
+	values.
+	(tulip_init_one): Replace PCI ids with constants from pci_id.h.
+	(tulip_suspend, tulip_resume, tulip_remove_one): Call
+	pci_power_on/off (commented out for now).
+
+2001-02-10  Jeff Garzik  <jgarzik@mandrakesoft.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>
+
+	* 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>
+
+	* 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>
+
+	* 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>
 
 	* tulip_core.c: static vars no longer explicitly
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c
--- v2.4.2/linux/drivers/net/tulip/interrupt.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tulip/interrupt.c	Fri Mar  2 11:02:14 2001
@@ -23,7 +23,7 @@
 
 
 
-static int tulip_refill_rx(struct net_device *dev)
+int tulip_refill_rx(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int entry;
@@ -50,6 +50,14 @@
 		}
 		tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
 	}
+	if(tp->chip_id == LC82C168) {
+		if(((inl(dev->base_addr + CSR5)>>17)&0x07) == 4) {
+			/* Rx stopped due to out of buffers,
+			 * restart it
+			 */
+			outl(0x01, dev->base_addr + CSR2);
+		}
+	}
 	return refilled;
 }
 
@@ -332,7 +340,11 @@
                      /* Josip Loncaric at ICASE did extensive experimentation
 			to develop a good interrupt mitigation setting.*/
                                 outl(0x8b240000, ioaddr + CSR11);
-                        } else {
+                        } else if (tp->chip_id == LC82C168) {
+				/* the LC82C168 doesn't have a hw timer.*/
+				outl(0x00, ioaddr + CSR7);
+				mod_timer(&tp->timer, RUN_AT(HZ/50));
+			} else {
                           /* Mask all interrupting sources, set timer to
 				re-enable. */
                                 outl(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
@@ -355,14 +367,19 @@
 	if (tp->rx_buffers[entry].skb == NULL) {
 		if (tulip_debug > 1)
 			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
-		if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
-			if (tulip_debug > 1)
-				printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
-			outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
-				ioaddr + CSR7);
-			outl(TimerInt, ioaddr + CSR5);
-			outl(12, ioaddr + CSR11);
-			tp->ttimer = 1;
+		if (tp->chip_id == LC82C168) {
+			outl(0x00, ioaddr + CSR7);
+			mod_timer(&tp->timer, RUN_AT(HZ/50));
+		} else {
+			if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
+				if (tulip_debug > 1)
+					printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+				outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
+					ioaddr + CSR7);
+				outl(TimerInt, ioaddr + CSR5);
+				outl(12, ioaddr + CSR11);
+				tp->ttimer = 1;
+			}
 		}
 	}
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c
--- v2.4.2/linux/drivers/net/tulip/media.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tulip/media.c	Fri Mar  2 11:02:14 2001
@@ -148,7 +148,7 @@
 	long ioaddr = dev->base_addr;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	struct mediatable *mtable = tp->mtable;
-	u32 new_csr6=0;
+	u32 new_csr6;
 	int i;
 
 	if (mtable) {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c
--- v2.4.2/linux/drivers/net/tulip/pnic.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tulip/pnic.c	Fri Mar  2 11:02:14 2001
@@ -50,6 +50,61 @@
 	}
 }
 
+/* Modified version of tulip_check_duplex:
+ * Always update the 100mbps bit, even if the
+ * full duplex bit didn't change.
+ *	Manfred Spraul <manfred@colorfullife.com>
+ */
+int pnic_check_duplex(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int mii_reg1, mii_reg5, negotiated, duplex;
+	int new_csr6;
+
+	mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1);
+	mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5);
+	if (tulip_debug > 1)
+		printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+			   "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+	if (mii_reg1 == 0xffff)
+		return -2;
+	if ((mii_reg1 & 0x0004) == 0) {
+		int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1);
+		if ((new_reg1 & 0x0004) == 0) {
+			if (tulip_debug  > 1)
+				printk(KERN_INFO "%s: No link beat on the MII interface,"
+					   " status %4.4x.\n", dev->name, new_reg1);
+			return -1;
+		}
+	}
+	negotiated = mii_reg5 & tp->advertising[0];
+	/* 100baseTx-FD  or  10T-FD, but not 100-HD */
+	duplex = ((negotiated & 0x0300) == 0x0100
+			  || (negotiated & 0x00C0) == 0x0040) ||
+		tp->full_duplex_lock;
+
+	new_csr6 = tp->csr6;
+	if (negotiated & 0x0380)	/* 100mbps. */
+		new_csr6 &= ~0x00400000;
+	 else
+		new_csr6 |= 0x00400000;
+	if (duplex)
+		new_csr6 |= 0x0200;
+	 else	
+		new_csr6 &= ~0x0200;
+	if (new_csr6 != tp->csr6) {
+		tp->full_duplex = duplex;
+		tp->csr6 = new_csr6;
+		if (tulip_debug > 0)
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+				   "#%d link partner capability of %4.4x.\n",
+				   dev->name, tp->full_duplex ? "full" : "half",
+				   tp->phys[0], mii_reg5);
+		tulip_restart_rxtx(tp, tp->csr6);
+		return 1;
+	}
+	return 0;
+}
 
 void pnic_lnk_change(struct net_device *dev, int csr5)
 {
@@ -62,6 +117,11 @@
 			   dev->name, phy_reg, csr5);
 	if (inl(ioaddr + CSR5) & TPLnkFail) {
 		outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
+		/* If we use an external MII, then we mustn't use the 
+		 * internal negotiation.
+		 */
+		if (tulip_media_cap[dev->if_port] & MediaIsMII)
+			return;
 		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
 			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
 			tulip_outl_csr(tp, tp->csr6, CSR6);
@@ -70,11 +130,18 @@
 			dev->trans_start = jiffies;
 		}
 	} else if (inl(ioaddr + CSR5) & TPLnkPass) {
-		pnic_do_nway(dev);
+		if (tulip_media_cap[dev->if_port] & MediaIsMII) {
+			spin_lock(&tp->lock);
+			pnic_check_duplex(dev);
+			spin_unlock(&tp->lock);
+		} else {
+			pnic_do_nway(dev);
+		}
 		outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
 	}
 }
 
+int tulip_refill_rx(struct net_device *dev);
 
 void pnic_timer(unsigned long data)
 {
@@ -82,10 +149,21 @@
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
+	
+	if(!inl(ioaddr + CSR7)) {
+		/* the timer was called due to a work overflow
+		 * in the interrupt handler. Skip the connection
+		 * checks, the nic is definitively speaking with
+		 * his link partner.
+		 */
+		goto too_good_connection;
+	}
 
 	if (tulip_media_cap[dev->if_port] & MediaIsMII) {
-		if (tulip_check_duplex(dev) > 0)
+		spin_lock_irq(&tp->lock);
+		if (pnic_check_duplex(dev) > 0)
 			next_tick = 3*HZ;
+		spin_unlock_irq(&tp->lock);
 	} else {
 		int csr12 = inl(ioaddr + CSR12);
 		int new_csr6 = tp->csr6 & ~0x40C40200;
@@ -137,7 +215,14 @@
 			}
 		}
 	}
-	tp->timer.expires = RUN_AT(next_tick);
-	add_timer(&tp->timer);
+too_good_connection:
+	mod_timer(&tp->timer, RUN_AT(next_tick));
+	if(!inl(ioaddr + CSR7)) {
+		if (tulip_debug > 1)
+			printk(KERN_INFO "%s: sw timer wakeup.\n", dev->name);
+		disable_irq(dev->irq);
+		tulip_refill_rx(dev);
+		enable_irq(dev->irq);
+		outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+	}
 }
-
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h
--- v2.4.2/linux/drivers/net/tulip/tulip.h	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tulip/tulip.h	Tue Mar  6 22:44:16 2001
@@ -18,6 +18,7 @@
 #include <linux/netdevice.h>
 #include <linux/timer.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 
 
 
@@ -107,7 +108,14 @@
 	CSR12 = 0x60,
 	CSR13 = 0x68,
 	CSR14 = 0x70,
-	CSR15 = 0x78
+	CSR15 = 0x78,
+};
+
+/* register offset and bits for CFDD PCI config reg */
+enum pci_cfg_driver_reg {	
+	CFDD = 0x40,
+	CFDD_Sleep = (1 << 31),
+	CFDD_Snooze = (1 << 30),
 };
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c
--- v2.4.2/linux/drivers/net/tulip/tulip_core.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/tulip/tulip_core.c	Fri Mar  2 11:02:14 2001
@@ -28,7 +28,7 @@
 #include <asm/unaligned.h>
 
 static char version[] __devinitdata =
-	"Linux Tulip driver version 0.9.13a (January 20, 2001)\n";
+	"Linux Tulip driver version 0.9.14 (February 20, 2001)\n";
 
 
 /* A few user-configurable values. */
@@ -120,37 +120,63 @@
  */
 
 struct tulip_chip_table tulip_tbl[] = {
+  /* DC21040 */
   { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+
+  /* DC21041 */
   { "Digital DC21041 Tulip", 128, 0x0001ebef,
 	HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer },
+
+  /* DC21140 */
   { "Digital DS21140 Tulip", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+
+  /* DC21142, DC21143 */
   { "Digital DS21143 Tulip", 128, 0x0801fbff,
 	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
 	| HAS_INTR_MITIGATION, t21142_timer },
-  { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+
+  /* LC82C168 */
+  { "Lite-On 82c168 PNIC", 256, 0x0001fbef,
 	HAS_MII | HAS_PNICNWAY, pnic_timer },
+
+  /* MX98713 */
   { "Macronix 98713 PMAC", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+
+  /* MX98715 */
   { "Macronix 98715 PMAC", 256, 0x0001ebef,
 	HAS_MEDIA_TABLE, mxic_timer },
+
+  /* MX98725 */
   { "Macronix 98725 PMAC", 256, 0x0001ebef,
 	HAS_MEDIA_TABLE, mxic_timer },
+
+  /* AX88140 */
   { "ASIX AX88140", 128, 0x0001fbff,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY | IS_ASIX, tulip_timer },
+
+  /* PNIC2 */
   { "Lite-On PNIC-II", 256, 0x0801fbff,
 	HAS_MII | HAS_NWAY | HAS_8023X, t21142_timer },
+
+  /* COMET */
   { "ADMtek Comet", 256, 0x0001abef,
 	MC_HASH_ONLY, comet_timer },
+
+  /* COMPEX9881 */
   { "Compex 9881 PMAC", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+
+  /* I21145 */
   { "Intel DS21145 Tulip", 128, 0x0801fbff,
 	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY,
 	t21142_timer },
+
+  /* DM910X */
   { "Davicom DM9102/DM9102A", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
 	tulip_timer },
-  {0},
 };
 
 
@@ -176,6 +202,7 @@
 	{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },
 	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },
 	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },
+	{ 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },
 	{0, }
 };
@@ -212,6 +239,24 @@
 
 
 
+static void tulip_set_power_state (struct tulip_private *tp,
+				   int sleep, int snooze)
+{
+	if (tp->flags & HAS_ACPI) {
+		u32 tmp, newtmp;
+		pci_read_config_dword (tp->pdev, CFDD, &tmp);
+		newtmp = tmp & ~(CFDD_Sleep | CFDD_Snooze);
+		if (sleep)
+			newtmp |= CFDD_Sleep;
+		else if (snooze)
+			newtmp |= CFDD_Snooze;
+		if (tmp != newtmp)
+			pci_write_config_dword (tp->pdev, CFDD, newtmp);
+	}
+	
+}
+
+
 static void tulip_up(struct net_device *dev)
 {
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -222,8 +267,7 @@
 	DPRINTK("ENTER\n");
 
 	/* Wake the chip from sleep/snooze mode. */
-	if (tp->flags & HAS_ACPI)
-		pci_write_config_dword(tp->pdev, 0x40, 0);
+	tulip_set_power_state (tp, 0, 0);
 
 	/* On some chip revs we must set the MII/SYM port before the reset!? */
 	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
@@ -532,8 +576,9 @@
 	tp->stats.tx_errors++;
 
 out:
-	dev->trans_start = jiffies;
 	spin_unlock_irqrestore (&tp->lock, flags);
+	dev->trans_start = jiffies;
+	netif_wake_queue (dev);
 }
 
 
@@ -670,8 +715,7 @@
 	dev->if_port = tp->saved_if_port;
 
 	/* Leave the driver in snooze, not sleep, mode. */
-	if (tp->flags & HAS_ACPI)
-		pci_write_config_dword (tp->pdev, 0x40, 0x40000000);
+	tulip_set_power_state (tp, 0, 1);
 }
 
 
@@ -1049,7 +1093,7 @@
 	 *	different driver (lmc driver)
 	 */
 	 
-        if( pdev->subsystem_vendor == 0x1376 ){
+        if (pdev->subsystem_vendor == PCI_VENDOR_ID_LMC) {
 		printk (KERN_ERR PFX "skipping LMC card.\n");
 		return -ENODEV;
 	}
@@ -1080,16 +1124,24 @@
 	   thankfully its an old 486 chipset.
 	*/
 	
-	if (pci_find_device(PCI_VENDOR_ID_INTEL, 0x0483, NULL))
+	if (pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, NULL))
 		csr0 = 0x00A04800;
 	/* The dreaded SiS496 486 chipset. Same workaround as above. */
-	if (pci_find_device(PCI_VENDOR_ID_SI, 0x0496, NULL))
+	if (pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, NULL))
 		csr0 = 0x00A04800;
 		
 	/*
 	 *	And back to business
 	 */
  
+	i = pci_enable_device(pdev);
+	if (i) {
+		printk (KERN_ERR PFX
+			"Cannot enable tulip board #%d, aborting\n",
+			board_idx);
+		return i;
+	}
+
 	ioaddr = pci_resource_start (pdev, 0);
 	irq = pdev->irq;
 
@@ -1126,12 +1178,6 @@
 		goto err_out_free_pio_res;
 	}
 
-	if (pci_enable_device(pdev)) {
-		printk (KERN_ERR PFX "%s: Cannot enable PCI device, aborting\n",
-			dev->name);
-		goto err_out_free_mmio_res;
-	}
-
 	pci_set_master(pdev);
 
 	pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
@@ -1443,8 +1489,7 @@
 	}
 
 	/* put the chip in snooze mode until opened */
-	if (tulip_tbl[chip_idx].flags & HAS_ACPI)
-		pci_write_config_dword(pdev, 0x40, 0x40000000);
+	tulip_set_power_state (tp, 0, 1);
 
 	return 0;
 
@@ -1468,8 +1513,8 @@
 	if (dev && netif_device_present (dev)) {
 		netif_device_detach (dev);
 		tulip_down (dev);
+		/* pci_power_off(pdev, -1); */
 	}
-//	pci_set_power_state(pdev, 3);
 }
 
 
@@ -1477,8 +1522,11 @@
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
 
-	pci_enable_device(pdev);
+#if 1
+	pci_enable_device (pdev);
+#endif
 	if (dev && !netif_device_present (dev)) {
+		/* pci_power_on(pdev); */
 		tulip_up (dev);
 		netif_device_attach (dev);
 	}
@@ -1487,24 +1535,29 @@
 
 static void __devexit tulip_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct tulip_private *tp;
 
-	if (dev) {
-		struct tulip_private *tp = (struct tulip_private *)dev->priv;
-		pci_free_consistent(pdev,
-				    sizeof(struct tulip_rx_desc) * RX_RING_SIZE +
-				    sizeof(struct tulip_tx_desc) * TX_RING_SIZE,
-				    tp->rx_ring,
-				    tp->rx_ring_dma);
-		unregister_netdev(dev);
-		release_mem_region (pci_resource_start (pdev, 1),
-				    pci_resource_len (pdev, 1));
-		release_region (pci_resource_start (pdev, 0),
-				pci_resource_len (pdev, 0));
-		kfree(dev);
+	if (!dev)
+		return;
 
-		pci_set_drvdata(pdev, NULL);
-	}
+	tp = dev->priv;
+	pci_free_consistent (pdev,
+			     sizeof (struct tulip_rx_desc) * RX_RING_SIZE +
+			     sizeof (struct tulip_tx_desc) * TX_RING_SIZE,
+			     tp->rx_ring, tp->rx_ring_dma);
+	unregister_netdev (dev);
+	release_mem_region (pci_resource_start (pdev, 1),
+			    pci_resource_len (pdev, 1));
+	release_region (pci_resource_start (pdev, 0),
+			pci_resource_len (pdev, 0));
+	if (tp->mtable)
+		kfree (tp->mtable);
+	kfree (dev);
+
+	pci_set_drvdata (pdev, NULL);
+
+	/* pci_power_off (pdev, -1); */
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.4.2/linux/drivers/net/via-rhine.c	Mon Dec 11 13:38:29 2000
+++ linux/drivers/net/via-rhine.c	Tue Mar 20 12:04:58 2001
@@ -55,6 +55,9 @@
 	LK1.1.6:
 	- Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
 	                 set netif_running_on/off on startup, del_timer_sync
+	
+	LK1.1.7:
+	- Manfred Spraul: added reset into tx_timeout
 */
 
 
@@ -114,20 +117,22 @@
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/irq.h>
 
 /* These identify the driver base version and may not be removed. */
 static char version1[] __devinitdata =
-"via-rhine.c:v1.08b-LK1.1.6  8/9/2000  Written by Donald Becker\n";
+"via-rhine.c:v1.08b-LK1.1.7  8/9/2000  Written by Donald Becker\n";
 static char version2[] __devinitdata =
 "  http://www.scyld.com/network/via-rhine.html\n";
 
@@ -213,7 +218,7 @@
 most useful with small frames.
 
 Since the VIA chips are only able to transfer data to buffers on 32 bit
-boundaries, the the IP header at offset 14 in an ethernet frame isn't
+boundaries, the IP header at offset 14 in an ethernet frame isn't
 longword aligned for further processing.  Copying these unaligned buffers
 has the beneficial effect of 16-byte aligning the IP header.
 
@@ -380,6 +385,7 @@
 	CmdNoTxPoll=0x0800, CmdReset=0x8000,
 };
 
+#define MAX_MII_CNT	4
 struct netdev_private {
 	/* Descriptor rings */
 	struct rx_desc *rx_ring;
@@ -421,7 +427,8 @@
 
 	/* MII transceiver section. */
 	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
+	unsigned char phys[MAX_MII_CNT];			/* MII device addresses. */
+	unsigned int mii_cnt;			/* number of MIIs found, but only the first one is used */
 	u16 mii_status;						/* last read MII status */
 };
 
@@ -431,7 +438,6 @@
 static void via_rhine_check_duplex(struct net_device *dev);
 static void via_rhine_timer(unsigned long data);
 static void via_rhine_tx_timeout(struct net_device *dev);
-static void via_rhine_init_ring(struct net_device *dev);
 static int  via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
 static void via_rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static void via_rhine_tx(struct net_device *dev);
@@ -443,6 +449,25 @@
 static int  via_rhine_close(struct net_device *dev);
 static inline void clear_tally_counters(long ioaddr);
 
+static void wait_for_reset(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	int i;
+
+	i = 0;
+	do {
+		udelay(5);
+		i++;
+		if(i > 2000) {
+			printk(KERN_ERR "%s: reset did not complete in 10 ms.\n",
+					dev->name);
+			break;
+		}
+	} while(readw(ioaddr + ChipCmd) & CmdReset);
+	if (debug > 1)
+		printk(KERN_INFO "%s: reset finished after %d microseconds.\n",
+				dev->name, 5*i);
+}
 
 static int __devinit via_rhine_init_one (struct pci_dev *pdev,
 					 const struct pci_device_id *ent)
@@ -451,14 +476,11 @@
 	struct netdev_private *np;
 	int i, option;
 	int chip_id = (int) ent->driver_data;
-	int irq = pdev->irq;
 	static int card_idx = -1;
 	static int did_version = 0;
 	long ioaddr;
 	int io_size;
 	int pci_flags;
-	void *ring;
-	dma_addr_t ring_dma;
 	
 	/* print version once and once only */
 	if (! did_version++) {
@@ -471,8 +493,11 @@
 	io_size = via_rhine_chip_info[chip_id].io_size;
 	pci_flags = via_rhine_chip_info[chip_id].pci_flags;
 
+	if (pci_enable_device (pdev))
+		goto err_out;
+
 	/* this should always be supported */
-	if (!pci_dma_supported(pdev, 0xffffffff)) {
+	if (pci_set_dma_mask(pdev, 0xffffffff)) {
 		printk(KERN_ERR "32-bit PCI DMA addresses not supported by the card!?\n");
 		goto err_out;
 	}
@@ -484,20 +509,7 @@
 		goto err_out;
 	}
 
-	/* allocate pci dma space for rx and tx descriptor rings */
-	ring = pci_alloc_consistent(pdev, 
-				    RX_RING_SIZE * sizeof(struct rx_desc) +
-				    TX_RING_SIZE * sizeof(struct tx_desc),
-				    &ring_dma);
-	if (!ring) {
-		printk(KERN_ERR "Could not allocate DMA memory.\n");
-		goto err_out;
-	}
-
 	ioaddr = pci_resource_start (pdev, pci_flags & PCI_ADDR0 ? 0 : 1);
-
-	if (pci_enable_device (pdev))
-		goto err_out_free_dma;
 	
 	if (pci_flags & PCI_USES_MASTER)
 		pci_set_master (pdev);
@@ -506,26 +518,12 @@
 	if (dev == NULL) {
 		printk (KERN_ERR "init_ethernet failed for card #%d\n",
 			card_idx);
-		goto err_out_free_dma;
+		goto err_out;
 	}
 	SET_MODULE_OWNER(dev);
 	
-	/* request all PIO and MMIO regions just to make sure
-	 * noone else attempts to use any portion of our I/O space */
-	if (!request_region (pci_resource_start (pdev, 0),
-			     pci_resource_len (pdev, 0), dev->name)) {
-		printk (KERN_ERR "request_region failed for device %s, region 0x%X @ 0x%lX\n",
-			dev->name, io_size,
-			pci_resource_start (pdev, 0));
+	if (pci_request_regions(pdev, dev->name))
 		goto err_out_free_netdev;
-	}
-	if (!request_mem_region (pci_resource_start (pdev, 1),
-				 pci_resource_len (pdev, 1), dev->name)) {
-		printk (KERN_ERR "request_mem_region failed for device %s, region 0x%X @ 0x%lX\n",
-			dev->name, io_size,
-			pci_resource_start (pdev, 1));
-		goto err_out_free_pio;
-	}
 
 #ifndef USE_IO
 	ioaddr = (long) ioremap (ioaddr, io_size);
@@ -533,7 +531,7 @@
 		printk (KERN_ERR "ioremap failed for device %s, region 0x%X @ 0x%X\n",
 			dev->name, io_size,
 			pci_resource_start (pdev, 1));
-		goto err_out_free_mmio;
+		goto err_out_free_res;
 	}
 #endif
 
@@ -545,23 +543,20 @@
 		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
 	for (i = 0; i < 5; i++)
 			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
 
 	/* Reset the chip to erase previous misconfiguration. */
 	writew(CmdReset, ioaddr + ChipCmd);
+	wait_for_reset(dev);
 
 	dev->base_addr = ioaddr;
-	dev->irq = irq;
+	dev->irq = pdev->irq;
 
 	np = dev->priv;
 	spin_lock_init (&np->lock);
 	np->chip_id = chip_id;
 	np->drv_flags = via_rhine_chip_info[chip_id].drv_flags;
 	np->pdev = pdev;
-	np->rx_ring = ring;
-	np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
-	np->rx_ring_dma = ring_dma;
-	np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -588,12 +583,12 @@
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
 	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		np->phys[0] = 1;		/* Standard for this chip. */
-		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
+		for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
@@ -610,6 +605,7 @@
 					netif_carrier_off(dev);
 			}
 		}
+		np->mii_cnt = phy_idx;
 	}
 
 	return 0;
@@ -617,27 +613,209 @@
 #ifndef USE_IO
 /* note this is ifdef'd because the ioremap is ifdef'd...
  * so additional exit conditions above this must move
- * release_mem_region outside of the ifdef */
-err_out_free_mmio:
-	release_mem_region(pci_resource_start (pdev, 1),
-			   pci_resource_len (pdev, 1));
+ * pci_release_regions outside of the ifdef */
+err_out_free_res:
+	pci_release_regions(pdev);
 #endif
-err_out_free_pio:
-	release_region(pci_resource_start (pdev, 0),
-		       pci_resource_len (pdev, 0));
 err_out_free_netdev:
 	unregister_netdev (dev);
 	kfree (dev);
-err_out_free_dma:
-	pci_free_consistent(pdev, 
+err_out:
+	return -ENODEV;
+}
+
+static int alloc_ring(struct net_device* dev)
+{
+	struct netdev_private *np = dev->priv;
+	void *ring;
+	dma_addr_t ring_dma;
+
+	ring = pci_alloc_consistent(np->pdev, 
+				    RX_RING_SIZE * sizeof(struct rx_desc) +
+				    TX_RING_SIZE * sizeof(struct tx_desc),
+				    &ring_dma);
+	if (!ring) {
+		printk(KERN_ERR "Could not allocate DMA memory.\n");
+		return -ENOMEM;
+	}
+	np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
+								   &np->tx_bufs_dma);
+	if (np->tx_bufs == NULL) {
+		pci_free_consistent(np->pdev, 
 			    RX_RING_SIZE * sizeof(struct rx_desc) +
 			    TX_RING_SIZE * sizeof(struct tx_desc),
 			    ring, ring_dma);
-err_out:
-	return -ENODEV;
+		return -ENOMEM;
+	}
+
+	np->rx_ring = ring;
+	np->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
+	np->rx_ring_dma = ring_dma;
+	np->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
+
+
+	return 0;
+}
+
+void free_ring(struct net_device* dev)
+{
+	struct netdev_private *np = dev->priv;
+
+	pci_free_consistent(np->pdev, 
+			    RX_RING_SIZE * sizeof(struct rx_desc) +
+			    TX_RING_SIZE * sizeof(struct tx_desc),
+			    np->rx_ring, np->rx_ring_dma);
+
+	pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
+						np->tx_bufs, np->tx_bufs_dma);
+
 }
 
+static void alloc_rbufs(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	dma_addr_t next;
+	int i;
+
+	np->dirty_rx = np->cur_rx = 0;
 
+	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+	np->rx_head_desc = &np->rx_ring[0];
+	next = np->rx_ring_dma;
+	
+	/* Init the ring entries */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rx_status = 0;
+		np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+		next += sizeof(struct rx_desc);
+		np->rx_ring[i].next_desc = cpu_to_le32(next);
+		np->rx_skbuff[i] = 0;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma);
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+		np->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;                 /* Mark as being used by this device. */
+
+		np->rx_skbuff_dma[i] =
+			pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
+						   PCI_DMA_FROMDEVICE);
+
+		np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
+		np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
+	}
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+}
+
+static void free_rbufs(struct net_device* dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rx_status = 0;
+		np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (np->rx_skbuff[i]) {
+			pci_unmap_single(np->pdev,
+							 np->rx_skbuff_dma[i],
+							 np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(np->rx_skbuff[i]);
+		}
+		np->rx_skbuff[i] = 0;
+	}
+}
+
+static void alloc_tbufs(struct net_device* dev)
+{
+	struct netdev_private *np = dev->priv;
+	dma_addr_t next;
+	int i;
+
+	np->dirty_tx = np->cur_tx = 0;
+	next = np->tx_ring_dma;
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_skbuff[i] = 0;
+		np->tx_ring[i].tx_status = 0;
+		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		next += sizeof(struct tx_desc);
+		np->tx_ring[i].next_desc = cpu_to_le32(next);
+		np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
+	}
+	np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
+
+}
+
+static void free_tbufs(struct net_device* dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_ring[i].tx_status = 0;
+		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (np->tx_skbuff[i]) {
+			if (np->tx_skbuff_dma[i]) {
+				pci_unmap_single(np->pdev,
+								 np->tx_skbuff_dma[i],
+								 np->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
+			}
+			dev_kfree_skb(np->tx_skbuff[i]);
+		}
+		np->tx_skbuff[i] = 0;
+		np->tx_buf[i] = 0;
+	}
+}
+
+static void init_registers(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
+
+	/* Initialize other registers. */
+	writew(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
+	/* Configure the FIFO thresholds. */
+	writeb(0x20, ioaddr + TxConfig);	/* Initial threshold 32 bytes */
+	np->tx_thresh = 0x20;
+	np->rx_thresh = 0x60;			/* Written in via_rhine_set_rx_mode(). */
+
+	if (dev->if_port == 0)
+		dev->if_port = np->default_port;
+
+	writel(np->rx_ring_dma, ioaddr + RxRingPtr);
+	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
+
+	via_rhine_set_rx_mode(dev);
+
+	/* Enable interrupts by setting the interrupt mask. */
+	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
+		   IntrTxDone | IntrTxAbort | IntrTxUnderrun |
+		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
+		   ioaddr + IntrEnable);
+
+	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
+	if (np->duplex_lock)
+		np->chip_cmd |= CmdFDuplex;
+	writew(np->chip_cmd, ioaddr + ChipCmd);
+
+	via_rhine_check_duplex(dev);
+
+	/* The LED outputs of various MII xcvrs should be configured.  */
+	/* For NS or Mison phys, turn on bit 1 in register 0x17 */
+	/* For ESI phys, turn on bit 7 in register 0x17. */
+	mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
+			   (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
+}
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
 
 static int mdio_read(struct net_device *dev, int phy_id, int regnum)
@@ -660,7 +838,7 @@
 
 static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int boguscnt = 1024;
 
@@ -691,75 +869,36 @@
 
 static int via_rhine_open(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
 
 	/* Reset the chip. */
 	writew(CmdReset, ioaddr + ChipCmd);
 
-	i = request_irq(dev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev);
+	i = request_irq(np->pdev->irq, &via_rhine_interrupt, SA_SHIRQ, dev->name, dev);
 	if (i)
 		return i;
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: via_rhine_open() irq %d.\n",
-			   dev->name, dev->irq);
-
-	np->tx_bufs = pci_alloc_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
-									   &np->tx_bufs_dma);
-	if (np->tx_bufs == NULL) {
-		free_irq(dev->irq, dev);
-		return -ENOMEM;
-	}
-
-	via_rhine_init_ring(dev);
-
-	writel(np->rx_ring_dma, ioaddr + RxRingPtr);
-	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
-
-	for (i = 0; i < 6; i++)
-		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-
-	/* Initialize other registers. */
-	writew(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
-	/* Configure the FIFO thresholds. */
-	writeb(0x20, ioaddr + TxConfig);	/* Initial threshold 32 bytes */
-	np->tx_thresh = 0x20;
-	np->rx_thresh = 0x60;			/* Written in via_rhine_set_rx_mode(). */
-
-	if (dev->if_port == 0)
-		dev->if_port = np->default_port;
-
-	netif_start_queue(dev);
-
-	via_rhine_set_rx_mode(dev);
-
-	/* Enable interrupts by setting the interrupt mask. */
-	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
-		   IntrTxDone | IntrTxAbort | IntrTxUnderrun |
-		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
-		   ioaddr + IntrEnable);
-
-	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
-	if (np->duplex_lock)
-		np->chip_cmd |= CmdFDuplex;
-	writew(np->chip_cmd, ioaddr + ChipCmd);
-
-	via_rhine_check_duplex(dev);
-
-	/* The LED outputs of various MII xcvrs should be configured.  */
-	/* For NS or Mison phys, turn on bit 1 in register 0x17 */
-	/* For ESI phys, turn on bit 7 in register 0x17. */
-	mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
-			   (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
-
+			   dev->name, np->pdev->irq);
+	
+	i = alloc_ring(dev);
+	if (i)
+		return i;
+	alloc_rbufs(dev);
+	alloc_tbufs(dev);
+	wait_for_reset(dev);
+	init_registers(dev);
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done via_rhine_open(), status %4.4x "
 			   "MII status: %4.4x.\n",
 			   dev->name, readw(ioaddr + ChipCmd),
 			   mdio_read(dev, np->phys[0], 1));
 
+	netif_start_queue(dev);
+
 	/* Set the timer to check for link beat. */
 	init_timer(&np->timer);
 	np->timer.expires = jiffies + 2;
@@ -772,7 +911,7 @@
 
 static void via_rhine_check_duplex(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
 	int negotiated = mii_reg5 & np->advertising;
@@ -799,7 +938,7 @@
 static void via_rhine_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 	int mii_status;
@@ -832,92 +971,45 @@
 
 static void via_rhine_tx_timeout (struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *) dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
-	/* Lock to protect mdio_read and access to stats. A friendly
-       advice to the implementor of the XXXs in this function is to be
-       sure not to spin too long (whatever that means :) */
-	spin_lock_irq (&np->lock);
-
 	printk (KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
 		"%4.4x, resetting...\n",
 		dev->name, readw (ioaddr + IntrStatus),
 		mdio_read (dev, np->phys[0], 1));
 
-	/* XXX Perhaps we should reinitialize the hardware here. */
 	dev->if_port = 0;
 
-	/* Stop and restart the chip's Tx processes . */
-	/* XXX to do */
-
-	/* Trigger an immediate transmit demand. */
-	/* XXX to do */
-
-	dev->trans_start = jiffies;
-	np->stats.tx_errors++;
-
-	spin_unlock_irq (&np->lock);
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void via_rhine_init_ring(struct net_device *dev)
-{
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
-	int i;
-	dma_addr_t next = np->rx_ring_dma;
-
-	np->cur_rx = np->cur_tx = 0;
-	np->dirty_rx = np->dirty_tx = 0;
-
-	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-	np->rx_head_desc = &np->rx_ring[0];
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].rx_status = 0;
-		np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
-		next += sizeof(struct rx_desc);
-		np->rx_ring[i].next_desc = cpu_to_le32(next);
-		np->rx_skbuff[i] = 0;
-	}
-	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].next_desc = cpu_to_le32(np->rx_ring_dma);
-
-	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-		np->rx_skbuff[i] = skb;
-		if (skb == NULL)
-			break;
-		skb->dev = dev;                 /* Mark as being used by this device. */
+	/* protect against concurrent rx interrupts */
+	disable_irq(np->pdev->irq);
 
-		np->rx_skbuff_dma[i] =
-			pci_map_single(np->pdev, skb->tail, np->rx_buf_sz,
-						   PCI_DMA_FROMDEVICE);
+	spin_lock(&np->lock);
 
-		np->rx_ring[i].addr = cpu_to_le32(np->rx_skbuff_dma[i]);
-		np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
-	}
-	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+	/* Reset the chip. */
+	writew(CmdReset, ioaddr + ChipCmd);
 
-	next = np->tx_ring_dma;
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_skbuff[i] = 0;
-		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
-		next += sizeof(struct tx_desc);
-		np->tx_ring[i].next_desc = cpu_to_le32(next);
-		np->tx_buf[i] = &np->tx_bufs[i * PKT_BUF_SZ];
-	}
-	np->tx_ring[i-1].next_desc = cpu_to_le32(np->tx_ring_dma);
+	/* clear all descriptors */
+	free_tbufs(dev);
+	free_rbufs(dev);
+	alloc_tbufs(dev);
+	alloc_rbufs(dev);
+
+	/* Reinitialize the hardware. */
+	wait_for_reset(dev);
+	init_registers(dev);
+	
+	spin_unlock(&np->lock);
+	enable_irq(np->pdev->irq);
 
-	return;
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	netif_wake_queue(dev);
 }
 
 static int via_rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	unsigned entry;
 
 	/* Caution: the write order is important here, set the field
@@ -1017,7 +1109,7 @@
    for clarity. */
 static void via_rhine_tx(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int txstatus = 0, entry = np->dirty_tx % TX_RING_SIZE;
 
 	spin_lock (&np->lock);
@@ -1066,7 +1158,7 @@
    for clarity and better register allocation. */
 static void via_rhine_rx(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 
@@ -1149,7 +1241,7 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			np->stats.rx_bytes += skb->len;
+			np->stats.rx_bytes += pkt_len;
 			np->stats.rx_packets++;
 		}
 		entry = (++np->cur_rx) % RX_RING_SIZE;
@@ -1180,7 +1272,7 @@
 
 static void via_rhine_error(struct net_device *dev, int intr_status)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	spin_lock (&np->lock);
@@ -1215,8 +1307,9 @@
 				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
 	}
 	if ((intr_status & ~( IntrLinkChange | IntrStatsMax |
-						  IntrTxAbort | IntrTxAborted)) && debug > 1) {
-		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+						  IntrTxAbort | IntrTxAborted))) {
+		if (debug > 1)
+			printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 			   dev->name, intr_status);
 		/* Recovery for other fault sources not known. */
 		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
@@ -1227,7 +1320,7 @@
 
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -1273,7 +1366,7 @@
 
 static void via_rhine_set_rx_mode(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	u32 mc_filter[2];			/* Multicast hash filter */
 	u8 rx_mode;					/* Note: 0x02=accept runt, 0x01=accept errs */
@@ -1305,7 +1398,7 @@
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	u16 *data = (u16 *)&rq->ifr_data;
 	unsigned long flags;
 	int retval;
@@ -1338,13 +1431,11 @@
 static int via_rhine_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
-	int i;
-	unsigned long flags;
+	struct netdev_private *np = dev->priv;
 
 	del_timer_sync(&np->timer);
 
-	spin_lock_irqsave(&np->lock, flags);
+	spin_lock_irq(&np->lock);
 
 	netif_stop_queue(dev);
 
@@ -1361,44 +1452,12 @@
 	/* Stop the chip's Tx and Rx processes. */
 	writew(CmdStop, ioaddr + ChipCmd);
 
-	spin_unlock_irqrestore(&np->lock, flags);
-
-	/* Make sure there is no irq-handler running on a different CPU. */
-	synchronize_irq();
+	spin_unlock_irq(&np->lock);
 
-	free_irq(dev->irq, dev);
-
-	/* Free all the skbuffs in the Rx queue. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].rx_status = 0;
-		np->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
-		if (np->rx_skbuff[i]) {
-			pci_unmap_single(np->pdev,
-							 np->rx_skbuff_dma[i],
-							 np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(np->rx_skbuff[i]);
-		}
-		np->rx_skbuff[i] = 0;
-	}
-
-	/* Free all the skbuffs in the Tx queue, and also any bounce buffers. */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_ring[i].tx_status = 0;
-		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
-		np->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
-		if (np->tx_skbuff[i]) {
-			if (np->tx_skbuff_dma[i]) {
-				pci_unmap_single(np->pdev,
-								 np->tx_skbuff_dma[i],
-								 np->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
-			}
-			dev_kfree_skb(np->tx_skbuff[i]);
-		}
-		np->tx_skbuff[i] = 0;
-		np->tx_buf[i] = 0;
-	}
-	pci_free_consistent(np->pdev, PKT_BUF_SZ * TX_RING_SIZE,
-						np->tx_bufs, np->tx_bufs_dma);
+	free_irq(np->pdev->irq, dev);
+	free_rbufs(dev);
+	free_tbufs(dev);
+	free_ring(dev);
 
 	return 0;
 }
@@ -1406,15 +1465,12 @@
 
 static void __devexit via_rhine_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct netdev_private *np = (struct netdev_private *)(dev->priv);
 	
 	unregister_netdev(dev);
 
-	release_region(pci_resource_start (pdev, 0),
-		       pci_resource_len (pdev, 0));
-	release_mem_region(pci_resource_start (pdev, 1),
-		           pci_resource_len (pdev, 1));
+	pci_release_regions(pdev);
 
 #ifndef USE_IO
 	iounmap((char *)(dev->base_addr));
@@ -1426,6 +1482,8 @@
 			    np->rx_ring, np->rx_ring_dma);
 
 	kfree(dev);
+
+	pci_set_drvdata(pdev, NULL);
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/Config.in linux/drivers/net/wan/Config.in
--- v2.4.2/linux/drivers/net/wan/Config.in	Fri Aug 11 17:14:23 2000
+++ linux/drivers/net/wan/Config.in	Tue Mar  6 19:44:37 2001
@@ -33,6 +33,11 @@
       fi
       dep_tristate '    Support for Frame Relay on MultiGate boards' CONFIG_COMX_PROTO_FR $CONFIG_COMX
    fi
+#
+# The Etinc driver has not been tested as non-modular yet.
+#
+
+   dep_tristate '  Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m
 
 #
 # Lan Media's board. Currently 1000, 1200, 5200, 5245
@@ -45,6 +50,18 @@
    dep_tristate '  Sealevel Systems 4021 support' CONFIG_SEALEVEL_4021 m
 
    dep_tristate '  SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP m
+
+   tristate '  Generic HDLC driver' CONFIG_HDLC
+   if [ "$CONFIG_HDLC" != "n" ]; then
+      bool '    Synchronous Point-to-Point Protocol (PPP) support' CONFIG_HDLC_PPP
+      if [ "$CONFIG_LAPB" = "m" -a "$CONFIG_HDLC" = "m" -o "$CONFIG_LAPB" = "y" ]; then
+	 bool '    X.25 protocol support' CONFIG_HDLC_X25
+      else
+	 comment '    X.25/LAPB support is disabled'
+      fi
+      dep_tristate '    SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC
+      dep_tristate '    Moxa C101 support' CONFIG_C101 $CONFIG_HDLC
+   fi
 
    tristate '  Frame relay DLCI support' CONFIG_DLCI
    if [ "$CONFIG_DLCI" != "n" ]; then
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile
--- v2.4.2/linux/drivers/net/wan/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/wan/Makefile	Tue Mar  6 19:44:37 2001
@@ -9,7 +9,7 @@
 
 O_TARGET := wan.o
 
-export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o
+export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o
 list-multi =	wanpipe.o cyclomx.o
 
 wanpipe-objs = sdlamain.o $(wanpipe-y)
@@ -32,6 +32,7 @@
 obj-$(CONFIG_COMX_PROTO_LAPB)	+=				comx-proto-lapb.o
 obj-$(CONFIG_COMX_PROTO_FR)	+=				comx-proto-fr.o
 obj-$(CONFIG_COSA)		+=		syncppp.o	cosa.o
+obj-$(CONFIG_DSCC4)             +=				dscc4.o
 obj-$(CONFIG_LANMEDIA)		+=		syncppp.o
 obj-$(CONFIG_SYNCLINK_SYNCPPP)	+=		syncppp.o
 obj-$(CONFIG_X25_ASY)		+= x25_asy.o
@@ -48,6 +49,10 @@
 obj-$(CONFIG_CYCLADES_SYNC)	+= cycx_drv.o cyclomx.o
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
+obj-$(CONFIG_HDLC)		+= hdlc.o
+obj-$(CONFIG_HDLC_PPP)		+= syncppp.o
+obj-$(CONFIG_N2)		+= n2.o
+obj-$(CONFIG_C101)		+= c101.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/c101.c linux/drivers/net/wan/c101.c
--- v2.4.2/linux/drivers/net/wan/c101.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/c101.c	Tue Mar  6 19:44:36 2001
@@ -0,0 +1,375 @@
+/*
+ * Moxa C101 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * For information see http://hq.pm.waw.pl/hdlc/
+ *
+ * Sources of information:
+ *    Hitachi HD64570 SCA User's Manual
+ *    Moxa C101 User's Manual
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "hd64570.h"
+
+#define DEBUG_RINGS
+/* #define DEBUG_PKT */
+
+static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4";
+static const char* devname = "C101";
+
+#define C101_PAGE 0x1D00
+#define C101_DTR 0x1E00
+#define C101_SCA 0x1F00
+#define C101_WINDOW_SIZE 0x2000
+#define C101_MAPPED_RAM_SIZE 0x4000
+
+#define RAM_SIZE (256 * 1024)
+#define CLOCK_BASE 9830400	/* 9.8304 MHz */
+#define PAGE0_ALWAYS_MAPPED
+
+static char *hw;		/* pointer to hw=xxx command line string */
+
+
+typedef struct card_s {
+	hdlc_device hdlc;	/* HDLC device struct - must be first */
+	spinlock_t lock;	/* TX lock */
+	int clkmode;		/* clock mode */
+	int clkrate;		/* clock speed */
+	int line;		/* loopback only */
+	u8 *win0base;		/* ISA window base address */
+	u32 phy_winbase;	/* ISA physical base address */
+	u16 buff_offset;	/* offset of first buffer of first channel */
+	u8 rxs, txs, tmc;	/* SCA registers */
+	u8 irq;			/* IRQ (3-15) */
+	u8 ring_buffers;	/* number of buffers in a ring */
+	u8 page;
+
+	u8 rxin;		/* rx ring buffer 'in' pointer */
+	u8 txin;		/* tx ring buffer 'in' and 'last' pointers */
+	u8 txlast;
+	u8 rxpart;		/* partial frame received, next frame invalid*/
+
+	struct card_s *next_card;
+}card_t;
+
+typedef card_t port_t;
+
+
+#define sca_in(reg, card)	   readb((card)->win0base + C101_SCA + (reg))
+#define sca_out(value, reg, card)  writeb(value, (card)->win0base + C101_SCA + (reg))
+#define sca_inw(reg, card)	   readw((card)->win0base + C101_SCA + (reg))
+#define sca_outw(value, reg, card) writew(value, (card)->win0base + C101_SCA + (reg))
+
+#define port_to_card(port)	   (port)
+#define log_node(port)		   (0)
+#define phy_node(port)		   (0)
+#define winsize(card)		   (C101_WINDOW_SIZE)
+#define win0base(card)		   ((card)->win0base)
+#define winbase(card)      	   ((card)->win0base + 0x2000)
+#define get_port(card, port)	   ((port) == 0 ? (card) : NULL)
+
+
+static inline u8 sca_get_page(card_t *card)
+{
+	return card->page;
+}
+
+static inline void openwin(card_t *card, u8 page)
+{
+	card->page = page;
+	writeb(page, card->win0base + C101_PAGE);
+}
+
+
+#define close_windows(card) {} /* no hardware support */
+
+
+#include "hd6457x.c"
+
+
+static int c101_set_clock(port_t *port, int value)
+{
+	u8 msci = get_msci(port);
+	u8 rxs = port->rxs & CLK_BRG_MASK;
+	u8 txs = port->txs & CLK_BRG_MASK;
+
+	switch(value) {
+	case CLOCK_EXT:
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_LINE_TX; /* TXC input */
+		break;
+
+	case CLOCK_INT:
+		rxs |= CLK_BRG_RX; /* TX clock */
+		txs |= CLK_RXCLK_TX; /* BRG output */
+		break;
+
+	case CLOCK_TXINT:
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_BRG_TX; /* BRG output */
+		break;
+
+	case CLOCK_TXFROMRX:
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_RXCLK_TX; /* RX clock */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	port->rxs = rxs;
+	port->txs = txs;
+	sca_out(rxs, msci + RXS, port);
+	sca_out(txs, msci + TXS, port);
+	port->clkmode = value;
+	return 0;
+}
+
+
+static int c101_open(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+
+	MOD_INC_USE_COUNT;
+	writeb(1, port->win0base + C101_DTR);
+	sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
+	sca_open(hdlc);
+	c101_set_clock(port, port->clkmode);
+	return 0;
+}
+
+
+static void c101_close(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+
+	sca_close(hdlc);
+	writeb(0, port->win0base + C101_DTR);
+	sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port);
+	MOD_DEC_USE_COUNT;
+}
+
+
+static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+{
+	int value = ifr->ifr_ifru.ifru_ivalue;
+	int result = 0;
+	port_t *port = hdlc_to_port(hdlc);
+
+	if(!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	switch(cmd) {
+	case HDLCSCLOCK:
+		result = c101_set_clock(port, value);
+	case HDLCGCLOCK:
+		value = port->clkmode;
+		break;
+
+	case HDLCSCLOCKRATE:
+		port->clkrate = value;
+		sca_set_clock(port);
+	case HDLCGCLOCKRATE:
+		value = port->clkrate;
+		break;
+
+	case HDLCSLINE:
+		result = sca_set_loopback(port, value);
+	case HDLCGLINE:
+		value = port->line;
+		break;
+
+#ifdef DEBUG_RINGS
+	case HDLCRUN:
+		sca_dump_rings(hdlc);
+		return 0;
+#endif /* DEBUG_RINGS */
+
+	default:
+		return -EINVAL;
+	}
+
+	ifr->ifr_ifru.ifru_ivalue = value;
+	return result;
+}
+
+
+
+static void c101_destroy_card(card_t *card)
+{
+	if (card->irq)
+		free_irq(card->irq, card);
+
+	if (card->win0base) {
+		iounmap(card->win0base);
+		release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE);
+	}
+
+	kfree(card);
+}
+
+
+
+static int c101_run(unsigned long irq, unsigned long winbase)
+{
+	card_t *card;
+	int result;
+
+	if (irq<3 || irq>15 || irq == 6) /* FIXME */ {
+		printk(KERN_ERR "c101: invalid IRQ value\n");
+		return -ENODEV;
+	}
+
+	if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) {
+		printk(KERN_ERR "c101: invalid RAM value\n");
+		return -ENODEV;
+	}
+
+	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	if (card == NULL) {
+		printk(KERN_ERR "c101: unable to allocate memory\n");
+		return -ENOBUFS;
+	}
+	memset(card, 0, sizeof(card_t));
+
+	if (request_irq(irq, sca_intr, 0, devname, card)) {
+		printk(KERN_ERR "c101: could not allocate IRQ\n");
+		c101_destroy_card(card);
+		return(-EBUSY);
+	}
+	card->irq = irq;
+
+	if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) {
+		printk(KERN_ERR "c101: could not request RAM window\n");
+		c101_destroy_card(card);
+		return(-EBUSY);
+	}
+	card->phy_winbase = winbase;
+	card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE);
+	if (!card->win0base) {
+		printk(KERN_ERR "c101: could not map I/O address\n");
+		c101_destroy_card(card);
+		return -EBUSY;
+	}
+
+	/* 2 rings required for 1 port */
+	card->ring_buffers = (RAM_SIZE -C101_WINDOW_SIZE) / (2 * HDLC_MAX_MRU);
+	printk(KERN_DEBUG "c101: using %u packets rings\n",card->ring_buffers);
+
+	card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */
+
+	readb(card->win0base + C101_PAGE); /* Resets SCA? */
+	udelay(100);
+	writeb(0, card->win0base + C101_PAGE);
+	writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */
+
+	sca_init(card, 0);
+
+	spin_lock_init(&card->lock);
+	hdlc_to_dev(&card->hdlc)->irq = irq;
+	hdlc_to_dev(&card->hdlc)->mem_start = winbase;
+	hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
+	hdlc_to_dev(&card->hdlc)->tx_queue_len = 50;
+	card->hdlc.ioctl = c101_ioctl;
+	card->hdlc.open = c101_open;
+	card->hdlc.close = c101_close;
+	card->hdlc.xmit = sca_xmit;
+
+	result = register_hdlc_device(&card->hdlc);
+	if (result) {
+		printk(KERN_WARNING "c101: unable to register hdlc device\n");
+		c101_destroy_card(card);
+		return result;
+	}
+
+	sca_init_sync_port(card); /* Set up C101 memory */
+
+	*new_card = card;
+	new_card = &card->next_card;
+	return 0;
+}
+
+
+
+static int __init c101_init(void)
+{
+	if (hw == NULL) {
+#ifdef MODULE
+		printk(KERN_INFO "c101: no card initialized\n");
+#endif
+		return -ENOSYS;	/* no parameters specified, abort */
+	}
+
+	printk(KERN_INFO "%s\n", version);
+
+	do {
+		unsigned long irq, ram;
+
+		irq = simple_strtoul(hw, &hw, 0);
+
+		if (*hw++ != ',')
+			break;
+		ram = simple_strtoul(hw, &hw, 0);
+
+		if (*hw == ':' || *hw == '\x0')
+			c101_run(irq, ram);
+
+		if (*hw == '\x0')
+			return 0;
+	}while(*hw++ == ':');
+
+	printk(KERN_ERR "c101: invalid hardware parameters\n");
+	return first_card ? 0 : -ENOSYS;
+}
+
+
+#ifndef MODULE
+static int __init c101_setup(char *str)
+{
+	hw = str;
+	return 1;
+}
+
+__setup("c101=", c101_setup);
+#endif
+
+
+static void __exit c101_cleanup(void)
+{
+	card_t *card = first_card;
+
+	while (card) {
+		card_t *ptr = card;
+		card = card->next_card;
+		unregister_hdlc_device(&ptr->hdlc);
+		c101_destroy_card(ptr);
+	}
+}
+
+
+module_init(c101_init);
+module_exit(c101_cleanup);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Moxa C101 serial port driver");
+MODULE_PARM(hw, "s");		/* hw=irq,ram:irq,... */
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx-proto-fr.c linux/drivers/net/wan/comx-proto-fr.c
--- v2.4.2/linux/drivers/net/wan/comx-proto-fr.c	Mon Sep 18 15:02:03 2000
+++ linux/drivers/net/wan/comx-proto-fr.c	Sat Mar  3 10:55:48 2001
@@ -505,9 +505,9 @@
 		struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
 		newskb->dev=fr->master;
 		dev_queue_xmit(newskb);
-		dev_kfree_skb(skb);
-		ch->stats.tx_packets++;
 		ch->stats.tx_bytes += skb->len;
+		ch->stats.tx_packets++;
+		dev_kfree_skb(skb);
 	} else {
 		netif_stop_queue(dev);
 		for (; dir ; dir = dir->next) {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx-proto-lapb.c linux/drivers/net/wan/comx-proto-lapb.c
--- v2.4.2/linux/drivers/net/wan/comx-proto-lapb.c	Sat Nov 11 19:02:39 2000
+++ linux/drivers/net/wan/comx-proto-lapb.c	Sat Mar  3 10:55:48 2001
@@ -311,6 +311,7 @@
 		skb->pkt_type = PACKET_HOST;
 
 		netif_rx(skb);
+		ch->dev->last_rx = jiffies;
 	}
 
 	for (; comxdir; comxdir = comxdir->next) {
@@ -350,6 +351,7 @@
 		skb->pkt_type = PACKET_HOST;
 
 		netif_rx(skb);
+		ch->dev->last_rx = jiffies;
 	}
 
 	for (; comxdir; comxdir = comxdir->next) {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx-proto-ppp.c linux/drivers/net/wan/comx-proto-ppp.c
--- v2.4.2/linux/drivers/net/wan/comx-proto-ppp.c	Mon Sep 18 15:02:03 2000
+++ linux/drivers/net/wan/comx-proto-ppp.c	Tue Mar  6 19:44:36 2001
@@ -44,7 +44,7 @@
 #include <asm/uaccess.h>
 #include <linux/init.h>
 
-#include	"syncppp.h"
+#include <net/syncppp.h>
 #include	"comx.h"
 
 MODULE_AUTHOR("Author: Gergely Madarasz <gorgo@itc.hu>");
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c
--- v2.4.2/linux/drivers/net/wan/comx.c	Thu Nov 16 14:08:25 2000
+++ linux/drivers/net/wan/comx.c	Tue Mar  6 19:44:36 2001
@@ -73,8 +73,8 @@
 #error For now, COMX really needs the /proc filesystem
 #endif
 
+#include <net/syncppp.h>
 #include "comx.h"
-#include "syncppp.h"
 
 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
 MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
@@ -380,6 +380,7 @@
 	}
 	if (skb) {
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- v2.4.2/linux/drivers/net/wan/cosa.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/wan/cosa.c	Tue Mar  6 19:44:36 2001
@@ -102,7 +102,7 @@
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 
-#include "syncppp.h"
+#include <net/syncppp.h>
 #include "cosa.h"
 
 /* Linux version stuff */
@@ -220,9 +220,9 @@
 
 #define COSA_MTU 2000	/* FIXME: I don't know this exactly */
 
-#undef DEBUG_DATA 1	/* Dump the data read or written to the channel */
-#undef DEBUG_IRQS 1	/* Print the message when the IRQ is received */
-#undef DEBUG_IO 1	/* Dump the I/O traffic */
+#undef DEBUG_DATA //1	/* Dump the data read or written to the channel */
+#undef DEBUG_IRQS //1	/* Print the message when the IRQ is received */
+#undef DEBUG_IO   //1	/* Dump the I/O traffic */
 
 #define TX_TIMEOUT	(5*HZ)
 
@@ -745,7 +745,7 @@
 	chan->stats.rx_bytes += chan->cosa->rxsize;
 	netif_rx(chan->rx_skb);
 	chan->rx_skb = 0;
-	chan->pppdev.dev->trans_start = jiffies;
+	chan->pppdev.dev->last_rx = jiffies;
 	return 0;
 }
 
@@ -836,7 +836,7 @@
 	up(&chan->rsem);
 
 	if (copy_to_user(buf, kbuf, count)) {
-		kfree(buf);
+		kfree(kbuf);
 		return -EFAULT;
 	}
 	kfree(kbuf);
@@ -2011,7 +2011,7 @@
 /* ---------- I/O debugging routines ---------- */
 /*
  * These routines can be used to monitor COSA/SRP I/O and to printk()
- * the data being transfered on the data and status I/O port in a
+ * the data being transferred on the data and status I/O port in a
  * readable way.
  */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/cosa.h linux/drivers/net/wan/cosa.h
--- v2.4.2/linux/drivers/net/wan/cosa.h	Mon Oct 11 10:13:25 1999
+++ linux/drivers/net/wan/cosa.h	Tue Mar  6 19:44:36 2001
@@ -33,7 +33,7 @@
 #define SR_RX_INT_ENA   0x80    /* receiver interrupt enable bit */
 
 /* status register - input bits */
-#define SR_USR_RQ       0x20    /* user interupt request pending */
+#define SR_USR_RQ       0x20    /* user interrupt request pending */
 #define SR_TX_RDY       0x40    /* transmitter empty (ready) */
 #define SR_RX_RDY       0x80    /* receiver data ready */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.4.2/linux/drivers/net/wan/cycx_x25.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/wan/cycx_x25.c	Tue Mar 20 12:05:01 2001
@@ -3,7 +3,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2001 Arnaldo Carvalho de Melo
 *
 * Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
 *
@@ -12,6 +12,7 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 2001/01/12	acme		use dev_kfree_skb_irq on interrupt context
 * 2000/04/02	acme		dprintk, cycx_debug
 * 				fixed the bug introduced in get_dev_by_lcn and
 * 				get_dev_by_dte_addr by the anonymous hacker
@@ -794,7 +795,7 @@
 
 	if (skb_tailroom(skb) < pktlen) {
 		/* No room for the packet. Call off the whole thing! */
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 		chan->rx_skb = NULL;
 
 		if (bitm)
@@ -812,14 +813,14 @@
 	if (bitm)
 		return; /* more data is coming */
 
-	dev->last_rx = jiffies;		/* timestamp */
 	chan->rx_skb = NULL;		/* dequeue packet */
 
 	++chan->ifstats.rx_packets;
-	chan->ifstats.rx_bytes += skb->len;
+	chan->ifstats.rx_bytes += pktlen;
 
 	skb->mac.raw = skb->data;
 	netif_rx(skb);
+	dev->last_rx = jiffies;		/* timestamp */
 }
 
 /* Connect interrupt handler. */
@@ -1459,6 +1460,7 @@
         skb->pkt_type = PACKET_HOST;
 
         netif_rx(skb);
+	dev->last_rx = jiffies;		/* timestamp */
 }
 
 /* Convert line speed in bps to a number used by cyclom 2x code. */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c
--- v2.4.2/linux/drivers/net/wan/dlci.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/wan/dlci.c	Sat Mar  3 10:55:48 2001
@@ -227,8 +227,10 @@
 		/* we've set up the protocol, so discard the header */
 		skb->mac.raw = skb->data; 
 		skb_pull(skb, header);
+		dlp->stats.rx_bytes += skb->len;
 		netif_rx(skb);
 		dlp->stats.rx_packets++;
+		dev->last_rx = jiffies;
 	}
 	else
 		dev_kfree_skb(skb);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/dscc4.c linux/drivers/net/wan/dscc4.c
--- v2.4.2/linux/drivers/net/wan/dscc4.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/dscc4.c	Tue Mar 20 12:05:00 2001
@@ -0,0 +1,1769 @@
+/*
+ * drivers/net/wan/dscc4/dscc4_main.c: a DSCC4 HDLC driver for Linux
+ *
+ * This software may be used and distributed according to the terms of the 
+ * GNU General Public License. 
+ *
+ * The author may be reached as romieu@cogenit.fr.
+ * Specific bug reports/asian food will be welcome.
+ *
+ * Special thanks to the nice people at CS-Telecom for the hardware and the
+ * access to the test/measure tools.
+ *
+ *
+ *                             Theory of Operation
+ *
+ * I. Board Compatibility
+ *
+ * This device driver is designed for the Siemens PEB20534 4 ports serial
+ * controller as found on Etinc PCISYNC cards. The documentation for the 
+ * chipset is available at http://www.infineon.com:
+ * - Data Sheet "DSCC4, DMA Supported Serial Communication Controller with
+ * 4 Channels, PEB 20534 Version 2.1, PEF 20534 Version 2.1";
+ * - Application Hint "Management of DSCC4 on-chip FIFO resources".
+ * Jens David has built an adapter based on the same chipset. Take a look
+ * at http://www.afthd.tu-darmstadt.de/~dg1kjd/pciscc4 for a specific
+ * driver.
+ * Sample code (2 revisions) is available at Infineon.
+ *
+ * II. Board-specific settings
+ *
+ * Pcisync can transmit some clock signal to the outside world on the
+ * *first two* ports provided you put a quartz and a line driver on it and
+ * remove the jumpers. The operation is described on Etinc web site. If you
+ * go DCE on these ports, don't forget to use an adequate cable.
+ *
+ * Sharing of the PCI interrupt line for this board is possible.
+ *
+ * III. Driver operation
+ *
+ * The rx/tx operations are based on a linked list of descriptor. I haven't
+ * tried the start/stop descriptor method as this one looks like the cheapest
+ * in terms of PCI manipulation.
+ *
+ * Tx direction
+ * Once the data section of the current descriptor processed, the next linked
+ * descriptor is loaded if the HOLD bit isn't set in the current descriptor.
+ * If HOLD is met, the transmission is stopped until the host unsets it and
+ * signals the change via TxPOLL.
+ * When the tx ring is full, the xmit routine issues a call to netdev_stop.
+ * The device is supposed to be enabled again during an ALLS irq (we could
+ * use HI but as it's easy to loose events, it's fscked).
+ *
+ * Rx direction
+ * The received frames aren't supposed to span over multiple receiving areas.
+ * I may implement it some day but it isn't the highest ranked item.
+ *
+ * IV. Notes
+ * The chipset is buggy. Typically, under some specific load patterns (I
+ * wouldn't call them "high"), the irq queues and the descriptors look like
+ * some event has been lost. Even assuming some fancy PCI feature, it won't 
+ * explain the reproductible missing "C" bit in the descriptors. Faking an 
+ * irq in the periodic timer isn't really elegant but at least it seems 
+ * reliable.
+ * The current error (XDU, RFO) recovery code is untested.
+ * So far, RDO takes his RX channel down and the right sequence to enable it
+ * again is still a mistery. If RDO happens, plan a reboot. More details
+ * in the code (NB: as this happens, TX still works).
+ * Don't mess the cables during operation, especially on DTE ports. I don't
+ * suggest it for DCE either but at least one can get some messages instead
+ * of a complete instant freeze.
+ * Tests are done on Rev. 20 of the silicium. The RDO handling changes with
+ * the documentation/chipset releases. An on-line errata would be welcome.
+ *
+ * TODO:
+ * - some trivial error lurk,
+ * - the stats are fscked,
+ * - use polling at high irq/s,
+ * - performance analysis,
+ * - endianness.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/cache.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <net/syncppp.h>
+#include <linux/hdlc.h>
+
+/* Version */
+static const char * version = "$Id: dscc4.c,v 1.130 2001/02/25 15:27:34 romieu Exp $\n";
+static int debug;
+
+
+/* Module parameters */
+MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>");
+MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller");
+MODULE_PARM(debug,"i");
+
+/* Structures */
+struct TxFD {
+	u32 state;
+	u32 next;
+	u32 data;
+	u32 complete;
+	u32 jiffies; /* more hack to come :o) */
+};
+
+struct RxFD {
+	u32 state1;
+	u32 next;
+	u32 data;
+	u32 state2;
+	u32 end;
+};
+
+#define DEBUG
+#define DEBUG_PARANOID
+#define TX_RING_SIZE    32
+#define RX_RING_SIZE    32
+#define IRQ_RING_SIZE   64 /* Keep it A multiple of 32 */
+#define TX_TIMEOUT      (HZ/10)
+#define BRR_DIVIDER_MAX 64*0x00008000
+#define dev_per_card	4
+
+#define SOURCE_ID(flags) ((flags >> 28 ) & 0x03)
+#define TO_SIZE(state) ((state >> 16) & 0x1fff)
+#define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16)
+#define RX_MAX(len) ((((len) >> 5) + 1) << 5)
+#define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET
+
+#undef DEBUG
+
+struct dscc4_pci_priv {
+        u32 *iqcfg;
+        int cfg_cur;
+        spinlock_t lock;
+        struct pci_dev *pdev;
+
+        struct net_device *root;
+        dma_addr_t iqcfg_dma;
+	u32 xtal_hz;
+};
+
+struct dscc4_dev_priv {
+        struct sk_buff *rx_skbuff[RX_RING_SIZE];
+        struct sk_buff *tx_skbuff[TX_RING_SIZE];
+
+        struct RxFD *rx_fd;
+        struct TxFD *tx_fd;
+        u32 *iqrx;
+        u32 *iqtx;
+
+        u32 rx_current;
+        u32 tx_current;
+        u32 iqrx_current;
+        u32 iqtx_current;
+
+        u32 tx_dirty;
+	int bad_tx_frame;
+	int bad_rx_frame;
+	int rx_needs_refill;
+
+        dma_addr_t tx_fd_dma;
+        dma_addr_t rx_fd_dma;
+        dma_addr_t iqtx_dma;
+        dma_addr_t iqrx_dma;
+
+        struct net_device_stats stats;
+	struct timer_list timer;
+
+        struct dscc4_pci_priv *pci_priv;
+        spinlock_t lock;
+
+        int dev_id;
+	u32 flags;
+	u32 timer_help;
+	u32 hi_expected;
+
+	struct hdlc_device_struct hdlc;
+	int usecount;
+};
+
+/* GLOBAL registers definitions */
+#define GCMDR   0x00
+#define GSTAR   0x04
+#define GMODE   0x08
+#define IQLENR0 0x0C
+#define IQLENR1 0x10
+#define IQRX0   0x14
+#define IQTX0   0x24
+#define IQCFG   0x3c
+#define FIFOCR1 0x44
+#define FIFOCR2 0x48
+#define FIFOCR3 0x4c
+#define FIFOCR4 0x34
+#define CH0CFG  0x50
+#define CH0BRDA 0x54
+#define CH0BTDA 0x58
+
+/* SCC registers definitions */
+#define SCC_START	0x0100
+#define SCC_OFFSET      0x80
+#define CMDR    0x00
+#define STAR    0x04
+#define CCR0    0x08
+#define CCR1    0x0c
+#define CCR2    0x10
+#define BRR     0x2C
+#define RLCR    0x40
+#define IMR     0x54
+#define ISR     0x58
+
+/* Bit masks */
+#define IntRxScc0       0x10000000
+#define IntTxScc0       0x01000000
+
+#define TxPollCmd	0x00000400
+#define RxActivate	0x08000000
+#define MTFi		0x04000000
+#define Rdr		0x00400000
+#define Rdt		0x00200000
+#define Idr		0x00100000
+#define Idt		0x00080000
+#define TxSccRes       0x01000000
+#define RxSccRes       0x00010000
+#define TxSizeMax	0x1ffc
+#define RxSizeMax	0x1ffc
+
+#define Ccr0ClockMask	0x0000003f
+#define Ccr1LoopMask	0x00000200
+#define BrrExpMask	0x00000f00
+#define BrrMultMask	0x0000003f
+#define EncodingMask	0x00700000
+#define Hold		0x40000000
+#define SccBusy		0x10000000
+#define FrameOk		(FrameVfr | FrameCrc)
+#define FrameVfr	0x80
+#define FrameRdo	0x40
+#define FrameCrc	0x20
+#define FrameAborted	0x00000200
+#define FrameEnd	0x80000000
+#define DataComplete	0x40000000
+#define LengthCheck	0x00008000
+#define SccEvt		0x02000000
+#define NoAck		0x00000200
+#define Action		0x00000001
+#define HiDesc		0x20000000
+
+/* SCC events */
+#define RxEvt		0xf0000000
+#define TxEvt		0x0f000000
+#define Alls		0x00040000
+#define Xdu		0x00010000
+#define Xmr		0x00002000
+#define Xpr		0x00001000
+#define Rdo		0x00000080
+#define Rfs		0x00000040
+#define Rfo		0x00000002
+#define Flex		0x00000001
+
+/* DMA core events */
+#define Cfg		0x00200000
+#define Hi		0x00040000
+#define Fi		0x00020000
+#define Err		0x00010000
+#define Arf		0x00000002
+#define ArAck		0x00000001
+
+/* Misc */
+#define NeedIDR		0x00000001
+#define NeedIDT		0x00000002
+#define RdoSet		0x00000004
+
+/* Functions prototypes */
+static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *, struct net_device *);
+static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *, struct net_device *);
+static int dscc4_found1(struct pci_dev *, unsigned long ioaddr);
+static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent);
+static int dscc4_open(struct net_device *);
+static int dscc4_start_xmit(struct sk_buff *, struct net_device *);
+static int dscc4_close(struct net_device *);
+static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int dscc4_change_mtu(struct net_device *dev, int mtu);
+static int dscc4_init_ring(struct net_device *);
+static void dscc4_release_ring(struct dscc4_dev_priv *);
+static void dscc4_timer(unsigned long);
+static void dscc4_tx_timeout(struct net_device *);
+static void dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);
+static struct net_device_stats *dscc4_get_stats(struct net_device *);
+static int dscc4_attach_hdlc_device(struct net_device *);
+static void dscc4_unattach_hdlc_device(struct net_device *);
+static int dscc4_hdlc_open(struct hdlc_device_struct *);
+static void dscc4_hdlc_close(struct hdlc_device_struct *);
+static int dscc4_hdlc_ioctl(struct hdlc_device_struct *, struct ifreq *, int);
+static int dscc4_hdlc_xmit(hdlc_device *, struct sk_buff *);
+#ifdef EXPERIMENTAL_POLLING
+static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);
+#endif
+
+void inline reset_TxFD(struct TxFD *tx_fd) {
+	/* FIXME: test with the last arg (size specification) = 0 */
+	tx_fd->state = FrameEnd | Hold | 0x00100000;
+	tx_fd->complete = 0x00000000;
+}
+
+void inline dscc4_release_ring_skbuff(struct sk_buff **p, int n)
+{
+	for(; n > 0; n--) {
+		if (*p)
+			dev_kfree_skb(*p);
+		p++;
+	}
+}
+
+static void dscc4_release_ring(struct dscc4_dev_priv *dpriv)
+{
+	struct pci_dev *pdev = dpriv->pci_priv->pdev;
+
+	pci_free_consistent(pdev, TX_RING_SIZE*sizeof(struct TxFD),
+			    dpriv->tx_fd, dpriv->tx_fd_dma);
+	pci_free_consistent(pdev, RX_RING_SIZE*sizeof(struct RxFD),
+			    dpriv->rx_fd, dpriv->rx_fd_dma);
+	dscc4_release_ring_skbuff(dpriv->tx_skbuff, TX_RING_SIZE);
+	dscc4_release_ring_skbuff(dpriv->rx_skbuff, RX_RING_SIZE);
+}
+
+void inline try_get_rx_skb(struct dscc4_dev_priv *priv, int cur, struct net_device *dev)
+{
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(RX_MAX(dev->mtu+2));
+	priv->rx_skbuff[cur] = skb;
+	if (!skb) {
+		priv->rx_fd[cur--].data = (u32) NULL;
+		priv->rx_fd[cur%RX_RING_SIZE].state1 |= Hold;
+		priv->rx_needs_refill++;
+		return;
+	}
+	skb->dev = dev;
+	skb->protocol = htons(ETH_P_IP);
+	skb->mac.raw = skb->data;
+	priv->rx_fd[cur].data = pci_map_single(priv->pci_priv->pdev, skb->data,
+					       skb->len, PCI_DMA_FROMDEVICE);
+}
+
+/*
+ * IRQ/thread/whatever safe
+ */
+static int dscc4_wait_ack_cec(u32 ioaddr, struct net_device *dev, char *msg)
+{
+	s16 i = 0;
+
+	while (readl(ioaddr + STAR) & SccBusy) {
+		if (i++ < 0)  {
+			printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
+			return -1;
+		}
+	}
+	printk(KERN_DEBUG "%s: %s ack (%d try)\n", dev->name, msg, i);
+	return 0;
+}
+
+static int dscc4_do_action(struct net_device *dev, char *msg)
+{
+	unsigned long ioaddr = dev->base_addr;
+	u32 state;
+	s16 i;
+
+	writel(Action, ioaddr + GCMDR);
+	ioaddr += GSTAR;
+	for (i = 0; i >= 0; i++) {
+		state = readl(ioaddr);
+		if (state & Arf) {
+			printk(KERN_ERR "%s: %s failed\n", dev->name, msg);
+			writel(Arf, ioaddr);
+			return -1;
+		} else if (state & ArAck) {
+			printk(KERN_DEBUG "%s: %s ack (%d try)\n",
+			       dev->name, msg, i);
+			writel(ArAck, ioaddr);
+			return 0;
+		}
+	}
+	printk(KERN_ERR "%s: %s timeout\n", dev->name, msg);
+	return -1;
+}
+
+static __inline__ int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
+{
+	int cur;
+	s16 i;
+
+	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
+	for (i = 0; i >= 0; i++) {
+		if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
+		    (dpriv->iqtx[cur] & Xpr))
+			return 0;
+	}
+	printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR");
+	return -1;
+}
+
+static __inline__ void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
+	struct RxFD *rx_fd, struct net_device *dev)
+{
+	struct pci_dev *pdev = dpriv->pci_priv->pdev;
+	struct sk_buff *skb;
+	int pkt_len;
+
+	skb = dpriv->rx_skbuff[cur];
+	pkt_len = TO_SIZE(rx_fd->state2);
+	pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
+	if((skb->data[pkt_len - 1] & FrameOk) == FrameOk) {
+		pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE);
+		dpriv->stats.rx_packets++;
+		dpriv->stats.rx_bytes += pkt_len;
+		skb->tail += pkt_len;
+		skb->len = pkt_len;
+       		if (netif_running(hdlc_to_dev(&dpriv->hdlc)))
+			hdlc_netif_rx(&dpriv->hdlc, skb);
+		else
+			netif_rx(skb);
+		try_get_rx_skb(dpriv, cur, dev);
+	} else {
+		if(skb->data[pkt_len - 1] & FrameRdo)
+			dpriv->stats.rx_fifo_errors++;
+		else if(!(skb->data[pkt_len - 1] | ~FrameCrc))
+			dpriv->stats.rx_crc_errors++;
+		else if(!(skb->data[pkt_len - 1] | ~FrameVfr))
+			dpriv->stats.rx_length_errors++;
+		else
+			dpriv->stats.rx_errors++;
+	}
+	rx_fd->state1 |= Hold;
+	rx_fd->state2 = 0x00000000;
+	rx_fd->end = 0xbabeface;
+	if (!rx_fd->data)
+		return;
+	rx_fd--;
+	if (!cur)
+		rx_fd += RX_RING_SIZE;
+	rx_fd->state1 &= ~Hold;
+}
+
+static int __init dscc4_init_one (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct dscc4_pci_priv *priv;
+	struct dscc4_dev_priv *dpriv;
+	int i;
+	static int cards_found = 0;
+	unsigned long ioaddr;
+
+	printk(KERN_DEBUG "%s", version);
+
+	if (pci_enable_device(pdev))
+		goto err_out;
+	if (!request_mem_region(pci_resource_start(pdev, 0),
+	                	pci_resource_len(pdev, 0), "registers")) {
+	        printk (KERN_ERR "dscc4: can't reserve MMIO region (regs)\n");
+	        goto err_out;
+	}
+	if (!request_mem_region(pci_resource_start(pdev, 1),
+	                        pci_resource_len(pdev, 1), "LBI interface")) {
+	        printk (KERN_ERR "dscc4: can't reserve MMIO region (lbi)\n");
+	        goto err_out_free_mmio_region0;
+	}
+	ioaddr = (unsigned long)ioremap(pci_resource_start(pdev, 0),
+					pci_resource_len(pdev, 0));
+	if (!ioaddr) {
+		printk(KERN_ERR "dscc4: cannot remap MMIO region %lx @ %lx\n",
+	                pci_resource_len(pdev, 0), pci_resource_start(pdev, 0));
+		goto err_out_free_mmio_region;
+	}
+	printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d.\n",
+	        pci_resource_start(pdev, 0),
+	        pci_resource_start(pdev, 1), pdev->irq);
+
+	/* High PCI latency useless. Cf app. note. */
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x10);
+	pci_set_master(pdev);
+
+	if (dscc4_found1(pdev, ioaddr))
+	        goto err_out_iounmap;
+
+	priv = (struct dscc4_pci_priv *)pci_get_drvdata(pdev);
+
+	if (request_irq(pdev->irq, &dscc4_irq, SA_SHIRQ, "dscc4", priv->root)) {
+		printk(KERN_WARNING "dscc4: IRQ %d is busy\n", pdev->irq);
+		goto err_out_iounmap;
+	}
+	priv->pdev = pdev;
+
+	/* power up/little endian/dma core controlled via hold bit */
+	writel(0x00000000, ioaddr + GMODE);
+	/* Shared interrupt queue */
+	{
+		u32 bits;
+
+		bits = (IRQ_RING_SIZE >> 5) - 1;
+		bits |= bits << 4;
+		bits |= bits << 8;
+		bits |= bits << 16;
+		writel(bits, ioaddr + IQLENR0);
+	}
+	/* Global interrupt queue */
+	writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1);
+	priv->iqcfg = (u32 *) pci_alloc_consistent(pdev,
+		IRQ_RING_SIZE*sizeof(u32), &priv->iqcfg_dma);
+	if (!priv->iqcfg)
+		goto err_out_free_irq;
+	writel(priv->iqcfg_dma, ioaddr + IQCFG);
+
+	/* 
+	 * SCC 0-3 private rx/tx irq structures 
+	 * IQRX/TXi needs to be set soon. Learned it the hard way...
+	 */
+	for(i = 0; i < dev_per_card; i++) {
+		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,
+			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);
+		if (!dpriv->iqtx)
+			goto err_out_free_iqtx;
+		writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);
+	}
+	for(i = 0; i < dev_per_card; i++) {
+		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,
+			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);
+		if (!dpriv->iqrx)
+			goto err_out_free_iqrx;
+		writel(dpriv->iqrx_dma, ioaddr + IQRX0 + i*4);
+	}
+
+	/* 
+	 * Cf application hint. Beware of hard-lock condition on 
+	 * threshold .
+	 */
+	writel(0x42104000, ioaddr + FIFOCR1);
+	//writel(0x9ce69800, ioaddr + FIFOCR2);
+	writel(0xdef6d800, ioaddr + FIFOCR2);
+	//writel(0x11111111, ioaddr + FIFOCR4);
+	writel(0x18181818, ioaddr + FIFOCR4);
+	// FIXME: should depend on the chipset revision
+	writel(0x0000000e, ioaddr + FIFOCR3);
+
+	writel(0xff200001, ioaddr + GCMDR);
+
+	cards_found++;
+	return 0;
+
+err_out_free_iqrx:
+	while (--i >= 0) {
+		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+				    dpriv->iqrx, dpriv->iqrx_dma);
+	}
+	i = dev_per_card;
+err_out_free_iqtx:
+	while (--i >= 0) {
+		dpriv = (struct dscc4_dev_priv *)(priv->root + i)->priv;
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+				    dpriv->iqtx, dpriv->iqtx_dma);
+	}
+	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), priv->iqcfg, 
+			    priv->iqcfg_dma);
+err_out_free_irq:
+	free_irq(pdev->irq, priv->root);
+err_out_iounmap:
+	iounmap ((void *)ioaddr);
+err_out_free_mmio_region:
+	release_mem_region(pci_resource_start(pdev, 1),
+			   pci_resource_len(pdev, 1));
+err_out_free_mmio_region0:
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+err_out:
+	return -ENODEV;
+};
+
+static int dscc4_found1(struct pci_dev *pdev, unsigned long ioaddr)
+{
+	struct dscc4_pci_priv *ppriv;
+	struct dscc4_dev_priv *dpriv;
+	struct net_device *dev;
+	int i = 0;
+
+	dpriv = (struct dscc4_dev_priv *)
+		kmalloc(dev_per_card*sizeof(struct dscc4_dev_priv), GFP_KERNEL);
+	if (!dpriv) {
+		printk(KERN_ERR "dscc4: can't allocate data\n");
+		goto err_out;
+	}
+	memset(dpriv, 0, dev_per_card*sizeof(struct dscc4_dev_priv));
+
+	dev = (struct net_device *)
+	      kmalloc(dev_per_card*sizeof(struct net_device), GFP_KERNEL);
+	if (!dev) {
+		printk(KERN_ERR "dscc4: can't allocate net_device\n");
+		goto err_dealloc_priv;
+	}
+	memset(dev, 0, dev_per_card*sizeof(struct net_device));
+
+	ppriv = (struct dscc4_pci_priv *)
+		kmalloc(sizeof(struct dscc4_pci_priv), GFP_KERNEL);
+	if (!ppriv) {
+		printk(KERN_ERR "dscc4: can't allocate pci private data.\n");
+		goto err_dealloc_dev;
+	}
+	memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
+
+	for (i = 0; i < dev_per_card; i++) {
+		struct dscc4_dev_priv *p;
+		struct net_device *d;
+
+	        d = dev + i;
+	        d->base_addr = ioaddr;
+		d->init = NULL;
+	        d->irq = pdev->irq;
+		/* The card adds the crc */
+		d->type = ARPHRD_RAWHDLC;
+	        d->open = dscc4_open;
+	        d->stop = dscc4_close;
+	        d->hard_start_xmit = dscc4_start_xmit;
+		d->set_multicast_list = NULL;
+	        d->do_ioctl = dscc4_ioctl;
+		d->get_stats = dscc4_get_stats;
+		d->change_mtu = dscc4_change_mtu;
+	        d->mtu = HDLC_MAX_MTU;
+	        d->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
+		d->tx_timeout = dscc4_tx_timeout;
+		d->watchdog_timeo = TX_TIMEOUT;
+
+		p = dpriv + i;
+		p->dev_id = i;
+		p->pci_priv = ppriv;
+		spin_lock_init(&p->lock);
+		d->priv = p;
+
+		if (dev_alloc_name(d, "scc%d")<0) {
+			printk(KERN_ERR "dev_alloc_name failed for scc.\n");
+			goto err_dealloc_dev;
+		}
+	        if (register_netdev(d)) {
+			printk(KERN_ERR "%s: register_netdev != 0.\n", d->name);
+			goto err_dealloc_dev;
+	        }
+		dscc4_attach_hdlc_device(d);
+		SET_MODULE_OWNER(d);
+	}
+	ppriv->root = dev;
+	ppriv->pdev = pdev;
+	spin_lock_init(&ppriv->lock);
+	pdev->driver_data = ppriv;
+	pci_set_drvdata(pdev, ppriv);
+	return 0;
+
+err_dealloc_dev:
+	while (--i >= 0)
+		unregister_netdev(dev + i);
+	kfree(dev);
+err_dealloc_priv:
+	kfree(dpriv);
+err_out:
+	return -1;
+};
+
+static void dscc4_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct dscc4_dev_priv *dpriv;
+	struct dscc4_pci_priv *ppriv;
+
+	dpriv = dev->priv;
+	if (netif_queue_stopped(dev) && 
+	   ((jiffies - dev->trans_start) > TX_TIMEOUT)) {
+		ppriv = dpriv->pci_priv;
+		if (dpriv->iqtx[dpriv->iqtx_current%IRQ_RING_SIZE]) {
+			u32 flags;
+
+			printk(KERN_DEBUG "%s: pending events\n", dev->name);
+			dev->trans_start = jiffies;
+			spin_lock_irqsave(&ppriv->lock, flags);
+			dscc4_tx_irq(ppriv, dev);
+			spin_unlock_irqrestore(&ppriv->lock, flags);
+		} else {
+			struct TxFD *tx_fd;
+			struct sk_buff *skb;
+			int i,j;
+
+			printk(KERN_DEBUG "%s: missing events\n", dev->name);
+			i = dpriv->tx_dirty%TX_RING_SIZE; 
+			j = dpriv->tx_current - dpriv->tx_dirty;
+			dpriv->stats.tx_dropped += j;
+			while(j--) {
+				skb = dpriv->tx_skbuff[i];
+				tx_fd = dpriv->tx_fd + i;
+				if (skb) {
+					dpriv->tx_skbuff[i] = NULL;
+					pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len,
+						 	 PCI_DMA_TODEVICE);
+					dev_kfree_skb_irq(skb);
+				} else 
+					printk(KERN_INFO "%s: hardware on drugs!\n", dev->name);
+				tx_fd->data = 0; /* DEBUG */
+				tx_fd->complete &= ~DataComplete;
+				i++;	
+				i %= TX_RING_SIZE; 
+			}
+			dpriv->tx_dirty = dpriv->tx_current;
+			dev->trans_start = jiffies;
+			netif_wake_queue(dev);
+			printk(KERN_DEBUG "%s: re-enabled\n", dev->name);	
+		}
+	}
+        dpriv->timer.expires = jiffies + TX_TIMEOUT;
+        add_timer(&dpriv->timer);
+}
+
+static void dscc4_tx_timeout(struct net_device *dev)
+{
+	/* FIXME: something is missing there */
+};
+
+static int dscc4_open(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_pci_priv *ppriv;
+	u32 ioaddr = 0;
+
+	MOD_INC_USE_COUNT;
+
+	ppriv = dpriv->pci_priv;
+
+	if (dscc4_init_ring(dev))
+		goto err_out;
+
+	ioaddr = dev->base_addr + SCC_REG_START(dpriv->dev_id);
+
+	/* FIXME: VIS */
+	writel(readl(ioaddr + CCR0) | 0x80001000, ioaddr + CCR0);
+
+	writel(LengthCheck | (dev->mtu >> 5), ioaddr + RLCR);
+
+	/* no address recognition/crc-CCITT/cts enabled */
+	writel(readl(ioaddr + CCR1) | 0x021c8000, ioaddr + CCR1);
+
+	/* Ccr2.Rac = 0 */
+	writel(0x00050008 & ~RxActivate, ioaddr + CCR2);
+
+#ifdef EXPERIMENTAL_POLLING
+	writel(0xfffeef7f, ioaddr + IMR); /* Interrupt mask */
+#else
+	/* Don't mask RDO. Ever. */
+	//writel(0xfffaef7f, ioaddr + IMR); /* Interrupt mask */
+	writel(0xfffaef7e, ioaddr + IMR); /* Interrupt mask */
+#endif
+	/* IDT+IDR during XPR */
+	dpriv->flags = NeedIDR | NeedIDT;
+
+	/*
+	 * The following is a bit paranoid...
+	 *
+	 * NB: the datasheet "...CEC will stay active if the SCC is in
+	 * power-down mode or..." and CCR2.RAC = 1 are two different
+	 * situations.
+	 */
+	if (readl(ioaddr + STAR) & SccBusy) {
+		printk(KERN_ERR "%s busy. Try later\n", dev->name);
+		goto err_free_ring;
+	}
+	writel(TxSccRes | RxSccRes, ioaddr + CMDR);
+
+	/* ... the following isn't */
+	if (dscc4_wait_ack_cec(ioaddr, dev, "Cec"))
+		goto err_free_ring;
+
+	/* 
+	 * I would expect XPR near CE completion (before ? after ?).
+	 * At worst, this code won't see a late XPR and people
+	 * will have to re-issue an ifconfig (this is harmless). 
+	 * WARNING, a really missing XPR usually means a hardware 
+	 * reset is needed. Suggestions anyone ?
+	 */
+	if (dscc4_xpr_ack(dpriv))
+		goto err_free_ring;
+	
+	netif_start_queue(dev);
+
+        init_timer(&dpriv->timer);
+        dpriv->timer.expires = jiffies + 10*HZ;
+        dpriv->timer.data = (unsigned long)dev;
+        dpriv->timer.function = &dscc4_timer;
+        add_timer(&dpriv->timer);
+	netif_carrier_on(dev);
+
+	return 0;
+
+err_free_ring:
+	dscc4_release_ring(dpriv);
+err_out:
+	MOD_DEC_USE_COUNT;
+	return -EAGAIN;
+}
+
+#ifdef EXPERIMENTAL_POLLING
+static int dscc4_tx_poll(struct dscc4_dev_priv *dpriv, struct net_device *dev)
+{
+	/* FIXME: it's gonna be easy (TM), for sure */
+}
+#endif /* EXPERIMENTAL_POLLING */
+
+static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_pci_priv *ppriv;
+	struct TxFD *tx_fd;
+	int cur, next;
+
+	ppriv = dpriv->pci_priv;
+	cur = dpriv->tx_current++%TX_RING_SIZE;
+	next = dpriv->tx_current%TX_RING_SIZE;
+	dpriv->tx_skbuff[next] = skb;
+	tx_fd = dpriv->tx_fd + next;
+	tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len & TxSizeMax);
+	tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
+				     PCI_DMA_TODEVICE);
+	tx_fd->complete = 0x00000000;
+	mb(); // FIXME: suppress ?
+
+#ifdef EXPERIMENTAL_POLLING
+	spin_lock(&dpriv->lock);
+	while(dscc4_tx_poll(dpriv, dev));
+	spin_unlock(&dpriv->lock);
+#endif
+	/*
+	 * I know there's a window for a race in the following lines but
+	 * dscc4_timer will take good care of it. The chipset eats events
+	 * (especially the net_dev re-enabling ones) thus there is no
+	 * reason to try and be smart.
+	 */
+	if ((dpriv->tx_dirty + 16) < dpriv->tx_current) {
+			netif_stop_queue(dev);
+			dpriv->hi_expected = 2;
+	}
+	tx_fd = dpriv->tx_fd + cur;
+	tx_fd->state &= ~Hold;
+	mb(); // FIXME: suppress ?
+
+	/* 
+	 * One may avoid some pci transactions during intense TX periods.
+	 * Not sure it's worth the pain...
+	 */
+	writel((TxPollCmd << dpriv->dev_id) | NoAck, dev->base_addr + GCMDR);
+	dev->trans_start = jiffies;
+	return 0;
+}
+
+static int dscc4_close(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	u32 ioaddr = dev->base_addr;
+	int dev_id;
+
+	del_timer_sync(&dpriv->timer);
+	netif_stop_queue(dev);
+
+	dev_id = dpriv->dev_id;
+
+	writel(0x00050000, ioaddr + SCC_REG_START(dev_id) + CCR2);
+	writel(MTFi|Rdr|Rdt, ioaddr + CH0CFG + dev_id*0x0c); /* Reset Rx/Tx */
+	writel(0x00000001, ioaddr + GCMDR);
+
+	dscc4_release_ring(dpriv);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
+{
+	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	u32 brr;
+
+	*state &= ~Ccr0ClockMask;
+	if (*bps) { /* DCE */
+		u32 n = 0, m = 0, divider;
+		int xtal;
+
+		xtal = dpriv->pci_priv->xtal_hz;
+		if (!xtal)
+			return -1;
+		divider = xtal / *bps;
+		if (divider > BRR_DIVIDER_MAX) {
+			divider >>= 4;
+			*state |= 0x00000036; /* Clock mode 6b (BRG/16) */
+		} else
+			*state |= 0x00000037; /* Clock mode 7b (BRG) */
+		if (divider >> 22) {
+			n = 63;
+			m = 15;
+		} else if (divider) {
+			/* Extraction of the 6 highest weighted bits */
+			m = 0;
+			while (0xffffffc0 & divider) {
+				m++;
+				divider >>= 1;
+			}
+			n = divider;
+		}
+		brr = (m << 8) | n;
+		divider = n << m;
+		if (!(*state & 0x00000001)) /* Clock mode 6b */
+			divider <<= 4;
+		*bps = xtal / divider;
+	} else { /* DTE */
+		/* 
+		 * "state" already reflects Clock mode 0a. 
+		 * Nothing more to be done 
+		 */
+		brr = 0;
+	}
+	writel(brr, dev->base_addr + BRR + SCC_REG_START(dpriv->dev_id));
+
+	return 0;
+}
+
+#ifdef LATER_PLEASE
+/*
+ * -*- [RFC] Configuring Synchronous Interfaces in Linux -*-
+ */
+
+// FIXME: MEDIA already defined in linux/hdlc.h
+#define HDLC_MEDIA_V35		0
+#define HDLC_MEDIA_RS232	1
+#define HDLC_MEDIA_X21		2
+#define HDLC_MEDIA_E1		3
+#define HDLC_MEDIA_HSSI		4
+
+#define HDLC_CODING_NRZ		0
+#define HDLC_CODING_NRZI	1
+#define HDLC_CODING_FM0		2
+#define HDLC_CODING_FM1		3
+#define HDLC_CODING_MANCHESTER	4
+
+#define HDLC_CRC_NONE		0
+#define HDLC_CRC_16		1
+#define HDLC_CRC_32		2
+#define HDLC_CRC_CCITT		3
+
+/* RFC: add the crc reset value ? */
+struct hdlc_physical {
+	u8 media;
+	u8 coding;
+	u32 rate;
+	u8 crc;
+	u8 crc_siz;		/* 2 or 4 bytes */
+	u8 shared_flags;	/* Discouraged on the DSCC4 */
+};
+
+// FIXME: PROTO already defined in linux/hdlc.h
+#define HDLC_PROTO_RAW		0
+#define HDLC_PROTO_FR		1
+#define HDLC_PROTO_X25		2
+#define HDLC_PROTO_PPP		3
+#define HDLC_PROTO_CHDLC	4
+
+struct hdlc_protocol {
+	u8 proto; 
+	
+	union {
+	} u;
+};
+
+struct screq {
+	u16 media_group;
+
+	union {
+		struct hdlc_physical hdlc_phy;
+		struct hdlc_protocol hdlc_proto;
+	} u;
+};
+
+// FIXME: go sub-module 
+static struct {
+	u16 coding;
+	u16 bits;
+} map[] = {
+	{HDLC_CODING_NRZ,		0x00},
+	{HDLC_CODING_NRZI,		0x20},
+	{HDLC_CODING_FM0,		0x40},
+	{HDLC_CODING_FM1,		0x50},
+	{HDLC_CODING_MANCHESTER,	0x60},
+	{65535,	0x00}
+};
+#endif /* LATER_PLEASE */
+
+static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	u32 state, ioaddr;
+
+        if (dev->flags & IFF_UP)
+                return -EBUSY;
+
+	switch (cmd) {
+		/* Set built-in quartz frequency */
+		case SIOCDEVPRIVATE: {
+			u32 hz;
+
+			hz = ifr->ifr_ifru.ifru_ivalue;
+			if (hz >= 33000000) /* 33 MHz */
+				return -EOPNOTSUPP;
+			dpriv->pci_priv->xtal_hz = hz;
+			return 0;
+		}
+		/* Set/unset loopback */
+		case SIOCDEVPRIVATE+1: {
+			u32 flags;
+	
+			ioaddr = dev->base_addr + CCR1 +
+				 SCC_REG_START(dpriv->dev_id);
+			state = readl(ioaddr);
+			flags = ifr->ifr_ifru.ifru_ivalue;
+			if (flags & 0x00000001) {
+				printk(KERN_DEBUG "%s: loopback\n", dev->name);
+				state |= 0x00000100;
+			} else {
+				printk(KERN_DEBUG "%s: normal\n", dev->name);
+				state &= ~0x00000100;
+			}
+			writel(state, ioaddr);
+			return 0;
+		}
+
+#ifdef LATER_PLEASE
+		case SIOCDEVPRIVATE+2: {
+		{
+			struct screq scr;
+
+			err = copy_from_user(&scr, ifr->ifr_ifru.ifru_data, sizeof(struct screq));
+			if (err)
+				return err;
+			do {
+				if (scr.u.hdlc_phy.coding == map[i].coding)
+					break;
+			} while (map[++i].coding != 65535);
+			if (!map[i].coding)
+				return -EOPNOTSUPP;
+			
+			ioaddr = dev->base_addr + CCR0 +
+				 SCC_REG_START(dpriv->dev_id);
+			state = readl(ioaddr) & ~EncodingMask;
+			state |= (u32)map[i].bits << 16;
+			writel(state, ioaddr);	
+			printk("state: %08x\n", state); /* DEBUG */
+			return 0;
+		}
+		case SIOCDEVPRIVATE+3: {
+			struct screq *scr = (struct screq *)ifr->ifr_ifru.ifru_data;
+
+			ioaddr = dev->base_addr + CCR0 +
+				 SCC_REG_START(dpriv->dev_id);
+			state = (readl(ioaddr) & EncodingMask) >> 16;
+			do {
+				if (state == map[i].bits)
+					break;
+			} while (map[++i].coding);
+			return put_user(map[i].coding, (u16 *)scr->u.hdlc_phy.coding);
+		}
+#endif /* LATER_PLEASE */
+
+		case HDLCSCLOCKRATE:
+		{
+			u32 state, bps;
+ 
+			bps = ifr->ifr_ifru.ifru_ivalue;
+			ioaddr = dev->base_addr + CCR0 +
+				 SCC_REG_START(dpriv->dev_id);
+			state = readl(ioaddr);
+			if(dscc4_set_clock(dev, &bps, &state) < 0)
+				return -EOPNOTSUPP;
+			if (bps) { /* DCE */
+				printk(KERN_DEBUG "%s: generated RxClk (DCE)\n",
+				       dev->name);
+				ifr->ifr_ifru.ifru_ivalue = bps;
+			} else { /* DTE */
+				state = 0x80001000;
+				printk(KERN_DEBUG "%s: external RxClk (DTE)\n",
+				       dev->name);
+			}
+			writel(state, ioaddr);	
+			return 0;
+		}
+		case HDLCGCLOCKRATE: {
+			u32 brr;
+			int bps;
+
+			brr = readl(dev->base_addr + BRR + 
+				    SCC_REG_START(dpriv->dev_id));
+			bps = dpriv->pci_priv->xtal_hz >> (brr >> 8);
+			bps /= (brr & 0x3f) + 1;
+			ifr->ifr_ifru.ifru_ivalue = bps;
+			return 0;
+		}
+
+		default:
+			return -EOPNOTSUPP;
+	}
+}
+
+static int dscc4_change_mtu(struct net_device *dev, int mtu)
+{
+	/* FIXME: chainsaw coded... */
+	if ((mtu <= 3) || (mtu > 65531))
+		return -EINVAL;
+        if(dev->flags & IFF_UP)
+                return -EBUSY;
+	dev->mtu = mtu;
+        return(0);
+}
+
+static void dscc4_irq(int irq, void *dev_instance, struct pt_regs *ptregs)
+{
+	struct net_device *dev = dev_instance;
+	struct dscc4_pci_priv *priv;
+	u32 ioaddr, state;
+	unsigned long flags;
+	int i;
+
+	priv = ((struct dscc4_dev_priv *)dev->priv)->pci_priv;
+	/* 
+	 * FIXME: shorten the protected area (set some bit telling we're
+	 * in an interrupt or increment some work-to-do counter etc...)
+	 */
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ioaddr = dev->base_addr;
+
+	state = readl(ioaddr + GSTAR);
+	if (!state)
+		goto out;
+	writel(state, ioaddr + GSTAR);
+
+	if (state & Arf) { 
+		printk(KERN_ERR "%s: failure (Arf). Harass the maintener\n",
+		       dev->name);
+		goto out;
+	}
+	state &= ~ArAck;
+	if (state & Cfg) {
+		if (debug)
+			printk(KERN_DEBUG "CfgIV\n");
+		if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf)
+			printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG");
+		if (!(state &= ~Cfg))
+			goto out;
+	}
+	if (state & RxEvt) {
+		i = dev_per_card - 1;
+		do {
+			dscc4_rx_irq(priv, dev + i);
+		} while (--i >= 0);
+		state &= ~RxEvt;
+	}
+	if (state & TxEvt) {
+		i = dev_per_card - 1;
+		do {
+			dscc4_tx_irq(priv, dev + i);
+		} while (--i >= 0);
+		state &= ~TxEvt;
+	}
+out:
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static __inline__ void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, 
+				    struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	u32 state;
+	int cur, loop = 0;
+
+try:
+	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
+	state = dpriv->iqtx[cur];
+	if (!state) {
+#ifdef DEBUG
+		if (loop > 1)
+			printk(KERN_DEBUG "%s: Tx irq loop=%d\n", dev->name, loop);
+#endif
+		if (loop && netif_queue_stopped(dev))
+			if ((dpriv->tx_dirty + 8) >= dpriv->tx_current)
+				netif_wake_queue(dev);
+		return;
+	}
+	loop++;
+	dpriv->iqtx[cur] = 0;
+	dpriv->iqtx_current++;
+
+#ifdef DEBUG_PARANOID
+	if (SOURCE_ID(state) != dpriv->dev_id) {
+		printk(KERN_DEBUG "%s (Tx): Source Id=%d, state=%08x\n",
+		       dev->name, SOURCE_ID(state), state );
+		return;
+	}
+	if (state & 0x0df80c01) {
+		printk(KERN_DEBUG "%s (Tx): state=%08x (UFO alert)\n",
+		       dev->name, state);
+		return;
+	}
+#endif
+	// state &= 0x0fffffff; /* Tracking the analyzed bits */
+	if (state & SccEvt) {
+		if (state & Alls) {
+			struct TxFD *tx_fd;
+			struct sk_buff *skb;
+
+			cur = dpriv->tx_dirty%TX_RING_SIZE;
+			tx_fd = dpriv->tx_fd + cur;
+
+			skb = dpriv->tx_skbuff[cur];
+
+			/* XXX: hideous kludge - to be removed "later" */
+			if (!skb) {
+				printk(KERN_ERR "%s: NULL skb in tx_irq at index %d\n", dev->name, cur);
+				goto try;
+			}
+			dpriv->tx_dirty++; // MUST be after skb test
+
+			/* Happens sometime. Don't know what triggers it */
+			if (!(tx_fd->complete & DataComplete)) {
+				u32 ioaddr, isr;
+
+				ioaddr = dev->base_addr + 
+					 SCC_REG_START(dpriv->dev_id) + ISR;
+				isr = readl(ioaddr);
+				printk(KERN_DEBUG 
+				       "%s: DataComplete=0 cur=%d isr=%08x state=%08x\n",
+				       dev->name, cur, isr, state);
+				writel(isr, ioaddr);
+				dpriv->stats.tx_dropped++;
+			} else {
+				tx_fd->complete &= ~DataComplete;
+				if (tx_fd->state & FrameEnd) {
+					dpriv->stats.tx_packets++;
+					dpriv->stats.tx_bytes += skb->len;
+				}
+			}
+
+			dpriv->tx_skbuff[cur] = NULL;
+			pci_unmap_single(ppriv->pdev, tx_fd->data, skb->len,
+					 PCI_DMA_TODEVICE);
+			tx_fd->data = 0; /* DEBUG */
+			dev_kfree_skb_irq(skb);
+{ // DEBUG
+			cur = (dpriv->tx_dirty-1)%TX_RING_SIZE;
+			tx_fd = dpriv->tx_fd + cur;
+			tx_fd->state |= Hold;
+}
+			if (!(state &= ~Alls))
+				goto try;
+		}
+		/* 
+		 * Transmit Data Underrun
+		 */
+		if (state & Xdu) {
+			printk(KERN_ERR "dscc4: XDU. Contact maintainer\n");
+			dpriv->flags = NeedIDT; 
+			/* Tx reset */
+			writel(MTFi | Rdt, 
+			       dev->base_addr + 0x0c*dpriv->dev_id + CH0CFG);
+			writel(0x00000001, dev->base_addr + GCMDR);
+			return;
+		}
+		if (state & Xmr) {
+			/* Frame needs to be sent again - FIXME */
+			//dscc4_start_xmit(dpriv->tx_skbuff[dpriv->tx_dirty], dev);
+			if (!(state &= ~0x00002000)) /* DEBUG */
+				goto try;
+		}
+		if (state & Xpr) {
+			unsigned long ioaddr = dev->base_addr;
+			unsigned long scc_offset;
+			u32 scc_addr;
+
+			scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id);
+			scc_addr = ioaddr + 0x0c*dpriv->dev_id;
+			if (readl(scc_offset + STAR) & SccBusy)
+				printk(KERN_DEBUG "%s busy. Fatal\n", 
+				       dev->name);
+			/*
+			 * Keep this order: IDT before IDR
+			 */
+			if (dpriv->flags & NeedIDT) {
+				writel(MTFi | Idt, scc_addr + CH0CFG);
+				writel(dpriv->tx_fd_dma + 
+				       (dpriv->tx_dirty%TX_RING_SIZE)*
+				       sizeof(struct TxFD), scc_addr + CH0BTDA);
+				if(dscc4_do_action(dev, "IDT"))
+					goto err_xpr;
+				dpriv->flags &= ~NeedIDT;
+				mb();
+			}
+			if (dpriv->flags & NeedIDR) {
+				writel(MTFi | Idr, scc_addr + CH0CFG);
+				writel(dpriv->rx_fd_dma + 
+				       (dpriv->rx_current%RX_RING_SIZE)*
+				       sizeof(struct RxFD), scc_addr + CH0BRDA);
+				if(dscc4_do_action(dev, "IDR"))
+					goto err_xpr;
+				dpriv->flags &= ~NeedIDR;
+				mb();
+				/* Activate receiver and misc */
+				writel(0x08050008, scc_offset + CCR2);
+			}
+		err_xpr:
+			if (!(state &= ~Xpr))
+				goto try;
+		}
+	} else { /* ! SccEvt */
+		if (state & Hi) {
+#ifdef EXPERIMENTAL_POLLING
+			while(!dscc4_tx_poll(dpriv, dev));
+#endif
+			state &= ~Hi;
+		}
+		/*
+		 * FIXME: it may be avoided. Re-re-re-read the manual.
+		 */
+		if (state & Err) {
+			printk(KERN_ERR "%s: Tx ERR\n", dev->name);
+			dpriv->stats.tx_errors++;
+			state &= ~Err;
+		}
+	}
+	goto try;
+}
+
+static __inline__ void dscc4_rx_irq(struct dscc4_pci_priv *priv, struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	u32 state;
+	int cur;
+
+try:
+	cur = dpriv->iqrx_current%IRQ_RING_SIZE;
+	state = dpriv->iqrx[cur];
+	if (!state)
+		return;
+	dpriv->iqrx[cur] = 0;
+	dpriv->iqrx_current++;
+
+#ifdef DEBUG_PARANOID
+	if (SOURCE_ID(state) != dpriv->dev_id) {
+		printk(KERN_DEBUG "%s (Rx): Source Id=%d, state=%08x\n",
+		       dev->name, SOURCE_ID(state), state);
+		goto try;
+	}
+	if (state & 0x0df80c01) {
+		printk(KERN_DEBUG "%s (Rx): state=%08x (UFO alert)\n",
+		       dev->name, state);
+		goto try;
+	}
+#endif
+	if (!(state & SccEvt)){
+		struct RxFD *rx_fd;
+
+		state &= 0x00ffffff;
+		if (state & Err) { /* Hold or reset */
+			printk(KERN_DEBUG "%s (Rx): ERR\n", dev->name);
+			cur = dpriv->rx_current;
+			rx_fd = dpriv->rx_fd + cur;
+			/*
+			 * Presume we're not facing a DMAC receiver reset. 
+			 * As We use the rx size-filtering feature of the 
+			 * DSCC4, the beginning of a new frame is waiting in 
+			 * the rx fifo. I bet a Receive Data Overflow will 
+			 * happen most of time but let's try and avoid it.
+			 * Btw (as for RDO) if one experiences ERR whereas
+			 * the system looks rather idle, there may be a 
+			 * problem with latency. In this case, increasing
+			 * RX_RING_SIZE may help.
+			 */
+			while (dpriv->rx_needs_refill) {
+				while(!(rx_fd->state1 & Hold)) {
+					rx_fd++;
+					cur++;
+					if (!(cur = cur%RX_RING_SIZE))
+						rx_fd = dpriv->rx_fd;
+				}
+				dpriv->rx_needs_refill--;
+				try_get_rx_skb(dpriv, cur, dev);
+				if (!rx_fd->data)
+					goto try;
+				rx_fd->state1 &= ~Hold;
+				rx_fd->state2 = 0x00000000;
+				rx_fd->end = 0xbabeface;
+			}
+			goto try;
+		}
+		if (state & Fi) {
+			cur = dpriv->rx_current%RX_RING_SIZE;
+			rx_fd = dpriv->rx_fd + cur;
+			dscc4_rx_skb(dpriv, cur, rx_fd, dev);
+			dpriv->rx_current++;
+			goto try;
+		}
+		if (state & Hi ) { /* HI bit */
+			state &= ~Hi;
+			goto try;
+		}
+	} else { /* ! SccEvt */
+#ifdef DEBUG_PARANOIA
+		int i;
+		static struct {
+			u32 mask;
+			const char *irq_name;
+		} evts[] = {
+			{ 0x00008000, "TIN"},
+			{ 0x00004000, "CSC"},
+			{ 0x00000020, "RSC"},
+			{ 0x00000010, "PCE"},
+			{ 0x00000008, "PLLA"},
+			{ 0x00000004, "CDSC"},
+			{ 0, NULL}
+		};
+#endif /* DEBUG_PARANOIA */
+		state &= 0x00ffffff;
+#ifdef DEBUG_PARANOIA
+		for (i = 0; evts[i].irq_name; i++) {
+			if (state & evts[i].mask) {
+				printk(KERN_DEBUG "dscc4(%s): %s\n",
+					dev->name, evts[i].irq_name);
+				if (!(state &= ~evts[i].mask))
+					goto try;
+			}
+		}
+#endif /* DEBUG_PARANOIA */
+		/*
+		 * Receive Data Overflow (FIXME: untested)
+		 */
+		if (state & Rdo) {
+			u32 ioaddr, scc_offset, scc_addr;
+			struct RxFD *rx_fd;
+			int cur;
+
+			//if (debug)
+			//	dscc4_rx_dump(dpriv);
+			ioaddr = dev->base_addr;
+			scc_addr = ioaddr + 0x0c*dpriv->dev_id;
+			scc_offset = ioaddr + SCC_REG_START(dpriv->dev_id);
+
+			writel(readl(scc_offset + CCR2) & ~RxActivate, 
+			       scc_offset + CCR2);
+			/*
+			 * This has no effect. Why ?
+			 * ORed with TxSccRes, one sees the CFG ack (for
+			 * the TX part only).
+			 */	
+			writel(RxSccRes, scc_offset + CMDR);
+			dpriv->flags |= RdoSet;
+
+			/* 
+			 * Let's try and save something in the received data.
+			 * rx_current must be incremented at least once to
+			 * avoid HOLD in the BRDA-to-be-pointed desc.
+			 */
+			do {
+				cur = dpriv->rx_current++%RX_RING_SIZE;
+				rx_fd = dpriv->rx_fd + cur;
+				if (!(rx_fd->state2 & DataComplete))
+					break;
+				if (rx_fd->state2 & FrameAborted) {
+					dpriv->stats.rx_over_errors++;
+					rx_fd->state1 |= Hold;
+					rx_fd->state2 = 0x00000000;
+					rx_fd->end = 0xbabeface;
+				} else 
+					dscc4_rx_skb(dpriv, cur, rx_fd, dev);
+			} while (1);
+
+			if (debug) {
+				if (dpriv->flags & RdoSet)
+					printk(KERN_DEBUG 
+					       "dscc4: no RDO in Rx data\n");
+			}
+#ifdef DSCC4_RDO_EXPERIMENTAL_RECOVERY
+			/*
+			 * FIXME: must the reset be this violent ?
+			 */
+			writel(dpriv->rx_fd_dma + 
+			       (dpriv->rx_current%RX_RING_SIZE)*
+			       sizeof(struct RxFD), scc_addr + CH0BRDA);
+			writel(MTFi|Rdr|Idr, scc_addr + CH0CFG);
+			if(dscc4_do_action(dev, "RDR")) {
+				printk(KERN_ERR "%s: RDO recovery failed(%s)\n",
+				       dev->name, "RDR");
+				goto rdo_end;
+			}
+			writel(MTFi|Idr, scc_addr + CH0CFG);
+			if(dscc4_do_action(dev, "IDR")) {
+				printk(KERN_ERR "%s: RDO recovery failed(%s)\n",
+				       dev->name, "IDR");
+				goto rdo_end;
+			}
+		rdo_end:
+#endif
+			writel(readl(scc_offset + CCR2) | RxActivate, 
+			       scc_offset + CCR2);
+			goto try;
+		}
+		/* These will be used later */
+		if (state & Rfs) {
+			if (!(state &= ~Rfs))
+				goto try;
+		}
+		if (state & Rfo) {
+			if (!(state &= ~Rfo))
+				goto try;
+		}
+		if (state & Flex) {
+			if (!(state &= ~Flex))
+				goto try;
+		}
+	}
+}
+
+static int dscc4_init_ring(struct net_device *dev)
+{
+	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct TxFD *tx_fd;
+	struct RxFD *rx_fd;
+	int i;
+
+	tx_fd = (struct TxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev,
+		TX_RING_SIZE*sizeof(struct TxFD), &dpriv->tx_fd_dma);
+	if (!tx_fd)
+		goto err_out;
+	rx_fd = (struct RxFD *) pci_alloc_consistent(dpriv->pci_priv->pdev,
+		RX_RING_SIZE*sizeof(struct RxFD), &dpriv->rx_fd_dma);
+	if (!rx_fd)
+		goto err_free_dma_tx;
+
+	dpriv->tx_fd = tx_fd;
+	dpriv->rx_fd = rx_fd;
+	dpriv->rx_current = 0;
+	dpriv->tx_current = 0;
+	dpriv->tx_dirty = 0;
+
+	/* the dma core of the dscc4 will be locked on the first desc */
+	for(i = 0; i < TX_RING_SIZE; ) {
+		reset_TxFD(tx_fd);
+	        /* FIXME: NULL should be ok - to be tried */
+	        tx_fd->data = dpriv->tx_fd_dma;
+	        dpriv->tx_skbuff[i] = NULL;
+		i++;
+		tx_fd->next = (u32)(dpriv->tx_fd_dma + i*sizeof(struct TxFD));
+		tx_fd++;
+	}
+	(--tx_fd)->next = (u32)dpriv->tx_fd_dma;
+{
+	/*
+	 * XXX: I would expect the following to work for the first descriptor
+	 * (tx_fd->state = 0xc0000000)
+	 * - Hold=1 (don't try and branch to the next descripto);
+	 * - No=0 (I want an empty data section, i.e. size=0);
+	 * - Fe=1 (required by No=0 or we got an Err irq and must reset).
+	 * Alas, it fails (and locks solid). Thus the introduction of a dummy
+	 * skb to avoid No=0 (choose one: Ugly [ ] Tasteless [ ] VMS [ ]).
+	 * TODO: fiddle the tx threshold when time permits.
+	 */
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(32);
+	if (!skb)
+		goto err_free_dma_tx;
+	skb->len = 32;
+	memset(skb->data, 0xaa, 16);
+	tx_fd -= (TX_RING_SIZE - 1);
+	tx_fd->state = 0xc0000000;
+	tx_fd->state |= ((u32)(skb->len & TxSizeMax)) << 16;
+	tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, 
+				     skb->len, PCI_DMA_TODEVICE);
+	dpriv->tx_skbuff[0] = skb;
+}
+	for (i = 0; i < RX_RING_SIZE;) {
+		/* size set by the host. Multiple of 4 bytes please */
+	        rx_fd->state1 = HiDesc; /* Hi, no Hold */
+	        rx_fd->state2 = 0x00000000;
+	        rx_fd->end = 0xbabeface;
+	        rx_fd->state1 |= ((u32)(dev->mtu & RxSizeMax)) << 16;
+		try_get_rx_skb(dpriv, i, dev);
+		i++;
+		rx_fd->next = (u32)(dpriv->rx_fd_dma + i*sizeof(struct RxFD));
+		rx_fd++;
+	}
+	(--rx_fd)->next = (u32)dpriv->rx_fd_dma;
+	rx_fd->state1 |= 0x40000000; /* Hold */
+
+	return 0;
+
+err_free_dma_tx:
+	pci_free_consistent(dpriv->pci_priv->pdev, TX_RING_SIZE*sizeof(*tx_fd),
+			    tx_fd, dpriv->tx_fd_dma);
+err_out:
+	return -1;
+}
+
+static struct net_device_stats *dscc4_get_stats(struct net_device *dev)
+{
+	struct dscc4_dev_priv *priv = (struct dscc4_dev_priv *)dev->priv;
+
+	return &priv->stats;
+}
+
+static void __exit dscc4_remove_one(struct pci_dev *pdev)
+{
+	struct dscc4_pci_priv *ppriv;
+	struct net_device *root;
+	int i;
+
+	ppriv = pci_get_drvdata(pdev);
+	root = ppriv->root;
+
+	free_irq(pdev->irq, root);
+	pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), ppriv->iqcfg, 
+			    ppriv->iqcfg_dma);
+	for (i=0; i < dev_per_card; i++) {
+		struct dscc4_dev_priv *dpriv;
+		struct net_device *dev;
+
+		dev = ppriv->root + i;
+		dscc4_unattach_hdlc_device(dev);
+
+		dpriv = (struct dscc4_dev_priv *)dev->priv;
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+				    dpriv->iqrx, dpriv->iqrx_dma);
+		pci_free_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), 
+				    dpriv->iqtx, dpriv->iqtx_dma);
+		unregister_netdev(dev);
+	}
+	kfree(root->priv);
+
+	iounmap((void *)root->base_addr);
+	kfree(root);
+
+	kfree(ppriv);
+
+	release_mem_region(pci_resource_start(pdev, 1),
+			   pci_resource_len(pdev, 1));
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
+}
+
+static int dscc4_hdlc_ioctl(struct hdlc_device_struct *hdlc, struct ifreq *ifr, int cmd)
+{
+	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
+	int result;
+
+	/* FIXME: locking ? */
+	result = dscc4_ioctl(dev, ifr, cmd);
+	return result;
+}
+
+static int dscc4_hdlc_open(struct hdlc_device_struct *hdlc)
+{
+	struct net_device *dev = (struct net_device *)(hdlc->netdev.base_addr);
+
+        if (netif_running(dev)) {
+		printk(KERN_DEBUG "%s: already running\n", dev->name); // DEBUG
+		return 0;
+	}
+	return dscc4_open(dev);
+}
+
+static int dscc4_hdlc_xmit(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
+
+	return dscc4_start_xmit(skb, dev);
+}
+
+static void dscc4_hdlc_close(struct hdlc_device_struct *hdlc)
+{
+	struct net_device *dev = (struct net_device *)hdlc->netdev.base_addr;
+	struct dscc4_dev_priv *dpriv;
+
+	dpriv = dev->priv;
+	--dpriv->usecount;
+}
+
+/* Operated under dev lock */
+static int dscc4_attach_hdlc_device(struct net_device *dev) 
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct hdlc_device_struct *hdlc;
+	int result;
+
+	hdlc = &dpriv->hdlc;
+	/* XXX: Don't look at the next line */
+	hdlc->netdev.base_addr = (unsigned long)dev;
+	// FIXME: set hdlc->set_mode ?
+	hdlc->open = dscc4_hdlc_open;
+	hdlc->close = dscc4_hdlc_close;
+	hdlc->ioctl = dscc4_hdlc_ioctl;
+	hdlc->xmit = dscc4_hdlc_xmit;
+
+	result = register_hdlc_device(hdlc);
+	if (!result)
+		dpriv->usecount++;
+	return result;
+}
+
+/* Operated under dev lock */
+static void dscc4_unattach_hdlc_device(struct net_device *dev) 
+{
+	struct dscc4_dev_priv *dpriv = dev->priv;
+
+	unregister_hdlc_device(&dpriv->hdlc);
+	dpriv->usecount--;
+}
+
+static struct pci_device_id dscc4_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_SIEMENS_DSCC4,
+	        PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl);
+
+static struct pci_driver dscc4_driver = {
+	name:           "dscc4",
+	id_table:       dscc4_pci_tbl,
+	probe:          dscc4_init_one,
+	remove:         dscc4_remove_one,
+};
+
+static int __init dscc4_init_module(void)
+{
+	return pci_module_init(&dscc4_driver);
+}
+
+static void __exit dscc4_cleanup_module(void)
+{
+	pci_unregister_driver(&dscc4_driver);
+}
+
+module_init(dscc4_init_module);
+module_exit(dscc4_cleanup_module);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hd64570.h linux/drivers/net/wan/hd64570.h
--- v2.4.2/linux/drivers/net/wan/hd64570.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/hd64570.h	Tue Mar  6 19:44:36 2001
@@ -0,0 +1,234 @@
+#ifndef __HD64570_H
+#define __HD64570_H
+
+/* SCA HD64570 register definitions - all addresses for mode 0 (8086 MPU)
+   and 1 (64180 MPU). For modes 2 and 3, XOR the address with 0x01.
+
+   Source: HD64570 SCA User's Manual
+*/
+
+
+
+/* SCA Control Registers */
+#define LPR    0x00		/* Low Power */
+
+/* Wait controller registers */
+#define PABR0  0x02		/* Physical Address Boundary 0 */
+#define PABR1  0x03		/* Physical Address Boundary 1 */
+#define WCRL   0x04		/* Wait Control L */
+#define WCRM   0x05		/* Wait Control M */
+#define WCRH   0x06		/* Wait Control H */
+
+#define PCR    0x08		/* DMA Priority Control */
+#define DMER   0x09		/* DMA Master Enable */
+
+
+/* Interrupt registers */
+#define ISR0   0x10		/* Interrupt Status 0  */
+#define ISR1   0x11		/* Interrupt Status 1  */
+#define ISR2   0x12		/* Interrupt Status 2  */
+
+#define IER0   0x14		/* Interrupt Enable 0  */
+#define IER1   0x15		/* Interrupt Enable 1  */
+#define IER2   0x16		/* Interrupt Enable 2  */
+
+#define ITCR   0x18		/* Interrupt Control */
+#define IVR    0x1A		/* Interrupt Vector */
+#define IMVR   0x1C		/* Interrupt Modified Vector */
+
+
+
+/* MSCI channel (port) 0 registers - offset 0x20
+   MSCI channel (port) 1 registers - offset 0x40 */
+
+#define MSCI0_OFFSET 0x20
+#define MSCI1_OFFSET 0x40
+
+#define TRBL   0x00		/* TX/RX buffer L */ 
+#define TRBH   0x01		/* TX/RX buffer H */ 
+#define ST0    0x02		/* Status 0 */
+#define ST1    0x03		/* Status 1 */
+#define ST2    0x04		/* Status 2 */
+#define ST3    0x05		/* Status 3 */
+#define FST    0x06		/* Frame Status  */
+#define IE0    0x08		/* Interrupt Enable 0 */
+#define IE1    0x09		/* Interrupt Enable 1 */
+#define IE2    0x0A		/* Interrupt Enable 2 */
+#define FIE    0x0B		/* Frame Interrupt Enable  */
+#define CMD    0x0C		/* Command */
+#define MD0    0x0E		/* Mode 0 */
+#define MD1    0x0F		/* Mode 1 */
+#define MD2    0x10		/* Mode 2 */
+#define CTL    0x11		/* Control */
+#define SA0    0x12		/* Sync/Address 0 */
+#define SA1    0x13		/* Sync/Address 1 */
+#define IDL    0x14		/* Idle Pattern */
+#define TMC    0x15		/* Time Constant */
+#define RXS    0x16		/* RX Clock Source */
+#define TXS    0x17		/* TX Clock Source */
+#define TRC0   0x18		/* TX Ready Control 0 */ 
+#define TRC1   0x19		/* TX Ready Control 1 */ 
+#define RRC    0x1A		/* RX Ready Control */ 
+#define CST0   0x1C		/* Current Status 0 */
+#define CST1   0x1D		/* Current Status 1 */
+
+
+/* Timer channel 0 (port 0 RX) registers - offset 0x60
+   Timer channel 1 (port 0 TX) registers - offset 0x68
+   Timer channel 2 (port 1 RX) registers - offset 0x70
+   Timer channel 3 (port 1 TX) registers - offset 0x78
+*/
+
+#define TIMER0RX_OFFSET 0x60
+#define TIMER0TX_OFFSET 0x68
+#define TIMER1RX_OFFSET 0x70
+#define TIMER1TX_OFFSET 0x78
+
+#define TCNTL  0x00		/* Up-counter L */
+#define TCNTH  0x01		/* Up-counter H */
+#define TCONRL 0x02		/* Constant L */
+#define TCONRH 0x03		/* Constant H */
+#define TCSR   0x04		/* Control/Status */
+#define TEPR   0x05		/* Expand Prescale */
+
+
+
+/* DMA channel 0 (port 0 RX) registers - offset 0x80
+   DMA channel 1 (port 0 TX) registers - offset 0xA0
+   DMA channel 2 (port 1 RX) registers - offset 0xC0
+   DMA channel 3 (port 1 TX) registers - offset 0xE0
+*/
+
+#define DMAC0RX_OFFSET 0x80
+#define DMAC0TX_OFFSET 0xA0
+#define DMAC1RX_OFFSET 0xC0
+#define DMAC1TX_OFFSET 0xE0
+
+#define BARL   0x00		/* Buffer Address L (chained block) */
+#define BARH   0x01		/* Buffer Address H (chained block) */
+#define BARB   0x02		/* Buffer Address B (chained block) */
+
+#define DARL   0x00		/* RX Destination Addr L (single block) */
+#define DARH   0x01		/* RX Destination Addr H (single block) */
+#define DARB   0x02		/* RX Destination Addr B (single block) */
+
+#define SARL   0x04		/* TX Source Address L (single block) */
+#define SARH   0x05		/* TX Source Address H (single block) */
+#define SARB   0x06		/* TX Source Address B (single block) */
+
+#define CPB    0x06		/* Chain Pointer Base (chained block) */
+
+#define CDAL   0x08		/* Current Descriptor Addr L (chained block) */
+#define CDAH   0x09		/* Current Descriptor Addr H (chained block) */
+#define EDAL   0x0A		/* Error Descriptor Addr L (chained block) */
+#define EDAH   0x0B		/* Error Descriptor Addr H (chained block) */
+#define BFLL   0x0C		/* RX Receive Buffer Length L (chained block)*/
+#define BFLH   0x0D		/* RX Receive Buffer Length H (chained block)*/
+#define BCRL   0x0E		/* Byte Count L */
+#define BCRH   0x0F		/* Byte Count H */
+#define DSR    0x10		/* DMA Status */
+#define DSR_RX(node) (DSR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET))
+#define DSR_TX(node) (DSR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET))
+#define DMR    0x11		/* DMA Mode */
+#define DMR_RX(node) (DMR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET))
+#define DMR_TX(node) (DMR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET))
+#define FCT    0x13		/* Frame End Interrupt Counter */
+#define FCT_RX(node) (FCT + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET))
+#define FCT_TX(node) (FCT + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET))
+#define DIR    0x14		/* DMA Interrupt Enable */
+#define DIR_RX(node) (DIR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET))
+#define DIR_TX(node) (DIR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET))
+#define DCR    0x15		/* DMA Command  */
+#define DCR_RX(node) (DCR + (node ? DMAC1RX_OFFSET : DMAC0RX_OFFSET))
+#define DCR_TX(node) (DCR + (node ? DMAC1TX_OFFSET : DMAC0TX_OFFSET))
+
+
+
+
+/* Descriptor Structure */
+
+typedef struct {
+	u16 cp;			/* Chain Pointer */
+	u32 bp;			/* Buffer Pointer (24 bits) */
+	u16 len;		/* Data Length */
+	u8 stat;		/* Status */
+	u8 unused2;
+}__attribute__ ((packed)) pkt_desc;
+
+
+/* Packet Descriptor Status bits */
+
+#define ST_TX_EOM     0x80	/* End of frame */
+#define ST_TX_EOT     0x01	/* End of transmition */
+
+#define ST_RX_EOM     0x80	/* End of frame */
+#define ST_RX_SHORT   0x40	/* Short frame */
+#define ST_RX_ABORT   0x20	/* Abort */
+#define ST_RX_RESBIT  0x10	/* Residual bit */
+#define ST_RX_OVERRUN 0x08	/* Overrun */
+#define ST_RX_CRC     0x04	/* CRC */
+
+#define ST_ERROR_MASK 0x7C
+
+#define DIR_EOTE      0x80      /* Transfer completed */
+#define DIR_EOME      0x40      /* Frame Transfer Completed (chained-block) */
+#define DIR_BOFE      0x20      /* Buffer Overflow/Underflow (chained-block)*/
+#define DIR_COFE      0x10      /* Counter Overflow (chained-block) */
+
+
+#define DSR_EOT       0x80      /* Transfer completed */
+#define DSR_EOM       0x40      /* Frame Transfer Completed (chained-block) */
+#define DSR_BOF       0x20      /* Buffer Overflow/Underflow (chained-block)*/
+#define DSR_COF       0x10      /* Counter Overflow (chained-block) */
+#define DSR_DE        0x02	/* DMA Enable */
+#define DSR_DWE       0x01      /* DMA Write Disable */
+
+/* DMA Master Enable Register (DMER) bits */
+#define DMER_DME      0x80	/* DMA Master Enable */
+
+
+#define CMD_RESET     0x21	/* Reset Channel */
+#define CMD_TX_ENABLE 0x02	/* Start transmitter */
+#define CMD_RX_ENABLE 0x12	/* Start receiver */
+
+#define MD0_HDLC      0x80	/* Bit-sync HDLC mode */
+#define MD0_CRC_ENA   0x04	/* Enable CRC code calculation */
+#define MD0_CRC_CCITT 0x02	/* CCITT CRC instead of CRC-16 */
+#define MD0_CRC_PR1   0x01	/* Initial all-ones instead of all-zeros */
+
+#define MD0_CRC_NONE  0x00
+#define MD0_CRC_16_0  0x04
+#define MD0_CRC_16    0x05
+#define MD0_CRC_ITU_0 0x06
+#define MD0_CRC_ITU   0x07
+
+#define MD2_NRZI      0x20	/* NRZI mode */
+#define MD2_LOOPBACK  0x03      /* Local data Loopback */
+
+#define CTL_NORTS     0x01
+#define CTL_IDLE      0x10	/* Transmit an idle pattern */
+#define CTL_UDRNC     0x20	/* Idle after CRC or FCS+flag transmition */
+
+#define ST0_TXRDY     0x02	/* TX ready */
+#define ST0_RXRDY     0x01	/* RX ready */
+
+#define ST1_UDRN      0x80	/* MSCI TX underrun */
+
+#define ST3_CTS       0x08	/* modem input - /CTS */
+#define ST3_DCD       0x04	/* modem input - /DCD */
+
+#define IE0_TXINT     0x80	/* TX INT MSCI interrupt enable */
+#define IE1_UDRN      0x80	/* TX underrun MSCI interrupt enable */
+
+#define DCR_ABORT     0x01	/* Software abort command */
+#define DCR_CLEAR_EOF 0x02	/* Clear EOF interrupt */
+
+/* TX and RX Clock Source - RXS and TXS */
+#define CLK_BRG_MASK  0x0F
+#define CLK_LINE_RX   0x00	/* TX/RX clock line input */
+#define CLK_LINE_TX   0x00	/* TX/RX line input */
+#define CLK_BRG_RX    0x40	/* internal baud rate generator */
+#define CLK_BRG_TX    0x40	/* internal baud rate generator */
+#define CLK_RXCLK_TX  0x60	/* TX clock from RX clock */
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hd6457x.c linux/drivers/net/wan/hd6457x.c
--- v2.4.2/linux/drivers/net/wan/hd6457x.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/hd6457x.c	Tue Mar  6 19:44:36 2001
@@ -0,0 +1,757 @@
+/*
+ * Hitachi SCA HD64570 and HD64572 common driver for Linux
+ *
+ * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * Sources of information:
+ *    Hitachi HD64570 SCA User's Manual
+ *    Hitachi HD64572 SCA-II User's Manual
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/hdlc.h>
+
+#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \
+    (defined (__HD64570_H) && defined (__HD64572_H))
+#error Either hd64570.h or hd64572.h must be included
+#endif
+
+
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
+
+/* Maximum events to handle at each interrupt - should I increase it? */
+#define INTR_WORK 4
+
+#define get_msci(port)	  (phy_node(port) ?   MSCI1_OFFSET :   MSCI0_OFFSET)
+#define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
+#define get_dmac_tx(port) (phy_node(port) ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)
+
+#define SCA_INTR_MSCI(node)    (node ? 0x10 : 0x01)
+#define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02)
+#define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04)
+
+#ifdef __HD64570_H /* HD64570 */
+#define sca_outa(value, reg, card)	sca_outw(value, reg, card)
+#define sca_ina(reg, card)		sca_inw(reg, card)
+#define writea(value, ptr)		writew(value, ptr)
+
+static inline int sca_intr_status(card_t *card)
+{
+	u8 isr0 = sca_in(ISR0, card);
+	u8 isr1 = sca_in(ISR1, card);
+	u8 result = 0;
+
+	if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0);
+	if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0);
+	if (isr1 & 0x30) result |= SCA_INTR_DMAC_RX(1);
+	if (isr1 & 0xC0) result |= SCA_INTR_DMAC_TX(1);
+	if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
+	if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
+
+	return result;
+}
+
+#else /* HD64572 */
+#define sca_outa(value, reg, card)	sca_outl(value, reg, card)
+#define sca_ina(reg, card)		sca_inl(reg, card)
+#define writea(value, ptr)		writel(value, ptr)
+
+
+static inline int sca_intr_status(card_t *card)
+{
+	u32 isr0 = sca_inl(ISR0, card);
+	u8 result = 0;
+
+	if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0);
+	if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0);
+	if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1);
+	if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1);
+	if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0);
+	if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1);
+
+	return result;
+}
+
+#endif /* HD64570 vs HD64572 */
+
+
+
+
+static inline port_t* hdlc_to_port(hdlc_device *hdlc)
+{
+	return (port_t*)hdlc;
+}
+
+
+
+static inline port_t* dev_to_port(struct net_device *dev)
+{
+	return hdlc_to_port(dev_to_hdlc(dev));
+}
+
+
+
+static inline u8 next_desc(port_t *port, u8 desc)
+{
+	return (desc + 1) % port_to_card(port)->ring_buffers;
+}
+
+
+
+static inline u16 desc_offset(port_t *port, u8 desc, u8 transmit)
+{
+	/* Descriptor offset always fits in 16 bytes */
+	u8 buffs = port_to_card(port)->ring_buffers;
+	return ((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) *
+		sizeof(pkt_desc);
+}
+
+
+
+static inline pkt_desc* desc_address(port_t *port, u8 desc, u8 transmit)
+{
+#ifdef PAGE0_ALWAYS_MAPPED
+	return (pkt_desc*)(win0base(port_to_card(port))
+			   + desc_offset(port, desc, transmit));
+#else
+	return (pkt_desc*)(winbase(port_to_card(port))
+			   + desc_offset(port, desc, transmit));
+#endif
+}
+
+
+
+static inline u32 buffer_offset(port_t *port, u8 desc, u8 transmit)
+{
+	u8 buffs = port_to_card(port)->ring_buffers;
+	return port_to_card(port)->buff_offset +
+		((log_node(port) * 2 + transmit) * buffs + (desc % buffs)) *
+		(u32)HDLC_MAX_MRU;
+}
+
+
+
+static void sca_init_sync_port(port_t *port)
+{
+	card_t *card = port_to_card(port);
+	u8 transmit, i;
+	u16 dmac, buffs = card->ring_buffers;
+
+	port->rxin = 0;
+	port->txin = 0;
+	port->txlast = 0;
+
+#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+	openwin(card, 0);
+#endif
+
+	for (transmit = 0; transmit < 2; transmit++) {
+		for (i = 0; i < buffs; i++) {
+			pkt_desc* desc = desc_address(port, i, transmit);
+			u16 chain_off = desc_offset(port, i + 1, transmit);
+			u32 buff_off = buffer_offset(port, i, transmit);
+
+			writea(chain_off, &desc->cp);
+			writel(buff_off, &desc->bp);
+			writew(0, &desc->len);
+			writeb(0, &desc->stat);
+		}
+
+		dmac = transmit ? get_dmac_tx(port) : get_dmac_rx(port);
+		/* DMA disable - to halt state */
+		sca_out(0, transmit ? DSR_TX(phy_node(port)) :
+			DSR_RX(phy_node(port)), card);
+		/* software ABORT - to initial state */
+		sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) :
+			DCR_RX(phy_node(port)), card);
+
+#ifdef __HD64570_H
+		sca_out(0, dmac + CPB, card); /* pointer base */
+#endif
+		/* current desc addr */
+		sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card);
+		if (!transmit)
+			sca_outa(desc_offset(port, buffs - 1, transmit),
+				 dmac + EDAL, card);
+		else
+			sca_outa(desc_offset(port, 0, transmit), dmac + EDAL,
+				 card);
+
+		/* clear frame end interrupt counter */
+		sca_out(DCR_CLEAR_EOF, transmit ? DCR_TX(phy_node(port)) :
+			DCR_RX(phy_node(port)), card);
+
+		if (!transmit) { /* Receive */
+			/* set buffer length */
+			sca_outw(HDLC_MAX_MRU, dmac + BFLL, card);
+			/* Chain mode, Multi-frame */
+			sca_out(0x14, DMR_RX(phy_node(port)), card);
+			sca_out(DIR_EOME | DIR_BOFE, DIR_RX(phy_node(port)),
+				card);
+			/* DMA enable */
+			sca_out(DSR_DE, DSR_RX(phy_node(port)), card);
+		} else {	/* Transmit */
+			/* Chain mode, Multi-frame */
+			sca_out(0x14, DMR_TX(phy_node(port)), card);
+			/* enable underflow interrupts */
+			sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card);
+		}
+	}
+}
+
+
+
+/* MSCI interrupt service */
+static inline void sca_msci_intr(port_t *port)
+{
+	u16 msci = get_msci(port);
+	card_t* card = port_to_card(port);
+	u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */
+
+	/* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n",
+	   stat, sca_in(ILAR, card)); */
+
+	/* Reset MSCI TX underrun status bit */
+	sca_out(stat & ST1_UDRN, msci + ST1, card);
+
+	if (stat & ST1_UDRN) {
+		port->hdlc.stats.tx_errors++; /* TX Underrun error detected */
+		port->hdlc.stats.tx_fifo_errors++;
+	}
+}
+
+
+
+static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc,
+			      u8 rxin)
+{
+	struct sk_buff *skb;
+	u16 len;
+	u32 buff;
+#ifndef ALL_PAGES_ALWAYS_MAPPED
+	u32 maxlen;
+	u8 page;
+#endif
+
+	len = readw(&desc->len);
+	skb = dev_alloc_skb(len);
+	if (!skb) {
+		port->hdlc.stats.rx_dropped++;
+		return;
+	}
+
+	buff = buffer_offset(port, rxin, 0);
+#ifndef ALL_PAGES_ALWAYS_MAPPED
+	page = buff / winsize(card);
+	buff = buff % winsize(card);
+	maxlen = winsize(card) - buff;
+
+	openwin(card, page);
+
+	if (len > maxlen) {
+		memcpy_fromio(skb->data, winbase(card) + buff, maxlen);
+		openwin(card, page + 1);
+		memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen);
+	} else
+#endif
+	memcpy_fromio(skb->data, winbase(card) + buff, len);
+
+#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+	/* select pkt_desc table page back */
+	openwin(card, 0);
+#endif
+	skb_put(skb, len);
+#ifdef DEBUG_PKT
+	printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len);
+	debug_frame(skb);
+#endif
+	port->hdlc.stats.rx_packets++;
+	port->hdlc.stats.rx_bytes += skb->len;
+	hdlc_netif_rx(&port->hdlc, skb);
+}
+
+
+
+/* Receive DMA interrupt service */
+static inline void sca_rx_intr(port_t *port)
+{
+	u16 dmac = get_dmac_rx(port);
+	card_t *card = port_to_card(port);
+	u8 stat = sca_in(DSR_RX(phy_node(port)), card); /* read DMA Status */
+	struct net_device_stats *stats = &port->hdlc.stats;
+
+	/* Reset DSR status bits */
+	sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
+		DSR_RX(phy_node(port)), card);
+
+	if (stat & DSR_BOF)
+		stats->rx_over_errors++; /* Dropped one or more frames */
+
+	while (1) {
+		u32 desc_off = desc_offset(port, port->rxin, 0);
+		pkt_desc *desc;
+		u32 cda = sca_ina(dmac + CDAL, card);
+
+		if (cda == desc_off)
+			break;	/* No frame received */
+
+#ifdef __HD64572_H
+		if (cda == desc_off + 8)
+			break;	/* SCA-II updates CDA in 2 steps */
+#endif
+
+		desc = desc_address(port, port->rxin, 0);
+		stat = readb(&desc->stat);
+		if (!(stat & ST_RX_EOM))
+			port->rxpart = 1; /* partial frame received */
+		else if ((stat & ST_ERROR_MASK) || port->rxpart) {
+			stats->rx_errors++;
+			if (stat & ST_RX_OVERRUN) stats->rx_fifo_errors++;
+			else if ((stat & (ST_RX_SHORT | ST_RX_ABORT |
+					  ST_RX_RESBIT)) || port->rxpart)
+				stats->rx_frame_errors++;
+			else if (stat & ST_RX_CRC) stats->rx_crc_errors++;
+			if (stat & ST_RX_EOM)
+				port->rxpart = 0; /* received last fragment */
+		} else
+			sca_rx(card, port, desc, port->rxin);
+
+		/* Set new error descriptor address */
+		sca_outa(desc_off, dmac + EDAL, card);
+		port->rxin = next_desc(port, port->rxin);
+	}
+
+	/* make sure RX DMA is enabled */
+	sca_out(DSR_DE, DSR_RX(phy_node(port)), card);
+}
+
+
+
+/* Transmit DMA interrupt service */
+static inline void sca_tx_intr(port_t *port)
+{
+	u16 dmac = get_dmac_tx(port);
+	card_t* card = port_to_card(port);
+	u8 stat;
+
+	spin_lock(&port->lock);
+
+	stat = sca_in(DSR_TX(phy_node(port)), card); /* read DMA Status */
+
+	/* Reset DSR status bits */
+	sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE,
+		DSR_TX(phy_node(port)), card);
+
+	while (1) {
+		u32 desc_off = desc_offset(port, port->txlast, 1);
+		pkt_desc *desc;
+		u16 len;
+
+		if (sca_ina(dmac + CDAL, card) == desc_off)
+			break;	/* Transmitter is/will_be sending this frame */
+
+		desc = desc_address(port, port->txlast, 1);
+		len = readw(&desc->len);
+
+		port->hdlc.stats.tx_packets++;
+		port->hdlc.stats.tx_bytes += len;
+		writeb(0, &desc->stat);	/* Free descriptor */
+
+		port->txlast = (port->txlast + 1) %
+			port_to_card(port)->ring_buffers;
+	}
+
+	netif_wake_queue(hdlc_to_dev(&port->hdlc));
+	spin_unlock(&port->lock);
+}
+
+
+
+static void sca_intr(int irq, void* dev_id, struct pt_regs *regs)
+{
+	card_t *card = dev_id;
+	int boguscnt = INTR_WORK;
+	int i;
+	u8 stat;
+
+#ifndef ALL_PAGES_ALWAYS_MAPPED
+	u8 page = sca_get_page(card);
+#endif
+
+	while((stat = sca_intr_status(card)) != 0) {
+		for (i = 0; i < 2; i++) {
+			port_t *port = get_port(card, i);
+			if (port) {
+				if (stat & SCA_INTR_MSCI(i))
+					sca_msci_intr(port);
+
+				if (stat & SCA_INTR_DMAC_RX(i))
+					sca_rx_intr(port);
+
+				if (stat & SCA_INTR_DMAC_TX(i))
+					sca_tx_intr(port);
+			}
+
+			if (--boguscnt < 0) {
+				printk(KERN_ERR "%s: too much work at "
+				       "interrupt\n",
+				       hdlc_to_name(&port->hdlc));
+				goto exit;
+			}
+		}
+	}
+
+ exit:
+#ifndef ALL_PAGES_ALWAYS_MAPPED
+	openwin(card, page);		/* Restore original page */
+#endif
+}
+
+
+
+static inline int sca_set_loopback(port_t *port, int line)
+{
+	card_t* card = port_to_card(port);
+	u8 msci = get_msci(port);
+	u8 md2 = sca_in(msci + MD2, card);
+
+	switch(line) {
+	case LINE_DEFAULT:
+		md2 &= ~MD2_LOOPBACK;
+		port->line &= ~LINE_LOOPBACK;
+		break;
+
+	case LINE_LOOPBACK:
+		md2 |= MD2_LOOPBACK;
+		port->line |= LINE_LOOPBACK;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	sca_out(md2, msci + MD2, card);
+	return 0;
+}
+
+
+
+static void sca_set_clock(port_t *port)
+{
+	card_t *card = port_to_card(port);
+	u8 msci = get_msci(port);
+	unsigned int tmc, br = 10, brv = 1024;
+
+	if (port->clkrate > 0) {
+		/* Try lower br for better accuracy*/
+		do {
+			br--;
+			brv >>= 1; /* brv = 2^9 = 512 max in specs */
+
+			/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
+			tmc = CLOCK_BASE / (brv * port->clkrate);
+		}while(br > 1 && tmc <= 128);
+
+		if (tmc < 1) {
+			tmc = 1;
+			br = 0;	/* For baud=CLOCK_BASE we use tmc=1 br=0 */
+			brv = 1;
+		} else if (tmc > 255)
+			tmc = 256; /* tmc=0 means 256 - low baud rates */
+
+		port->clkrate = CLOCK_BASE / (brv * tmc);
+	} else {
+		br = 9; /* Minimum clock rate */
+		tmc = 256;	/* 8bit = 0 */
+		port->clkrate = CLOCK_BASE / (256 * 512);
+	}
+
+	port->rxs = (port->rxs & ~CLK_BRG_MASK) | br;
+	port->txs = (port->txs & ~CLK_BRG_MASK) | br;
+	port->tmc = tmc;
+
+	/* baud divisor - time constant*/
+#ifdef __HD64570_H
+	sca_out(port->tmc, msci + TMC, card);
+#else
+	sca_out(port->tmc, msci + TMCR, card);
+	sca_out(port->tmc, msci + TMCT, card);
+#endif
+
+	/* Set BRG bits */
+	sca_out(port->rxs, msci + RXS, card);
+	sca_out(port->txs, msci + TXS, card);
+}
+
+
+
+static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi)
+{
+	card_t* card = port_to_card(port);
+	u8 msci = get_msci(port);
+	u8 md2 = (nrzi ? MD2_NRZI : 0) |
+		((port->line & LINE_LOOPBACK) ? MD2_LOOPBACK : 0);
+	u8 ctl = (idle ? CTL_IDLE : 0);
+#ifdef __HD64572_H
+	ctl |= CTL_URCT | CTL_URSKP; /* Skip the rest of underrun frame */
+#endif
+
+	sca_out(CMD_RESET, msci + CMD, card);
+	sca_out(MD0_HDLC | crc, msci + MD0, card);
+	sca_out(0x00, msci + MD1, card); /* no address field check */
+	sca_out(md2, msci + MD2, card);
+	sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
+	sca_out(ctl, msci + CTL, card);
+
+#ifdef __HD64570_H
+	/* Allow at least 8 bytes before requesting RX DMA operation */
+	/* TX with higher priority and possibly with shorter transfers */
+	sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/
+	sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/
+	sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
+#else
+	sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
+	/* Setting than to larger value may cause Illegal Access */
+	sca_out(0x20, msci + TNR0, card); /* =TX DMA activation condition */
+	sca_out(0x30, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
+	sca_out(0x04, msci + TCR, card); /* =Critical TX DMA activ condition */
+#endif
+
+
+#ifdef __HD64570_H
+	/* MSCI TX INT IRQ enable */
+	sca_out(IE0_TXINT, msci + IE0, card);
+	sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun IRQ */
+	sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08),
+		IER0, card);
+	/* DMA IRQ enable */
+	sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
+		IER1, card);
+#else
+	/* MSCI TX INT and underrrun IRQ enable */
+	sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card);
+	/* DMA & MSCI IRQ enable */
+	sca_outl(sca_in(IER0, card) |
+		 (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card);
+#endif
+
+#ifdef __HD64570_H
+	sca_out(port->tmc, msci + TMC, card); /* Restore registers */
+#else
+	sca_out(port->tmc, msci + TMCR, card);
+	sca_out(port->tmc, msci + TMCT, card);
+#endif
+	sca_out(port->rxs, msci + RXS, card);
+	sca_out(port->txs, msci + TXS, card);
+	sca_out(CMD_TX_ENABLE, msci + CMD, card);
+	sca_out(CMD_RX_ENABLE, msci + CMD, card);
+}
+
+
+
+#ifdef DEBUG_RINGS
+static void sca_dump_rings(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+	card_t *card = port_to_card(port);
+	u16 cnt;
+#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+	u8 page;
+#endif
+
+#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+	page = sca_get_page(card);
+	openwin(card, 0);
+#endif
+
+	printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u "
+	       "%sactive",
+	       sca_ina(get_dmac_rx(port) + CDAL, card),
+	       sca_ina(get_dmac_rx(port) + EDAL, card),
+	       sca_in(DSR_RX(phy_node(port)), card),
+	       port->rxin,
+	       sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in");
+	for (cnt = 0; cnt<port_to_card(port)->ring_buffers; cnt++)
+		printk(" %02X",
+		       readb(&(desc_address(port, cnt, 0)->stat)));
+
+	printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
+	       "last=%u %sactive",
+	       sca_ina(get_dmac_tx(port) + CDAL, card),
+	       sca_ina(get_dmac_tx(port) + EDAL, card),
+	       sca_in(DSR_TX(phy_node(port)), card), port->txin,
+	       port->txlast,
+	       sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in");
+
+	for (cnt = 0; cnt<port_to_card(port)->ring_buffers; cnt++)
+		printk(" %02X",
+		       readb(&(desc_address(port, cnt, 1)->stat)));
+	printk("\n");
+
+	printk(KERN_ERR "MSCI: MD: %02x %02x %02x, "
+	       "ST: %02x %02x %02x %02x"
+#ifdef __HD64572_H
+	       " %02x"
+#endif
+	       ", FST: %02x CST: %02x %02x\n",
+	       sca_in(get_msci(port) + MD0, card),
+	       sca_in(get_msci(port) + MD1, card),
+	       sca_in(get_msci(port) + MD2, card),
+	       sca_in(get_msci(port) + ST0, card),
+	       sca_in(get_msci(port) + ST1, card),
+	       sca_in(get_msci(port) + ST2, card),
+	       sca_in(get_msci(port) + ST3, card),
+#ifdef __HD64572_H
+	       sca_in(get_msci(port) + ST4, card),
+#endif
+	       sca_in(get_msci(port) + FST, card),
+	       sca_in(get_msci(port) + CST0, card),
+	       sca_in(get_msci(port) + CST1, card));
+
+#ifdef __HD64572_H
+	printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card));
+#endif
+
+#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+	openwin(card, page); /* Restore original page */
+#endif
+}
+#endif /* DEBUG_RINGS */
+
+
+
+static void sca_open(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+
+	sca_set_hdlc_mode(port, 1, MD0_CRC_ITU, 0);
+	netif_start_queue(hdlc_to_dev(hdlc));
+}
+
+
+static void sca_close(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+
+	/* reset channel */
+	netif_stop_queue(hdlc_to_dev(hdlc));
+	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
+}
+
+
+
+static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	port_t *port = hdlc_to_port(hdlc);
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	card_t *card = port_to_card(port);
+	pkt_desc *desc;
+	u32 buff, len;
+#ifndef ALL_PAGES_ALWAYS_MAPPED
+	u8 page;
+	u32 maxlen;
+#endif
+
+	spin_lock_irq(&port->lock);
+
+	desc = desc_address(port, port->txin + 1, 1);
+	if (readb(&desc->stat)) { /* allow 1 packet gap */
+		/* should never happen - previous xmit should stop queue */
+#ifdef DEBUG_PKT
+		printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
+#endif
+		netif_stop_queue(dev);
+		spin_unlock_irq(&port->lock);
+		return 1;	/* request packet to be queued */
+	}
+
+#ifdef DEBUG_PKT
+	printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len);
+	debug_frame(skb);
+#endif
+
+	desc = desc_address(port, port->txin, 1);
+	buff = buffer_offset(port, port->txin, 1);
+	len = skb->len;
+#ifndef ALL_PAGES_ALWAYS_MAPPED
+	page = buff / winsize(card);
+	buff = buff % winsize(card);
+	maxlen = winsize(card) - buff;
+
+	openwin(card, page);
+	if (len > maxlen) {
+		memcpy_toio(winbase(card) + buff, skb->data, maxlen);
+		openwin(card, page + 1);
+		memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen);
+	}
+	else
+#endif
+		memcpy_toio(winbase(card) + buff, skb->data, len);
+
+#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
+	openwin(card, 0);	/* select pkt_desc table page back */
+#endif
+	writew(len, &desc->len);
+	writeb(ST_TX_EOM, &desc->stat);
+	dev->trans_start = jiffies;
+
+	port->txin = next_desc(port, port->txin);
+	sca_outa(desc_offset(port, port->txin, 1),
+		 get_dmac_tx(port) + EDAL, card);
+
+	sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */
+
+	desc = desc_address(port, port->txin + 1, 1);
+	if (readb(&desc->stat)) /* allow 1 packet gap */
+		netif_stop_queue(hdlc_to_dev(&port->hdlc));
+
+	spin_unlock_irq(&port->lock);
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
+static void sca_init(card_t *card, int wait_states)
+{
+	sca_out(wait_states, WCRL, card); /* Wait Control */
+	sca_out(wait_states, WCRM, card);
+	sca_out(wait_states, WCRH, card);
+
+	sca_out(0, DMER, card);	/* DMA Master disable */
+	sca_out(0x03, PCR, card); /* DMA priority */
+	sca_out(0, IER1, card);	/* DMA interrupt disable */
+	sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */
+	sca_out(0, DSR_TX(0), card);
+	sca_out(0, DSR_RX(1), card);
+	sca_out(0, DSR_TX(1), card);
+	sca_out(DMER_DME, DMER, card); /* DMA Master enable */
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hdlc.c linux/drivers/net/wan/hdlc.c
--- v2.4.2/linux/drivers/net/wan/hdlc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/hdlc.c	Tue Mar  6 19:44:36 2001
@@ -0,0 +1,1454 @@
+/*
+ * Generic HDLC support routines for Linux
+ *
+ * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * Current status:
+ *    - this is work in progress
+ *    - not heavily tested on SMP
+ *    - currently supported:
+ *	* raw IP-in-HDLC
+ *	* Cisco HDLC
+ *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
+ *	* PPP (using syncppp.c)
+ *	* X.25
+ *
+ * Use sethdlc utility to set line parameters, protocol and PVCs
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+/* #define DEBUG_PKT */
+/* #define DEBUG_HARD_HEADER */
+/* #define DEBUG_FECN */
+/* #define DEBUG_BECN */
+
+static const char* version = "HDLC support module revision 1.02 for Linux 2.4";
+
+
+#define CISCO_MULTICAST		0x8F	/* Cisco multicast address */
+#define CISCO_UNICAST		0x0F	/* Cisco unicast address */
+#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
+#define CISCO_SYS_INFO		0x2000	/* Cisco interface/system info */
+#define CISCO_ADDR_REQ		0	/* Cisco address request */
+#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
+
+static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+/********************************************************
+ *
+ * Cisco HDLC support
+ *
+ *******************************************************/
+
+static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
+			     u16 type, void *daddr, void *saddr,
+			     unsigned int len)
+{
+	hdlc_header *data;
+#ifdef DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
+#endif
+
+	skb_push(skb, sizeof(hdlc_header));
+	data = (hdlc_header*)skb->data;
+	if (type == CISCO_KEEPALIVE)
+		data->address = CISCO_MULTICAST;
+	else
+		data->address = CISCO_UNICAST;
+	data->control = 0;
+	data->protocol = htons(type);
+
+	return sizeof(hdlc_header);
+}
+
+
+
+static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
+				 u32 par1, u32 par2)
+{
+	struct sk_buff *skb;
+	cisco_packet *data;
+
+	skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet));
+	if (!skb) {
+		printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n",
+			       hdlc_to_name(hdlc));
+		return;
+	}
+	skb_reserve(skb, 4);
+	cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
+			  NULL, NULL, 0);
+	data = (cisco_packet*)skb->tail;
+
+	data->type = htonl(type);
+	data->par1 = htonl(par1);
+	data->par2 = htonl(par2);
+	data->rel = 0xFFFF;
+	data->time = htonl(jiffies * 1000 / HZ);
+
+	skb_put(skb, sizeof(cisco_packet));
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = hdlc_to_dev(hdlc);
+
+	dev_queue_xmit(skb);
+}
+
+
+
+static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	hdlc_header *data = (hdlc_header*)skb->data;
+	cisco_packet *cisco_data;
+	struct in_device *in_dev;
+	u32 addr, mask;
+
+	if (skb->len<sizeof(hdlc_header))
+		goto rx_error;
+
+	if (data->address != CISCO_MULTICAST &&
+	    data->address != CISCO_UNICAST)
+		goto rx_error;
+
+	skb_pull(skb, sizeof(hdlc_header));
+
+	switch(ntohs(data->protocol)) {
+	case ETH_P_IP:
+	case ETH_P_IPX:
+	case ETH_P_IPV6:
+		skb->protocol = data->protocol;
+		skb->dev = hdlc_to_dev(hdlc);
+		netif_rx(skb);
+		return;
+
+	case CISCO_SYS_INFO:
+		/* Packet is not needed, drop it. */
+		dev_kfree_skb_any(skb);
+		return;
+
+	case CISCO_KEEPALIVE:
+		if (skb->len != CISCO_PACKET_LEN &&
+		    skb->len != CISCO_BIG_PACKET_LEN) {
+			printk(KERN_INFO "%s: Invalid length of Cisco "
+			       "control packet (%d bytes)\n",
+			       hdlc_to_name(hdlc), skb->len);
+			goto rx_error;
+		}
+
+		cisco_data = (cisco_packet*)skb->data;
+
+		switch(ntohl (cisco_data->type)) {
+		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
+			in_dev = hdlc_to_dev(hdlc)->ip_ptr;
+			addr = 0;
+			mask = ~0; /* is the mask correct? */
+
+			if (in_dev != NULL) {
+				struct in_ifaddr **ifap = &in_dev->ifa_list;
+
+				while (*ifap != NULL) {
+					if (strcmp(hdlc_to_name(hdlc),
+						   (*ifap)->ifa_label) == 0) {
+						addr = (*ifap)->ifa_local;
+						mask = (*ifap)->ifa_mask;
+						break;
+					}
+					ifap = &(*ifap)->ifa_next;
+				}
+
+				cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
+						     addr, mask);
+			}
+			dev_kfree_skb_any(skb);
+			return;
+
+		case CISCO_ADDR_REPLY:
+			printk(KERN_INFO "%s: Unexpected Cisco IP address "
+			       "reply\n", hdlc_to_name(hdlc));
+			goto rx_error;
+
+		case CISCO_KEEPALIVE_REQ:
+			hdlc->lmi.rxseq = ntohl(cisco_data->par1);
+			if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) {
+				hdlc->lmi.last_poll = jiffies;
+				if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) {
+					u32 sec, min, hrs, days;
+					sec = ntohl(cisco_data->time) / 1000;
+					min = sec / 60; sec -= min * 60;
+					hrs = min / 60; min -= hrs * 60;
+					days = hrs / 24; hrs -= days * 24;
+					printk(KERN_INFO "%s: Link up (peer "
+					       "uptime %ud%uh%um%us)\n",
+					       hdlc_to_name(hdlc), days, hrs,
+					       min, sec);
+				}
+				hdlc->lmi.state |= LINK_STATE_RELIABLE;
+			}
+
+			dev_kfree_skb_any(skb);
+			return;
+		} /* switch(keepalive type) */
+	} /* switch(protocol) */
+
+	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
+	       data->protocol);
+	dev_kfree_skb_any(skb);
+	return;
+
+ rx_error:
+	hdlc->stats.rx_errors++; /* Mark error */
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static void cisco_timer(unsigned long arg)
+{
+	hdlc_device *hdlc = (hdlc_device*)arg;
+
+	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
+	    (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) {
+		hdlc->lmi.state &= ~LINK_STATE_RELIABLE;
+		printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
+	}
+
+	cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq,
+			     hdlc->lmi.rxseq);
+	hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
+
+	hdlc->timer.function = cisco_timer;
+	hdlc->timer.data = arg;
+	add_timer(&hdlc->timer);
+}
+
+
+
+/******************************************************************
+ *
+ *     generic Frame Relay routines
+ *
+ *****************************************************************/
+
+
+static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
+			  u16 type, void *daddr, void *saddr, unsigned int len)
+{
+	u16 head_len;
+
+	if (!daddr)
+		daddr = dev->broadcast;
+
+#ifdef DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
+#endif
+
+	switch(type) {
+	case ETH_P_IP:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IP;
+		break;
+
+	case ETH_P_IPV6:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IPV6;
+		break;
+
+	case LMI_PROTO:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = LMI_PROTO;
+		break;
+
+	default:
+		head_len = 10;
+		skb_push(skb, head_len);
+		skb->data[3] = FR_PAD;
+		skb->data[4] = NLPID_SNAP;
+		skb->data[5] = FR_PAD;
+		skb->data[6] = FR_PAD;
+		skb->data[7] = FR_PAD;
+		skb->data[8] = type>>8;
+		skb->data[9] = (u8)type;
+	}
+
+	memcpy(skb->data, daddr, 2);
+	skb->data[2] = FR_UI;
+
+	return head_len;
+}
+
+
+
+static inline void fr_log_dlci_active(pvc_device *pvc)
+{
+	printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
+	       pvc->state & PVC_STATE_ACTIVE ? "" : "in",
+	       pvc->state & PVC_STATE_NEW ? " new" : "");
+}
+
+
+
+static inline u8 fr_lmi_nextseq(u8 x)
+{
+	x++;
+	return x ? x : 1;
+}
+
+
+
+static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
+{
+	struct sk_buff *skb;
+	pvc_device *pvc = hdlc->first_pvc;
+	int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH;
+	int stat_len = 3;
+	u8 *data;
+	int i = 0;
+
+	if (mode_is(hdlc, MODE_DCE) && fullrep) {
+		len += hdlc->pvc_count * (2 + stat_len);
+		if (len > HDLC_MAX_MTU) {
+			printk(KERN_WARNING "%s: Too many PVCs while sending "
+			       "LMI full report\n", hdlc_to_name(hdlc));
+			return;
+		}
+	}
+
+	skb = dev_alloc_skb(len);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
+			       hdlc_to_name(hdlc));
+		return;
+	}
+	memset(skb->data, 0, len);
+	skb_reserve(skb, 4);
+	fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
+	data = skb->tail;
+	data[i++] = LMI_CALLREF;
+	data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY;
+	if (mode_is(hdlc, MODE_FR_ANSI))
+		data[i++] = LMI_ANSI_LOCKSHIFT;
+	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE :
+		LMI_REPTYPE;
+	data[i++] = LMI_REPT_LEN;
+	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
+
+	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE;
+	data[i++] = LMI_INTEG_LEN;
+	data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq);
+	data[i++] = hdlc->lmi.rxseq;
+
+	if (mode_is(hdlc, MODE_DCE) && fullrep) {
+		while (pvc) {
+			data[i++] = mode_is(hdlc, MODE_FR_CCITT) ?
+				LMI_CCITT_PVCSTAT:LMI_PVCSTAT;
+			data[i++] = stat_len;
+
+			if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
+			    (pvc->netdev.flags & IFF_UP) &&
+			    !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) {
+				pvc->state |= PVC_STATE_NEW;
+				fr_log_dlci_active(pvc);
+			}
+
+			dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
+				       data+i, pvc->state);
+			i += stat_len;
+			pvc = pvc->next;
+		}
+	}
+
+	skb_put(skb, i);
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = hdlc_to_dev(hdlc);
+
+	dev_queue_xmit(skb);
+}
+
+
+
+static void fr_timer(unsigned long arg)
+{
+	hdlc_device *hdlc = (hdlc_device*)arg;
+	int i, cnt = 0, reliable;
+	u32 list;
+
+	if (mode_is(hdlc, MODE_DCE))
+		reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ);
+	else {
+		hdlc->lmi.last_errors <<= 1; /* Shift the list */
+		if (hdlc->lmi.state & LINK_STATE_REQUEST) {
+			printk(KERN_INFO "%s: No LMI status reply received\n",
+			       hdlc_to_name(hdlc));
+			hdlc->lmi.last_errors |= 1;
+		}
+
+		for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393;
+		     i++, list >>= 1)
+			cnt += (list & 1);	/* errors count */
+
+		reliable = (cnt < hdlc->lmi.N392);
+	}
+
+	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) !=
+	    (reliable ? LINK_STATE_RELIABLE : 0)) {
+		pvc_device *pvc = hdlc->first_pvc;
+
+		while (pvc) {/* Deactivate all PVCs */
+			pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE);
+			pvc = pvc->next;
+		}
+
+		hdlc->lmi.state ^= LINK_STATE_RELIABLE;
+		printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
+		       reliable ? "" : "un");
+
+		if (reliable) {
+			hdlc->lmi.N391cnt = 0; /* Request full status */
+			hdlc->lmi.state |= LINK_STATE_CHANGED;
+		}
+	}
+
+	if (mode_is(hdlc, MODE_DCE))
+		hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ;
+	else {
+		if (hdlc->lmi.N391cnt)
+			hdlc->lmi.N391cnt--;
+
+		fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0);
+
+		hdlc->lmi.state |= LINK_STATE_REQUEST;
+		hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
+	}
+
+	hdlc->timer.function = fr_timer;
+	hdlc->timer.data = arg;
+	add_timer(&hdlc->timer);
+}
+
+
+
+static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	int stat_len;
+	pvc_device *pvc;
+	int reptype = -1, error;
+	u8 rxseq, txseq;
+	int i;
+
+	if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ?
+			LMI_ANSI_LENGTH : LMI_LENGTH)) {
+		printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
+		return 1;
+	}
+
+	if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ?
+			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
+		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
+		       hdlc_to_name(hdlc), skb->data[2],
+		       mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply");
+		return 1;
+	}
+
+	i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6;
+
+	if (skb->data[i] !=
+	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
+		printk(KERN_INFO "%s: Not a report type=%x\n",
+		       hdlc_to_name(hdlc), skb->data[i]);
+		return 1;
+	}
+	i++;
+
+	i++;				/* Skip length field */
+
+	reptype = skb->data[i++];
+
+	if (skb->data[i]!=
+	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
+		printk(KERN_INFO "%s: Unsupported status element=%x\n",
+		       hdlc_to_name(hdlc), skb->data[i]);
+		return 1;
+	}
+	i++;
+
+	i++;			/* Skip length field */
+
+	hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */
+	rxseq = skb->data[i++];	/* Should confirm our sequence */
+
+	txseq = hdlc->lmi.txseq;
+
+	if (mode_is(hdlc, MODE_DCE)) {
+		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
+			printk(KERN_INFO "%s: Unsupported report type=%x\n",
+			       hdlc_to_name(hdlc), reptype);
+			return 1;
+		}
+	}
+
+	error = 0;
+	if (!(hdlc->lmi.state & LINK_STATE_RELIABLE))
+		error = 1;
+
+	if (rxseq == 0 || rxseq != txseq) {
+		hdlc->lmi.N391cnt = 0; /* Ask for full report next time */
+		error = 1;
+	}
+
+	if (mode_is(hdlc, MODE_DCE)) {
+		if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) {
+/* Stop sending full report - the last one has been confirmed by DTE */
+			hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT;
+			pvc = hdlc->first_pvc;
+			while (pvc) {
+				if (pvc->state & PVC_STATE_NEW) {
+					pvc->state &= ~PVC_STATE_NEW;
+					pvc->state |= PVC_STATE_ACTIVE;
+					fr_log_dlci_active(pvc);
+
+/* Tell DTE that new PVC is now active */
+					hdlc->lmi.state |= LINK_STATE_CHANGED;
+				}
+				pvc = pvc->next;
+			}
+		}
+
+		if (hdlc->lmi.state & LINK_STATE_CHANGED) {
+			reptype = LMI_FULLREP;
+			hdlc->lmi.state |= LINK_STATE_FULLREP_SENT;
+			hdlc->lmi.state &= ~LINK_STATE_CHANGED;
+		}
+
+		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
+		return 0;
+	}
+
+	/* DTE */
+
+	if (reptype != LMI_FULLREP || error)
+		return 0;
+
+	stat_len = 3;
+	pvc = hdlc->first_pvc;
+
+	while (pvc) {
+		pvc->newstate = 0;
+		pvc = pvc->next;
+	}
+
+	while (skb->len >= i + 2 + stat_len) {
+		u16 dlci;
+		u8 state = 0;
+
+		if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ?
+				     LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
+			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
+			       hdlc_to_name(hdlc), skb->data[i]);
+			return 1;
+		}
+		i++;
+
+		if (skb->data[i] != stat_len) {
+			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
+			       hdlc_to_name(hdlc), skb->data[i]);
+			return 1;
+		}
+		i++;
+
+		dlci = status_to_dlci(hdlc, skb->data+i, &state);
+		pvc = find_pvc(hdlc, dlci);
+
+		if (pvc)
+			pvc->newstate = state;
+		else if (state == PVC_STATE_NEW)
+			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
+			       hdlc_to_name(hdlc), dlci);
+
+		i += stat_len;
+	}
+
+	pvc = hdlc->first_pvc;
+
+	while (pvc) {
+		if (pvc->newstate == PVC_STATE_NEW)
+			pvc->newstate = PVC_STATE_ACTIVE;
+
+		pvc->newstate |= (pvc->state &
+				  ~(PVC_STATE_NEW|PVC_STATE_ACTIVE));
+		if (pvc->state != pvc->newstate) {
+			pvc->state = pvc->newstate;
+			fr_log_dlci_active(pvc);
+		}
+		pvc = pvc->next;
+	}
+
+	/* Next full report after N391 polls */
+	hdlc->lmi.N391cnt = hdlc->lmi.N391;
+
+	return 0;
+}
+
+
+
+static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	fr_hdr *fh = (fr_hdr*)skb->data;
+	u8 *data = skb->data;
+	u16 dlci;
+	pvc_device *pvc;
+
+	if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
+		goto rx_error;
+
+	dlci = q922_to_dlci(skb->data);
+
+	if (dlci == LMI_DLCI) {
+		if (data[3] == LMI_PROTO) {
+			if (fr_lmi_recv(hdlc, skb))
+				goto rx_error;
+			else {
+				/* No request pending */
+				hdlc->lmi.state &= ~LINK_STATE_REQUEST;
+				hdlc->lmi.last_poll = jiffies;
+				dev_kfree_skb_any(skb);
+				return;
+			}
+		}
+
+		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
+		       hdlc_to_name(hdlc));
+		goto rx_error;
+	}
+
+	pvc = find_pvc(hdlc, dlci);
+	if (!pvc) {
+#ifdef DEBUG_PKT
+		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
+		       hdlc_to_name(hdlc), dlci);
+#endif
+		goto rx_error;
+	}
+
+	if ((pvc->netdev.flags & IFF_UP) == 0) {
+#ifdef DEBUG_PKT
+		printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
+		       hdlc_to_name(hdlc), dlci);
+#endif
+		goto rx_error;
+	}
+
+	pvc->stats.rx_packets++; /* PVC traffic */
+	pvc->stats.rx_bytes += skb->len;
+
+	if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) {
+#ifdef DEBUG_FECN
+		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
+		       fh->fecn ? "N" : "FF");
+#endif
+		pvc->state ^= PVC_STATE_FECN;
+	}
+
+	if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) {
+#ifdef DEBUG_FECN
+		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
+		       fh->becn ? "N" : "FF");
+#endif
+		pvc->state ^= PVC_STATE_BECN;
+	}
+
+	if (pvc->state & PVC_STATE_BECN)
+		pvc->stats.rx_compressed++;
+
+	if (data[3] == NLPID_IP) {
+		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+		skb->protocol = htons(ETH_P_IP);
+		skb->dev = &pvc->netdev;
+		netif_rx(skb);
+		return;
+	}
+
+
+	if (data[3] == NLPID_IPV6) {
+		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+		skb->protocol = htons(ETH_P_IPV6);
+		skb->dev = &pvc->netdev;
+		netif_rx(skb);
+		return;
+	}
+
+	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD &&
+	    data[6] == FR_PAD && data[7] == FR_PAD &&
+	    ((data[8]<<8) | data[9]) == ETH_P_ARP) {
+		skb_pull(skb, 10);
+		skb->protocol = htons(ETH_P_ARP);
+		skb->dev = &pvc->netdev;
+		netif_rx(skb);
+		return;
+	}
+
+	printk(KERN_INFO "%s: Unusupported protocol %x\n",
+	       hdlc_to_name(hdlc), data[3]);
+	dev_kfree_skb_any(skb);
+	return;
+
+ rx_error:
+	hdlc->stats.rx_errors++; /* Mark error */
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static void fr_cisco_open(hdlc_device *hdlc)
+{
+	hdlc->lmi.state = LINK_STATE_CHANGED;
+	hdlc->lmi.txseq = hdlc->lmi.rxseq = 0;
+	hdlc->lmi.last_errors = 0xFFFFFFFF;
+	hdlc->lmi.N391cnt = 0;
+
+	init_timer(&hdlc->timer);
+	hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */
+	hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer;
+	hdlc->timer.data = (unsigned long)hdlc;
+	add_timer(&hdlc->timer);
+}
+
+
+
+static void fr_cisco_close(hdlc_device *hdlc)
+{
+	pvc_device *pvc = hdlc->first_pvc;
+
+	del_timer_sync(&hdlc->timer);
+
+	while(pvc) {		/* NULL in Cisco mode */
+		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
+		pvc = pvc->next;
+	}
+}
+
+
+
+/******************************************************************
+ *
+ *     generic HDLC routines
+ *
+ *****************************************************************/
+
+
+
+static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+
+/********************************************************
+ *
+ * PVC device routines
+ *
+ *******************************************************/
+
+static int pvc_open(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	int result = 0;
+
+	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
+		return -EIO;  /* Master must be UP in order to activate PVC */
+
+	memset(&(pvc->stats), 0, sizeof(struct net_device_stats));
+	pvc->state = 0;
+
+	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc)
+		result = pvc->master->open_pvc(pvc);
+	if (result)
+		return result;
+
+	pvc->master->lmi.state |= LINK_STATE_CHANGED;
+	return 0;
+}
+
+
+
+static int pvc_close(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	pvc->state = 0;
+
+	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc)
+		pvc->master->close_pvc(pvc);
+
+	pvc->master->lmi.state |= LINK_STATE_CHANGED;
+	return 0;
+}
+
+
+
+static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+
+	if (pvc->state & PVC_STATE_ACTIVE) {
+		skb->dev = hdlc_to_dev(pvc->master);
+		pvc->stats.tx_bytes += skb->len;
+		pvc->stats.tx_packets++;
+		if (pvc->state & PVC_STATE_FECN)
+			pvc->stats.tx_compressed++; /* TX Congestion counter */
+		dev_queue_xmit(skb);
+	} else {
+		pvc->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+	}
+
+	return 0;
+}
+
+
+
+static struct net_device_stats *pvc_get_stats(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	return &pvc->stats;
+}
+
+
+
+static int pvc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+
+static void destroy_pvc_list(hdlc_device *hdlc)
+{
+	pvc_device *pvc = hdlc->first_pvc;
+	while(pvc) {
+		pvc_device *next = pvc->next;
+		unregister_netdevice(&pvc->netdev);
+		kfree(pvc);
+		pvc = next;
+	}
+
+	hdlc->first_pvc = NULL;	/* All PVCs destroyed */
+	hdlc->pvc_count = 0;
+	hdlc->lmi.state |= LINK_STATE_CHANGED;
+}
+
+
+
+/********************************************************
+ *
+ * X.25 protocol support routines
+ *
+ *******************************************************/
+
+#ifdef CONFIG_HDLC_X25
+/* These functions are callbacks called by LAPB layer */
+
+void x25_connect_disconnect(void *token, int reason, int code)
+{
+	hdlc_device *hdlc = token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
+		return;
+	}
+
+	ptr = skb_put(skb, 1);
+	*ptr = code;
+
+	skb->dev = hdlc_to_dev(hdlc);
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+void x25_connected(void *token, int reason)
+{
+	x25_connect_disconnect(token, reason, 1);
+}
+
+void x25_disconnected(void *token, int reason)
+{
+	x25_connect_disconnect(token, reason, 2);
+}
+
+
+int x25_data_indication(void *token, struct sk_buff *skb)
+{
+	hdlc_device *hdlc = token;
+	unsigned char *ptr;
+
+	ptr = skb_push(skb, 1);
+	*ptr = 0;
+
+	skb->dev = hdlc_to_dev(hdlc);
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	return netif_rx(skb);
+}
+
+
+void x25_data_transmit(void *token, struct sk_buff *skb)
+{
+	hdlc_device *hdlc = token;
+	hdlc->xmit(hdlc, skb);	/* Ignore return value :-( */
+}
+#endif /* CONFIG_HDLC_X25 */
+
+
+/********************************************************
+ *
+ * HDLC device routines
+ *
+ *******************************************************/
+
+static int hdlc_open(struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	int result;
+
+	if (hdlc->mode == MODE_NONE)
+		return -ENOSYS;
+
+	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
+
+	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
+	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
+		fr_cisco_open(hdlc);
+#ifdef CONFIG_HDLC_PPP
+	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
+		sppp_attach(&hdlc->pppdev);
+		/* sppp_attach nukes them. We don't need syncppp's ioctl */
+		dev->do_ioctl = hdlc_ioctl;
+		hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO;
+		dev->type = ARPHRD_PPP;
+		result = sppp_open(dev);
+		if (result) {
+			sppp_detach(dev);
+			return result;
+		}
+	}
+#endif
+#ifdef CONFIG_HDLC_X25
+	else if (mode_is(hdlc, MODE_X25)) {
+		struct lapb_register_struct cb;
+
+		cb.connect_confirmation = x25_connected;
+		cb.connect_indication = x25_connected;
+		cb.disconnect_confirmation = x25_disconnected;
+		cb.disconnect_indication = x25_disconnected;
+		cb.data_indication = x25_data_indication;
+		cb.data_transmit = x25_data_transmit;
+
+		result = lapb_register(hdlc, &cb);
+		if (result != LAPB_OK)
+			return result;
+	}
+#endif
+	result = hdlc->open(hdlc);
+	if (result) {
+		if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
+		    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
+			fr_cisco_close(hdlc);
+#ifdef CONFIG_HDLC_PPP
+		else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
+			sppp_close(dev);
+			sppp_detach(dev);
+			dev->rebuild_header = NULL;
+			dev->change_mtu = hdlc_change_mtu;
+			dev->mtu = HDLC_MAX_MTU;
+			dev->hard_header_len = 16;
+		}
+#endif
+#ifdef CONFIG_HDLC_X25
+		else if (mode_is(hdlc, MODE_X25))
+			lapb_unregister(hdlc);
+#endif
+	}
+
+	return result;
+}
+
+
+
+static int hdlc_close(struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+
+	hdlc->close(hdlc);
+
+	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
+	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
+		fr_cisco_close(hdlc);
+#ifdef CONFIG_HDLC_PPP
+	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
+		sppp_close(dev);
+		sppp_detach(dev);
+		dev->rebuild_header = NULL;
+		dev->change_mtu = hdlc_change_mtu;
+		dev->mtu = HDLC_MAX_MTU;
+		dev->hard_header_len = 16;
+	}
+#endif
+#ifdef CONFIG_HDLC_X25
+	else if (mode_is(hdlc, MODE_X25))
+		lapb_unregister(hdlc);
+#endif
+	return 0;
+}
+
+
+
+static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+
+#ifdef CONFIG_HDLC_X25
+	if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) {
+		int result;
+
+
+		/* X.25 to LAPB */
+		switch (skb->data[0]) {
+		case 0:		/* Data to be transmitted */
+			skb_pull(skb, 1);
+			if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
+				dev_kfree_skb(skb);
+			return 0;
+
+		case 1:
+			if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
+				if (result == LAPB_CONNECTED) {
+				/* Send connect confirm. msg to level 3 */
+					x25_connected(hdlc, 0);
+				} else {
+					printk(KERN_ERR "%s: LAPB connect "
+					       "request failed, error code = "
+					       "%i\n", hdlc_to_name(hdlc),
+					       result);
+				}
+			}
+			break;
+
+		case 2:
+			if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) {
+				if (result == LAPB_NOTCONNECTED) {
+				/* Send disconnect confirm. msg to level 3 */
+					x25_disconnected(hdlc, 0);
+				} else {
+					printk(KERN_ERR "%s: LAPB disconnect "
+					       "request failed, error code = "
+					       "%i\n", hdlc_to_name(hdlc),
+					       result);
+				}
+			}
+			break;
+
+		default:		/* to be defined */
+		}
+
+		dev_kfree_skb(skb);
+		return 0;
+	} /* MODE_X25 */
+#endif /* CONFIG_HDLC_X25 */
+
+	return hdlc->xmit(hdlc, skb);
+}
+
+
+
+void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb)
+{
+/* skb contains raw HDLC frame, in both hard- and software modes */
+	skb->mac.raw = skb->data;
+
+	switch(hdlc->mode & MODE_MASK) {
+	case MODE_HDLC:
+		skb->protocol = htons(ETH_P_IP);
+		skb->dev = hdlc_to_dev(hdlc);
+		netif_rx(skb);
+		return;
+
+	case MODE_FR:
+		fr_netif(hdlc, skb);
+		return;
+
+	case MODE_CISCO:
+		cisco_netif(hdlc, skb);
+		return;
+
+#ifdef CONFIG_HDLC_PPP
+	case MODE_PPP:
+#if 0
+		sppp_input(hdlc_to_dev(hdlc), skb);
+#else
+		skb->protocol = htons(ETH_P_WAN_PPP);
+		skb->dev = hdlc_to_dev(hdlc);
+		netif_rx(skb);
+#endif
+		return;
+#endif
+#ifdef CONFIG_HDLC_X25
+	case MODE_X25:
+		skb->dev = hdlc_to_dev(hdlc);
+		if (lapb_data_received(hdlc, skb) == LAPB_OK)
+			return;
+		break;
+#endif
+	}
+
+	hdlc->stats.rx_errors++;
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
+{
+	return &dev_to_hdlc(dev)->stats;
+}
+
+
+
+static int hdlc_set_mode(hdlc_device *hdlc, int mode)
+{
+	int result = -1;	/* Default to soft modes */
+	struct net_device *dev = hdlc_to_dev(hdlc);
+
+	if(!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if(dev->flags & IFF_UP)
+		return -EBUSY;
+
+	dev->addr_len = 0;
+	dev->hard_header = NULL;
+	hdlc->mode = MODE_NONE;
+
+	if (!(mode & MODE_SOFT))
+		switch(mode & MODE_MASK) {
+		case MODE_HDLC:
+			result = hdlc->set_mode ?
+				hdlc->set_mode(hdlc, MODE_HDLC) : 0;
+			break;
+
+		case MODE_CISCO: /* By card */
+#ifdef CONFIG_HDLC_PPP
+		case MODE_PPP:
+#endif
+#ifdef CONFIG_HDLC_X25
+		case MODE_X25:
+#endif
+		case MODE_FR:
+			result = hdlc->set_mode ?
+				hdlc->set_mode(hdlc, mode) : -ENOSYS;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+	if (result) {
+		mode |= MODE_SOFT; /* Try "host software" protocol */
+
+		switch(mode & MODE_MASK) {
+		case MODE_CISCO:
+			dev->hard_header = cisco_hard_header;
+			break;
+
+#ifdef CONFIG_HDLC_PPP
+		case MODE_PPP:
+			break;
+#endif
+#ifdef CONFIG_HDLC_X25
+		case MODE_X25:
+			break;
+#endif
+
+		case MODE_FR:
+			dev->hard_header = fr_hard_header;
+			dev->addr_len = 2;
+			*(u16*)dev->dev_addr = htons(LMI_DLCI);
+			dlci_to_q922(dev->broadcast, LMI_DLCI);
+			break;
+
+		default:
+			return -EINVAL;
+		}
+
+		result = hdlc->set_mode ?
+			hdlc->set_mode(hdlc, MODE_HDLC) : 0;
+	}
+
+	if (result)
+		return result;
+
+	hdlc->mode = mode;
+	switch(mode & MODE_MASK) {
+#ifdef CONFIG_HDLC_PPP
+	case MODE_PPP:   dev->type = ARPHRD_PPP;   break;
+#endif
+#ifdef CONFIG_HDLC_X25
+	case MODE_X25:   dev->type = ARPHRD_X25;   break;
+#endif
+	case MODE_FR:    dev->type = ARPHRD_FRAD;  break;
+	case MODE_CISCO: dev->type = ARPHRD_CISCO; break;
+	default:         dev->type = ARPHRD_RAWHDLC;
+	}
+
+	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
+	destroy_pvc_list(hdlc);
+	return 0;
+}
+
+
+
+static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci)
+{
+	pvc_device **pvc_p = &hdlc->first_pvc;
+	pvc_device *pvc;
+	int result, create = 1;	/* Create or delete PVC */
+
+	if(!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if(dlci<0) {
+		dlci = -dlci;
+		create = 0;
+	}
+
+	if(dlci <= 0 || dlci >= 1024)
+		return -EINVAL;	/* Only 10 bits for DLCI, DLCI=0 is reserved */
+
+	if(!mode_is(hdlc, MODE_FR))
+		return -EINVAL;	/* Only meaningfull on FR */
+
+	while(*pvc_p) {
+		if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
+			break;
+		pvc_p = &(*pvc_p)->next;
+	}
+
+	if (create) {		/* Create PVC */
+		if (*pvc_p != NULL)
+			return -EEXIST;
+
+		pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
+		if (!pvc) {
+			printk(KERN_WARNING "%s: Memory squeeze on "
+			       "hdlc_fr_pvc()\n", hdlc_to_name(hdlc));
+			return -ENOBUFS;
+		}
+		memset(pvc, 0, sizeof(pvc_device));
+
+		pvc->netdev.hard_start_xmit = pvc_xmit;
+		pvc->netdev.get_stats = pvc_get_stats;
+		pvc->netdev.open = pvc_open;
+		pvc->netdev.stop = pvc_close;
+		pvc->netdev.change_mtu = pvc_change_mtu;
+		pvc->netdev.mtu = HDLC_MAX_MTU;
+
+		pvc->netdev.type = ARPHRD_DLCI;
+		pvc->netdev.hard_header_len = 16;
+		pvc->netdev.hard_header = fr_hard_header;
+		pvc->netdev.tx_queue_len = 0;
+		pvc->netdev.flags = IFF_POINTOPOINT;
+
+		dev_init_buffers(&pvc->netdev);
+
+		pvc->master = hdlc;
+		*(u16*)pvc->netdev.dev_addr = htons(dlci);
+		dlci_to_q922(pvc->netdev.broadcast, dlci);
+		pvc->netdev.addr_len = 2;
+		pvc->netdev.irq = hdlc_to_dev(hdlc)->irq;
+
+		result = dev_alloc_name(&pvc->netdev, "pvc%d");
+		if (result < 0) {
+			kfree(pvc);
+			*pvc_p = NULL;
+			return result;
+		}
+
+		if (register_netdevice(&pvc->netdev) != 0) {
+			kfree(pvc);
+			*pvc_p = NULL;
+			return -EIO;
+		}
+
+		if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) {
+			result = hdlc->create_pvc(pvc);
+			if (result) {
+				unregister_netdevice(&pvc->netdev);
+				kfree(pvc);
+				*pvc_p = NULL;
+				return result;
+			}
+		}
+
+		hdlc->lmi.state |= LINK_STATE_CHANGED;
+		hdlc->pvc_count++;
+		return 0;
+	}
+
+	if (*pvc_p == NULL)		/* Delete PVC */
+		return -ENOENT;
+
+	pvc = *pvc_p;
+
+	if (pvc->netdev.flags & IFF_UP)
+		return -EBUSY;		/* PVC in use */
+
+	if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc)
+		hdlc->destroy_pvc(pvc);
+
+	hdlc->lmi.state |= LINK_STATE_CHANGED;
+	hdlc->pvc_count--;
+	*pvc_p = pvc->next;
+	unregister_netdevice(&pvc->netdev);
+	kfree(pvc);
+	return 0;
+}
+
+
+
+static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+
+	switch(cmd) {
+	case HDLCGMODE:
+		ifr->ifr_ifru.ifru_ivalue = hdlc->mode;
+		return 0;
+
+	case HDLCSMODE:
+		return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue);
+
+	case HDLCPVC:
+		return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue);
+
+	default:
+		if (hdlc->ioctl != NULL)
+			return hdlc->ioctl(hdlc, ifr, cmd);
+	}
+
+	return -EINVAL;
+}
+
+
+
+static int hdlc_init(struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+
+	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
+
+	dev->get_stats = hdlc_get_stats;
+	dev->open = hdlc_open;
+	dev->stop = hdlc_close;
+	dev->hard_start_xmit = hdlc_xmit;
+	dev->do_ioctl = hdlc_ioctl;
+	dev->change_mtu = hdlc_change_mtu;
+	dev->mtu = HDLC_MAX_MTU;
+
+	dev->type = ARPHRD_RAWHDLC;
+	dev->hard_header_len = 16;
+
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+	dev_init_buffers(dev);
+	return 0;
+}
+
+
+
+int register_hdlc_device(hdlc_device *hdlc)
+{
+	int result;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+
+	dev->init = hdlc_init;
+	dev->priv = &hdlc->syncppp_ptr;
+	hdlc->syncppp_ptr = &hdlc->pppdev;
+	hdlc->pppdev.dev = dev;
+	hdlc->mode = MODE_NONE;
+	hdlc->lmi.T391 = 10;	/* polling verification timer */
+	hdlc->lmi.T392 = 15;	/* link integrity verification polling timer */
+	hdlc->lmi.N391 = 6;	/* full status polling counter */
+	hdlc->lmi.N392 = 3;	/* error threshold */
+	hdlc->lmi.N393 = 4;	/* monitored events count */
+
+	result = dev_alloc_name(dev, "hdlc%d");
+	if (result<0)
+		return result;
+
+	result = register_netdev(dev);
+	if (result != 0)
+		return -EIO;
+
+	dev_init_buffers(dev);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+
+void unregister_hdlc_device(hdlc_device *hdlc)
+{
+	destroy_pvc_list(hdlc);
+	unregister_netdev(hdlc_to_dev(hdlc));
+	MOD_DEC_USE_COUNT;
+}
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("HDLC support module");
+
+EXPORT_SYMBOL(hdlc_netif_rx);
+EXPORT_SYMBOL(register_hdlc_device);
+EXPORT_SYMBOL(unregister_hdlc_device);
+
+static int __init hdlc_module_init(void)
+{
+	printk(KERN_INFO "%s\n", version);
+	return 0;
+}
+
+
+module_init(hdlc_module_init);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/hostess_sv11.c linux/drivers/net/wan/hostess_sv11.c
--- v2.4.2/linux/drivers/net/wan/hostess_sv11.c	Sun Aug 13 14:57:35 2000
+++ linux/drivers/net/wan/hostess_sv11.c	Tue Mar  6 19:44:36 2001
@@ -34,7 +34,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
-#include "syncppp.h"
+#include <net/syncppp.h>
 #include "z85230.h"
 
 static int dma;
@@ -59,7 +59,7 @@
 {
 	/* Drop the CRC - its not a good idea to try and negotiate it ;) */
 	skb_trim(skb, skb->len-2);
-	skb->protocol=htons(ETH_P_WAN_PPP);
+	skb->protocol=__constant_htons(ETH_P_WAN_PPP);
 	skb->mac.raw=skb->data;
 	skb->dev=c->netdevice;
 	/*
@@ -67,6 +67,7 @@
 	 *	it right now.
 	 */
 	netif_rx(skb);
+	c->netdevice->last_rx = jiffies;
 }
  
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c
--- v2.4.2/linux/drivers/net/wan/lmc/lmc_main.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/wan/lmc/lmc_main.c	Tue Mar  6 19:44:36 2001
@@ -67,7 +67,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include "../syncppp.h"
+#include <net/syncppp.h>
 #include <linux/inet.h>
 
 #if LINUX_VERSION_CODE >= 0x20200
@@ -77,15 +77,7 @@
 #define ARPHRD_HDLC 513
 #endif
 
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
 
 #define DRIVER_MAJOR_VERSION     1
 #define DRIVER_MINOR_VERSION    34
@@ -166,7 +158,7 @@
 
     /*
      * Most functions mess with the structure
-     * Disable interupts while we do the polling
+     * Disable interrupts while we do the polling
      */
     spin_lock_irqsave(&sc->lmc_lock, flags);
 
@@ -546,7 +538,7 @@
                     udelay(50);
 
                     /*
-                     * Clear reset and activate programing lines
+                     * Clear reset and activate programming lines
                      * Reset: Input
                      * DP:    Input
                      * Clock: Output
@@ -584,7 +576,7 @@
                             sc->lmc_gpio |= LMC_GEP_DATA; /* Data is 1 */
                             break;
                         default:
-                            printk(KERN_WARNING "%s Bad data in xilinx programing data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
+                            printk(KERN_WARNING "%s Bad data in xilinx programming data at %d, got %d wanted 0 or 1\n", dev->name, pos, data[pos]);
                             sc->lmc_gpio |= LMC_GEP_DATA; /* Assume it's 1 */
                         }
                         sc->lmc_gpio &= ~LMC_GEP_CLK; /* Clock to zero */
@@ -598,13 +590,13 @@
                         udelay(1);
                     }
                     if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_INIT) == 0){
-                        printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (corrupted data)\n", dev->name);
+                        printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (corrupted data)\n", dev->name);
                     }
                     else if((LMC_CSR_READ(sc, csr_gp) & LMC_GEP_DP) == 0){
-                        printk(KERN_WARNING "%s: Reprograming FAILED. Needs to be reprogramed. (done)\n", dev->name);
+                        printk(KERN_WARNING "%s: Reprogramming FAILED. Needs to be reprogrammed. (done)\n", dev->name);
                     }
                     else {
-                        printk(KERN_DEBUG "%s: Done reprograming Xilinx, %d bits, good luck!\n", dev->name, pos);
+                        printk(KERN_DEBUG "%s: Done reprogramming Xilinx, %d bits, good luck!\n", dev->name, pos);
                     }
 
                     lmc_gpio_mkinput(sc, 0xff);
@@ -662,12 +654,13 @@
 
     if(sc->check != 0xBEAFCAFE){
         printk("LMC: Corrupt net_device stuct, breaking out\n");
+	spin_unlock_irqrestore(&sc->lmc_lock, flags);
         return;
     }
 
 
     /* Make sure the tx jabber and rx watchdog are off,
-     * and the transmit and recieve processes are running.
+     * and the transmit and receive processes are running.
      */
 
     LMC_CSR_WRITE (sc, csr_15, 0x00000011);
@@ -793,7 +786,7 @@
     if(sc->failed_recv_alloc == 1){
         /*
          * We failed to alloc mem in the
-         * interupt halder, go through the rings
+         * interrupt handler, go through the rings
          * and rebuild them
          */
         sc->failed_recv_alloc = 0;
@@ -1356,7 +1349,7 @@
     /* Stop Tx and Rx on the chip */
     csr6 = LMC_CSR_READ (sc, csr_command);
     csr6 &= ~LMC_DEC_ST;		/* Turn off the Transmission bit */
-    csr6 &= ~LMC_DEC_SR;		/* Turn off the Recieve bit */
+    csr6 &= ~LMC_DEC_SR;		/* Turn off the Receive bit */
     LMC_CSR_WRITE (sc, csr_command, csr6);
 
     dev->flags &= ~IFF_RUNNING;
@@ -1425,7 +1418,7 @@
     spin_lock(&sc->lmc_lock);
 
     /*
-     * Read the csr to find what interupts we have (if any)
+     * Read the csr to find what interrupts we have (if any)
      */
     csr = LMC_CSR_READ (sc, csr_status);
 
@@ -1441,7 +1434,7 @@
     /* always go through this loop at least once */
     while (csr & sc->lmc_intrmask) {
         /*
-         * Clear interupt bits, we handle all case below
+         * Clear interrupt bits, we handle all case below
          */
         LMC_CSR_WRITE (sc, csr_status, csr);
 
@@ -1464,7 +1457,7 @@
         }
         
         if (csr & TULIP_STS_RXINTR){
-            lmc_trace(dev, "rx interupt");
+            lmc_trace(dev, "rx interrupt");
             lmc_rx (dev);
             
         }
@@ -1588,7 +1581,7 @@
         
         /*
          * Get current csr status to make sure
-         * we've cleared all interupts
+         * we've cleared all interrupts
          */
         csr = LMC_CSR_READ (sc, csr_status);
     }				/* end interrupt loop */
@@ -1599,8 +1592,6 @@
     spin_unlock(&sc->lmc_lock);
 
     lmc_trace(dev, "lmc_interrupt out");
-
-    return;
 }
 
 static int lmc_start_xmit (struct sk_buff *skb, struct net_device *dev) /*fold00*/
@@ -1879,12 +1870,12 @@
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
                 sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
-                /* Transfered to 21140 below */
+                /* Transferred to 21140 below */
             }
             else {
                 /*
                  * We've run out of memory, stop trying to allocate
-                 * memory and exit the interupt handler
+                 * memory and exit the interrupt handler
                  *
                  * The chip may run out of receivers and stop
                  * in which care we'll try to allocate the buffer
@@ -2129,7 +2120,7 @@
 
     lmc_trace(sc->lmc_device, "lmc_softreset in");
 
-    /* Initialize the recieve rings and buffers. */
+    /* Initialize the receive rings and buffers. */
     sc->lmc_txfull = 0;
     sc->lmc_next_rx = 0;
     sc->lmc_next_tx = 0;
@@ -2138,7 +2129,7 @@
 
     /*
      * Setup each one of the receiver buffers
-     * allocate an skbuff for each one, setup the the descriptor table
+     * allocate an skbuff for each one, setup the descriptor table
      * and point each buffer at the next one
      */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_media.c linux/drivers/net/wan/lmc/lmc_media.c
--- v2.4.2/linux/drivers/net/wan/lmc/lmc_media.c	Wed Feb 21 18:20:29 2001
+++ linux/drivers/net/wan/lmc/lmc_media.c	Tue Mar  6 19:44:36 2001
@@ -29,7 +29,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include "../syncppp.h"
+#include <net/syncppp.h>
 #include <linux/inet.h>
 
 #if LINUX_VERSION_CODE >= 0x20200
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_proto.c linux/drivers/net/wan/lmc/lmc_proto.c
--- v2.4.2/linux/drivers/net/wan/lmc/lmc_proto.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/lmc/lmc_proto.c	Tue Mar  6 19:44:36 2001
@@ -43,7 +43,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include "../syncppp.h"
+#include <net/syncppp.h>
 #include <linux/inet.h>
 #include <linux/tqueue.h>
 #include <linux/proc_fs.h>
@@ -61,7 +61,6 @@
  * compiled without referencing any of the sync ppp routines.
  */
 #ifdef SPPPSTUB
-#define SYNC_PPP_init() (void)0
 #define SPPP_detach(d)	(void)0
 #define SPPP_open(d)	0
 #define SPPP_reopen(d)	(void)0
@@ -70,7 +69,6 @@
 #define SPPP_do_ioctl(d,i,c)	-EOPNOTSUPP
 #else
 #if LINUX_VERSION_CODE < 0x20363
-#define SYNC_PPP_init	sync_ppp_init
 #define SPPP_attach(x)	sppp_attach((struct ppp_device *)(x)->lmc_device)
 #define SPPP_detach(x)	sppp_detach((x)->lmc_device)
 #define SPPP_open(x)	sppp_open((x)->lmc_device)
@@ -78,7 +76,6 @@
 #define SPPP_close(x)	sppp_close((x)->lmc_device)
 #define SPPP_do_ioctl(x, y, z)	sppp_do_ioctl((x)->lmc_device, (y), (z))
 #else
-#define SYNC_PPP_init	sync_ppp_init
 #define SPPP_attach(x)	sppp_attach((x)->pd)
 #define SPPP_detach(x)	sppp_detach((x)->pd->dev)
 #define SPPP_open(x)	sppp_open((x)->pd->dev)
@@ -88,21 +85,19 @@
 #endif
 #endif
 
-static int lmc_first_ppp_load = 0;
-
 // init
 void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/
 {
     lmc_trace(sc->lmc_device, "lmc_proto_init in");
     switch(sc->if_type){
     case LMC_PPP:
-        if(lmc_first_ppp_load == 0)
-#ifndef MODULE
-            SYNC_PPP_init();
-#endif
         
 #if LINUX_VERSION_CODE >= 0x20363
         sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
+	if (!sc->pd) {
+		printk("lmc_proto_init(): kmalloc failure!\n");
+		return;
+	}
         sc->pd->dev = sc->lmc_device;
 #endif
         sc->if_ptr = sc->pd;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/lmc/lmc_var.h linux/drivers/net/wan/lmc/lmc_var.h
--- v2.4.2/linux/drivers/net/wan/lmc/lmc_var.h	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/lmc/lmc_var.h	Tue Mar  6 19:44:36 2001
@@ -482,10 +482,10 @@
 
 #define TULIP_STS_NORMALINTR    0x00010000L /* (RW)  Normal Interrupt */
 #define TULIP_STS_ABNRMLINTR    0x00008000L /* (RW)  Abnormal Interrupt */
-#define TULIP_STS_ERI           0x00004000L /* (RW)  Early Receive Interupt */
+#define TULIP_STS_ERI           0x00004000L /* (RW)  Early Receive Interrupt */
 #define TULIP_STS_SYSERROR      0x00002000L /* (RW)  System Error */
 #define TULIP_STS_GTE           0x00000800L /* (RW)  General Pupose Timer Exp */
-#define TULIP_STS_ETI           0x00000400L /* (RW)  Early Transmit Interupt */
+#define TULIP_STS_ETI           0x00000400L /* (RW)  Early Transmit Interrupt */
 #define TULIP_STS_RXWT          0x00000200L /* (RW)  Receiver Watchdog Timeout */
 #define TULIP_STS_RXSTOPPED     0x00000100L /* (RW)  Receiver Process Stopped */
 #define TULIP_STS_RXNOBUF       0x00000080L /* (RW)  Receive Buf Unavail */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/n2.c linux/drivers/net/wan/n2.c
--- v2.4.2/linux/drivers/net/wan/n2.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wan/n2.c	Tue Mar  6 19:44:37 2001
@@ -0,0 +1,590 @@
+/*
+ * SDL Inc. RISCom/N2 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * For information see http://hq.pm.waw.pl/hdlc/
+ *
+ * Note: integrated CSU/DSU/DDS are not supported by this driver
+ *
+ * Sources of information:
+ *    Hitachi HD64570 SCA User's Manual
+ *    SDL Inc. PPP/HDLC/CISCO driver
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <asm/io.h>
+#include "hd64570.h"
+
+#define DEBUG_RINGS
+/* #define DEBUG_PKT */
+
+static const char* version = "SDL RISCom/N2 driver revision: 1.02 for Linux 2.4";
+static const char* devname = "RISCom/N2";
+
+#define USE_WINDOWSIZE 16384
+#define USE_BUS16BITS 1
+#define CLOCK_BASE 9830400	/* 9.8304 MHz */
+
+#define N2_IOPORTS 0x10
+
+static char *hw = NULL;	/* pointer to hw=xxx command line string */
+
+/* RISCom/N2 Board Registers */
+
+/* PC Control Register */
+#define N2_PCR 0
+#define PCR_RUNSCA 1     /* Run 64570 */
+#define PCR_VPM    2     /* Enable VPM - needed if using RAM above 1 MB */
+#define PCR_ENWIN  4     /* Open window */
+#define PCR_BUS16  8     /* 16-bit bus */
+
+
+/* Memory Base Address Register */
+#define N2_BAR 2
+
+
+/* Page Scan Register  */
+#define N2_PSR 4
+#define WIN16K       0x00
+#define WIN32K       0x20
+#define WIN64K       0x40
+#define PSR_WINBITS  0x60
+#define PSR_DMAEN    0x80
+#define PSR_PAGEBITS 0x0F
+
+
+/* Modem Control Reg */
+#define N2_MCR 6
+#define CLOCK_OUT_PORT1 0x80
+#define CLOCK_OUT_PORT0 0x40
+#define TX422_PORT1     0x20
+#define TX422_PORT0     0x10
+#define DSR_PORT1       0x08
+#define DSR_PORT0       0x04
+#define DTR_PORT1       0x02
+#define DTR_PORT0       0x01
+
+
+typedef struct port_s {
+	hdlc_device hdlc;	/* HDLC device struct - must be first */
+	struct card_s *card;
+	spinlock_t lock;	/* TX lock */
+	int clkmode;		/* clock mode */
+	int clkrate;		/* clock rate */
+	int line;		/* loopback only */
+	u8 rxs, txs, tmc;	/* SCA registers */
+	u8 valid;		/* port enabled */
+	u8 phy_node;		/* physical port # - 0 or 1 */
+	u8 log_node;		/* logical port # */
+	u8 rxin;		/* rx ring buffer 'in' pointer */
+	u8 txin;		/* tx ring buffer 'in' and 'last' pointers */
+	u8 txlast;
+	u8 rxpart;		/* partial frame received, next frame invalid*/
+}port_t;
+
+
+
+typedef struct card_s {
+	u8 *winbase;		/* ISA window base address */
+	u32 phy_winbase;	/* ISA physical base address */
+	u32 ram_size;		/* number of bytes */
+	u16 io;			/* IO Base address */
+	u16 buff_offset;	/* offset of first buffer of first channel */
+	u8 irq;			/* IRQ (3-15) */
+	u8 ring_buffers;	/* number of buffers in a ring */
+
+	port_t ports[2];
+	struct card_s *next_card;
+}card_t;
+
+
+
+#define sca_reg(reg, card) (0x8000 | (card)->io | \
+			    ((reg) & 0x0F) | (((reg) & 0xF0) << 6))
+#define sca_in(reg, card)		inb(sca_reg(reg, card))
+#define sca_out(value, reg, card)	outb(value, sca_reg(reg, card))
+#define sca_inw(reg, card)		inw(sca_reg(reg, card))
+#define sca_outw(value, reg, card)	outw(value, sca_reg(reg, card))
+
+#define port_to_card(port)		((port)->card)
+#define log_node(port)			((port)->log_node)
+#define phy_node(port)			((port)->phy_node)
+#define winsize(card)			(USE_WINDOWSIZE)
+#define winbase(card)      	     	((card)->winbase)
+#define get_port(card, port)		((card)->ports[port].valid ? \
+					 &(card)->ports[port] : NULL)
+
+
+
+static __inline__ u8 sca_get_page(card_t *card)
+{
+	return inb(card->io + N2_PSR) & PSR_PAGEBITS;
+}
+
+
+static __inline__ void openwin(card_t *card, u8 page)
+{
+	u8 psr = inb(card->io + N2_PSR);
+	outb((psr & ~PSR_PAGEBITS) | page, card->io + N2_PSR);
+}
+
+
+static __inline__ void close_windows(card_t *card)
+{
+	outb(inb(card->io + N2_PCR) & ~PCR_ENWIN, card->io + N2_PCR);
+}
+
+
+#include "hd6457x.c"
+
+
+
+static int n2_set_clock(port_t *port, int value)
+{
+	card_t *card = port->card;
+	int io = card->io;
+	u8 mcr = inb(io + N2_MCR);
+	u8 msci = get_msci(port);
+	u8 rxs = port->rxs & CLK_BRG_MASK;
+	u8 txs = port->txs & CLK_BRG_MASK;
+
+	switch(value) {
+	case CLOCK_EXT:
+		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_LINE_TX; /* TXC input */
+		break;
+
+	case CLOCK_INT:
+		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
+		rxs |= CLK_BRG_RX; /* BRG output */
+		txs |= CLK_RXCLK_TX; /* RX clock */
+		break;
+
+	case CLOCK_TXINT:
+		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_BRG_TX; /* BRG output */
+		break;
+
+	case CLOCK_TXFROMRX:
+		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_RXCLK_TX; /* RX clock */
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	outb(mcr, io + N2_MCR);
+	port->rxs = rxs;
+	port->txs = txs;
+	sca_out(rxs, msci + RXS, card);
+	sca_out(txs, msci + TXS, card);
+	port->clkmode = value;
+	return 0;
+}
+
+
+
+static int n2_open(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+	int io = port->card->io;
+	u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
+
+	MOD_INC_USE_COUNT;
+	mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */
+	outb(mcr, io + N2_MCR);
+  
+	outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
+	outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
+	sca_open(hdlc);
+	n2_set_clock(port, port->clkmode);
+	return 0;
+}
+
+
+
+static void n2_close(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+	int io = port->card->io;
+	u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
+
+	sca_close(hdlc);
+	mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
+	outb(mcr, io + N2_MCR);
+	MOD_DEC_USE_COUNT;
+}
+
+
+
+static int n2_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+{
+	int value = ifr->ifr_ifru.ifru_ivalue;
+	int result = 0;
+	port_t *port = hdlc_to_port(hdlc);
+
+	if(!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	switch(cmd) {
+	case HDLCSCLOCK:
+		result = n2_set_clock(port, value);
+	case HDLCGCLOCK:
+		value = port->clkmode;
+		break;
+
+	case HDLCSCLOCKRATE:
+		port->clkrate = value;
+		sca_set_clock(port);
+	case HDLCGCLOCKRATE:
+		value = port->clkrate;
+		break;
+
+	case HDLCSLINE:
+		result = sca_set_loopback(port, value);
+	case HDLCGLINE:
+		value = port->line;
+		break;
+
+#ifdef DEBUG_RINGS
+	case HDLCRUN:
+		sca_dump_rings(hdlc);
+		return 0;
+#endif /* DEBUG_RINGS */
+
+	default:
+		return -EINVAL;
+	}
+
+	ifr->ifr_ifru.ifru_ivalue = value;
+	return result;
+}
+
+
+
+static u8 n2_count_page(card_t *card)
+{
+	u8 page;
+	int i, bcount = USE_WINDOWSIZE, wcount = USE_WINDOWSIZE/2;
+	u16 *dp = (u16*)card->winbase;
+	u8 *bp = (u8*)card->winbase;
+	u8 psr = inb(card->io + N2_PSR) & PSR_WINBITS;
+
+
+	for (page = 0; page < 16; page++) {
+		outb(psr | page, card->io + N2_PSR); /* select a page */
+		writeb(page, dp);
+		if (readb(dp) != page)
+			break;	/* If can't read back, no good memory */
+
+		outb(psr, card->io + N2_PSR); /* goto page 0 */
+		if (readb(dp))
+			break;	/* If page 0 changed, then wrapped around */
+
+		outb(psr | page, card->io + N2_PSR); /* select page again */
+
+		/*  first do byte tests */
+		for (i = 0; i < bcount; i++)
+			writeb(i, bp + i);
+		for (i = 0; i < bcount; i++)
+			if (readb(bp + i) != (i & 0xff))
+				return 0;
+
+		for (i = 0; i < bcount; i++)
+			writeb(~i, bp + i);
+		for (i = 0; i < bcount; i++)
+			if (readb(bp + i) != (~i & 0xff))
+				return 0;
+
+		/* next do 16-bit tests */
+		for (i = 0; i < wcount; i++)
+			writew(0x55AA, dp + i);
+		for (i = 0; i < wcount; i++)
+			if (readw(dp + i) != 0x55AA)
+				return 0;
+
+		for (i = 0; i < wcount; i++)
+			writew(0xAA55, dp + i);
+		for (i = 0; i < wcount; i++)
+			if (readw(dp + i) != 0xAA55)
+				return 0;
+
+		for (i = 0; i < wcount; i++)
+			writew(page, dp + i);
+	}
+
+	return page;
+}
+
+
+
+static void n2_destroy_card(card_t *card)
+{
+	int cnt;
+
+	for (cnt = 0; cnt < 2; cnt++)
+		if (card->ports[cnt].card)
+			unregister_hdlc_device(&card->ports[cnt].hdlc);
+
+	if (card->irq)
+		free_irq(card->irq, card);
+
+	if (card->winbase) {
+		iounmap(card->winbase);
+		release_mem_region(card->phy_winbase, USE_WINDOWSIZE);
+	}
+
+	if (card->io)
+		release_region(card->io, N2_IOPORTS);
+	kfree(card);
+}
+
+
+
+static int n2_run(unsigned long io, unsigned long irq, unsigned long winbase,
+		  long valid0, long valid1)
+{
+	card_t *card;
+	u8 cnt, pcr;
+
+	if (io < 0x200 || io > 0x3FF || (io % N2_IOPORTS) != 0) {
+		printk(KERN_ERR "n2: invalid I/O port value\n");
+		return -ENODEV;
+	}
+
+	if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ {
+		printk(KERN_ERR "n2: invalid IRQ value\n");
+		return -ENODEV;
+	}
+    
+	if (winbase < 0xA0000 || winbase > 0xFFFFF || (winbase & 0xFFF) != 0) {
+		printk(KERN_ERR "n2: invalid RAM value\n");
+		return -ENODEV;
+	}
+
+	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	if (card == NULL) {
+		printk(KERN_ERR "n2: unable to allocate memory\n");
+		return -ENOBUFS;
+	}
+	memset(card, 0, sizeof(card_t));
+
+	if (!request_region(io, N2_IOPORTS, devname)) {
+		printk(KERN_ERR "n2: I/O port region in use\n");
+		n2_destroy_card(card);
+		return -EBUSY;
+	}
+	card->io = io;
+
+	if (request_irq(irq, &sca_intr, 0, devname, card)) {
+		printk(KERN_ERR "n2: could not allocate IRQ\n");
+		n2_destroy_card(card);
+		return(-EBUSY);
+	}
+	card->irq = irq;
+
+	if (!request_mem_region(winbase, USE_WINDOWSIZE, devname)) {
+		printk(KERN_ERR "n2: could not request RAM window\n");
+		n2_destroy_card(card);
+		return(-EBUSY);
+	}
+	card->phy_winbase = winbase;
+	card->winbase = ioremap(winbase, USE_WINDOWSIZE);
+
+	outb(0, io + N2_PCR);
+	outb(winbase >> 12, io + N2_BAR);
+
+	switch (USE_WINDOWSIZE) {
+	case 16384:
+		outb(WIN16K, io + N2_PSR);
+		break;
+
+	case 32768:
+		outb(WIN32K, io + N2_PSR);
+		break;
+
+	case 65536:
+		outb(WIN64K, io + N2_PSR);
+		break;
+
+	default:
+		printk(KERN_ERR "n2: invalid window size\n");
+		n2_destroy_card(card);
+		return -ENODEV;
+	}
+
+	pcr = PCR_ENWIN | PCR_VPM | (USE_BUS16BITS ? PCR_BUS16 : 0);
+	outb(pcr, io + N2_PCR);
+
+	cnt = n2_count_page(card);
+	if (!cnt) {
+		printk(KERN_ERR "n2: memory test failed.\n");
+		n2_destroy_card(card);
+		return -EIO;
+	}
+
+	card->ram_size = cnt * USE_WINDOWSIZE;
+
+	/* 4 rings required for 2 ports, 2 rings for one port */
+	card->ring_buffers = card->ram_size /
+		((valid0 + valid1) * 2 * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+
+	card->buff_offset = (valid0 + valid1) * 2 * (sizeof(pkt_desc))
+		* card->ring_buffers;
+
+	printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, "
+	       "using %u packets rings\n", card->ram_size / 1024, card->irq,
+	       card->ring_buffers);
+
+	pcr |= PCR_RUNSCA;		/* run SCA */
+	outb(pcr, io + N2_PCR);
+	outb(0, io + N2_MCR);
+
+	sca_init(card, 0);
+	for (cnt = 0; cnt < 2; cnt++) {
+		port_t *port = &card->ports[cnt];
+
+		if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1))
+			continue;
+
+		port->phy_node = cnt;
+		port->valid = 1;
+
+		if ((cnt == 1) && valid0)
+			port->log_node = 1;
+
+		spin_lock_init(&port->lock);
+		hdlc_to_dev(&port->hdlc)->irq = irq;
+		hdlc_to_dev(&port->hdlc)->mem_start = winbase;
+		hdlc_to_dev(&port->hdlc)->mem_end = winbase + USE_WINDOWSIZE-1;
+		hdlc_to_dev(&port->hdlc)->tx_queue_len = 50;
+		port->hdlc.ioctl = n2_ioctl;
+		port->hdlc.open = n2_open;
+		port->hdlc.close = n2_close;
+		port->hdlc.xmit = sca_xmit;
+
+		if (register_hdlc_device(&port->hdlc)) {
+			printk(KERN_WARNING "n2: unable to register hdlc "
+			       "device\n");
+			n2_destroy_card(card);
+			return -ENOBUFS;
+		}
+		port->card = card;
+		sca_init_sync_port(port); /* Set up SCA memory */
+
+		printk(KERN_INFO "%s: RISCom/N2 node %d\n",
+		       hdlc_to_name(&port->hdlc), port->phy_node);
+	}
+
+	*new_card = card;
+	new_card = &card->next_card;
+
+	return 0;
+}
+
+
+
+static int __init n2_init(void)
+{
+	if (hw==NULL) {
+#ifdef MODULE
+		printk(KERN_INFO "n2: no card initialized\n");
+#endif
+		return -ENOSYS;	/* no parameters specified, abort */
+	}
+
+	printk(KERN_INFO "%s\n", version);
+
+	do {
+		unsigned long io, irq, ram;
+		long valid[2] = { 0, 0 }; /* Default = both ports disabled */
+
+		io = simple_strtoul(hw, &hw, 0);
+
+		if (*hw++ != ',')
+			break;
+		irq = simple_strtoul(hw, &hw, 0);
+
+		if (*hw++ != ',')
+			break;
+		ram = simple_strtoul(hw, &hw, 0);
+
+		if (*hw++ != ',')
+			break;
+		while(1) {
+			if (*hw == '0' && !valid[0])
+				valid[0] = 1; /* Port 0 enabled */
+			else if (*hw == '1' && !valid[1])
+				valid[1] = 1; /* Port 1 enabled */
+			else
+				break;
+			hw++;
+		}
+      
+		if (!valid[0] && !valid[1])
+			break;	/* at least one port must be used */
+
+		if (*hw == ':' || *hw == '\x0')
+			n2_run(io, irq, ram, valid[0], valid[1]);
+
+		if (*hw == '\x0')
+			return 0;
+	}while(*hw++ == ':');
+
+	printk(KERN_ERR "n2: invalid hardware parameters\n");
+	return first_card ? 0 : -ENOSYS;
+}
+
+
+#ifndef MODULE
+static int __init n2_setup(char *str)
+{
+	hw = str;
+	return 1;
+}
+
+__setup("n2=", n2_setup);
+#endif
+
+
+static void __exit n2_cleanup(void)
+{
+	card_t *card = first_card;
+
+	while (card) {
+		card_t *ptr = card;
+		card = card->next_card;
+		n2_destroy_card(ptr);
+	}
+}
+
+
+module_init(n2_init);
+module_exit(n2_cleanup);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("RISCom/N2 serial port driver");
+MODULE_PARM(hw, "s");		/* hw=io,irq,ram,ports:io,irq,... */
+EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c
--- v2.4.2/linux/drivers/net/wan/sbni.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/sbni.c	Tue Mar 20 12:05:01 2001
@@ -283,7 +283,7 @@
 	struct net_device *dev = neigh->dev;
   
   
-	if (type == __constant_htons(ETH_P_802_3))
+	if (type == htons(ETH_P_802_3))
 		return -1;
   
 	sbni->h_proto = type;
@@ -742,7 +742,7 @@
 					 */
 					DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
 					/*
-					 *	We sucessfully sent current packet
+					 *	We successfully sent current packet
 					 */
 	      
 					if(lp->waitack)
@@ -1014,6 +1014,8 @@
 
 		skb_pull(skb,SBNI_HH_SZ);
    
+		skb->dev->last_rx = jiffies;
+		lp->stats.rx_bytes += skb->len;
 		netif_rx(skb);
 		lp->stats.rx_packets++;
 	}
@@ -1148,7 +1150,7 @@
 	lp->waitack=0;
 	netif_wake_queue(dev);
 	
-	DP( printk("%s: queue dropping stoped\n",dev->name); );	
+	DP( printk("%s: queue dropping stopped\n",dev->name); );	
 }
 
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- v2.4.2/linux/drivers/net/wan/sdla_chdlc.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/sdla_chdlc.c	Tue Mar  6 19:44:36 2001
@@ -932,7 +932,7 @@
 
     	if(test_and_set_bit(0, (void*)&card->wandev.critical)) {
 	
-		printk(KERN_INFO "%s: Critical in if_send: %x\n",
+		printk(KERN_INFO "%s: Critical in if_send: %lx\n",
 					card->wandev.name,card->wandev.critical);
                 ++card->wandev.stats.tx_dropped;
 #ifdef LINUX_2_1
@@ -1497,7 +1497,7 @@
 	 */
 	if(card->hw.type != SDLA_S514) {
 		if(test_and_set_bit(0, (void*)&card->wandev.critical)) {
-			printk(KERN_INFO "%s: Critical while in ISR: %x\n",
+			printk(KERN_INFO "%s: Critical while in ISR: %lx\n",
 				card->devname, card->wandev.critical);
 			card->in_isr = 0;
 			return;
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- v2.4.2/linux/drivers/net/wan/sdla_fr.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/sdla_fr.c	Tue Mar  6 19:44:36 2001
@@ -1654,7 +1654,7 @@
 			++card->statistics.isr_intr_test;
 	    		break;	
 
-                case FR_INTR_DLC: /* Event interrupt occured */
+                case FR_INTR_DLC: /* Event interrupt occurred */
 			mbox->cmd.command = FR_READ_STATUS;
 			mbox->cmd.length = 0;
 			err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
@@ -1691,7 +1691,7 @@
 /*============================================================================
  * Receive interrupt handler.
  * When a receive interrupt occurs do the following:
- *	1- Find the structure for the dlci that the interrupt occured on
+ *	1- Find the structure for the dlci that the interrupt occurred on
  *      2- If it doesn't exist then print appropriate msg and goto step 8. 
  * 	3- If it exist then copy data to a skb.
  * 	4- If skb contains Sangoma UDP data then process them
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- v2.4.2/linux/drivers/net/wan/sdla_ppp.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/sdla_ppp.c	Tue Mar  6 19:44:36 2001
@@ -897,7 +897,7 @@
 
     	if (test_and_set_bit(0, (void*)&card->wandev.critical)) {
 
-		printk(KERN_INFO "%s: Critical in if_send: %x\n",
+		printk(KERN_INFO "%s: Critical in if_send: %lx\n",
 				card->wandev.name,card->wandev.critical);
     		dev_kfree_skb(skb);
 
@@ -1686,8 +1686,6 @@
 				card->devname);
 			++card->wandev.stats.rx_dropped;
 			++ppp_priv_area->rx_intr_stat.rx_intr_no_socket;
-			
-               		dev_kfree_skb(skb);
 		}
 
 	} else {
@@ -2589,8 +2587,6 @@
     	}	
 
 	ppp_priv_area->udp_pkt_lgth = 0;
-	
-	return; 
 }
 
 /*=============================================================================
@@ -2753,7 +2749,7 @@
 			 card->devname, err);
 		return err;
 	}else
-		printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n",
+		printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfully\n",
 			card->devname, in_ntoa(ip_addr));
 
 	
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- v2.4.2/linux/drivers/net/wan/sdla_x25.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/sdla_x25.c	Tue Mar  6 19:44:36 2001
@@ -929,7 +929,7 @@
  *
  * Notes:
  * 1. When allocating a socket buffer, if M-bit is set then more data is
- *    comming and we have to allocate buffer for the maximum IP packet size
+ *    coming and we have to allocate buffer for the maximum IP packet size
  *    expected on this channel.
  * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no
  *    socket buffers available) the whole packet sequence must be discarded.
@@ -1001,7 +1001,7 @@
 	memcpy(bufptr, rxmb->data, len);
 
 	if (qdm & 0x01)
-		return;		/* more data is comming */
+		return;		/* more data is coming */
 
 	dev->last_rx = jiffies;		/* timestamp */
 	chan->rx_skb = NULL;		/* dequeue packet */
@@ -1153,7 +1153,7 @@
 	{
 		wanpipe_set_state(card, WAN_CONNECTED);
 		x25_set_intr_mode(card, 0x83);	/* enable Rx interrupts */
-		status->imask &= ~0x2;		/* mask Tx interupts */
+		status->imask &= ~0x2;		/* mask Tx interrupts */
 	}
 	else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT)
 	    disconnect(card);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
--- v2.4.2/linux/drivers/net/wan/sdladrv.c	Tue Jun 20 14:14:51 2000
+++ linux/drivers/net/wan/sdladrv.c	Tue Mar  6 19:44:37 2001
@@ -195,6 +195,12 @@
  * Note: All data must be explicitly initialized!!!
  */
 
+static struct pci_device_id sdladrv_pci_tbl[] __initdata = {
+	{ V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl);
+
 /* private data */
 static char modname[]	= "sdladrv";
 static char fullname[]	= "SDLA Support Module";
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c
--- v2.4.2/linux/drivers/net/wan/sdlamain.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wan/sdlamain.c	Tue Mar  6 19:44:36 2001
@@ -635,7 +635,7 @@
  * o verify user buffer
  * o copy adapter memory image to user buffer
  *
- * Note: when dumping memory, this routine switches curent dual-port memory
+ * Note: when dumping memory, this routine switches current dual-port memory
  *	 vector, so care must be taken to avoid racing conditions.
  */
 static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump)
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/sealevel.c linux/drivers/net/wan/sealevel.c
--- v2.4.2/linux/drivers/net/wan/sealevel.c	Sun Aug 13 14:57:35 2000
+++ linux/drivers/net/wan/sealevel.c	Tue Mar  6 19:44:37 2001
@@ -26,7 +26,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
-#include "syncppp.h"
+#include <net/syncppp.h>
 #include "z85230.h"
 
 
@@ -67,6 +67,7 @@
 	 *	it right now.
 	 */
 	netif_rx(skb);
+	c->netdevice->last_rx = jiffies;
 }
  
 /*
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c
--- v2.4.2/linux/drivers/net/wan/syncppp.c	Fri Aug 11 14:31:45 2000
+++ linux/drivers/net/wan/syncppp.c	Tue Mar  6 19:44:37 2001
@@ -42,6 +42,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <linux/route.h>
@@ -51,7 +52,7 @@
 #include <linux/pkt_sched.h>
 #include <asm/byteorder.h>
 #include <linux/spinlock.h>
-#include "syncppp.h"
+#include <net/syncppp.h>
 
 #define MAXALIVECNT     6               /* max. alive packets */
 
@@ -147,7 +148,6 @@
 
 static int debug = 0;
 
-MODULE_PARM(debug,"1i");
 
 /*
  *	Interface down stub
@@ -208,7 +208,7 @@
 	
 	skb->dev=dev;
 	skb->mac.raw=skb->data;
-	
+
 	if (dev->flags & IFF_RUNNING)
 	{
 		/* Count received bytes, add FCS and one flag */
@@ -1391,28 +1391,25 @@
 };
 
 
-void sync_ppp_init(void)
+
+static int __init sync_ppp_init(void)
 {
+	if(debug)
+		debug=PP_DEBUG;
 	printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
 	printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
 	spin_lock_init(&spppq_lock);
 	sppp_packet_type.type=htons(ETH_P_WAN_PPP);	
 	dev_add_pack(&sppp_packet_type);
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	if(debug)
-		debug=PP_DEBUG;
-	sync_ppp_init();
 	return 0;
 }
 
-void cleanup_module(void)
+
+static void __exit sync_ppp_cleanup(void)
 {
 	dev_remove_pack(&sppp_packet_type);
 }
 
-#endif
+module_init(sync_ppp_init);
+module_exit(sync_ppp_cleanup);
+MODULE_PARM(debug,"1i");
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/syncppp.h linux/drivers/net/wan/syncppp.h
--- v2.4.2/linux/drivers/net/wan/syncppp.h	Mon Mar 13 09:43:37 2000
+++ linux/drivers/net/wan/syncppp.h	Wed Dec 31 16:00:00 1969
@@ -1,99 +0,0 @@
-/*
- * Defines for synchronous PPP/Cisco link level subroutines.
- *
- * Copyright (C) 1994 Cronyx Ltd.
- * Author: Serge Vakulenko, <vak@zebub.msk.su>
- *
- * This software is distributed with NO WARRANTIES, not even the implied
- * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Authors grant any other persons or organizations permission to use
- * or modify this software as long as this message is kept with the software,
- * all derivative works or modified versions.
- *
- * Version 1.7, Wed Jun  7 22:12:02 MSD 1995
- *
- *
- *
- */
-
-#ifndef _SYNCPPP_H_
-#define _SYNCPPP_H_ 1
-
-#ifdef __KERNEL__
-struct slcp {
-	u16	state;          /* state machine */
-	u32	magic;          /* local magic number */
-	u_char	echoid;         /* id of last keepalive echo request */
-	u_char	confid;         /* id of last configuration request */
-};
-
-struct sipcp {
-	u16	state;          /* state machine */
-	u_char  confid;         /* id of last configuration request */
-};
-
-struct sppp 
-{
-	struct sppp *	pp_next;	/* next interface in keepalive list */
-	u32		pp_flags;	/* use Cisco protocol instead of PPP */
-	u16		pp_alivecnt;	/* keepalive packets counter */
-	u16		pp_loopcnt;	/* loopback detection counter */
-	u32		pp_seq;		/* local sequence number */
-	u32		pp_rseq;	/* remote sequence number */
-	struct slcp	lcp;		/* LCP params */
-	struct sipcp	ipcp;		/* IPCP params */
-	u32		ibytes,obytes;	/* Bytes in/out */
-	u32		ipkts,opkts;	/* Packets in/out */
-	struct timer_list	pp_timer;
-	struct net_device	*pp_if;
-	char		pp_link_state;	/* Link status */
-};
-
-struct ppp_device
-{	
-	struct net_device *dev;	/* Network device pointer */
-	struct sppp sppp;	/* Synchronous PPP */
-};
-
-#define sppp_of(dev)	\
-	    (&((struct ppp_device *)(*(unsigned long *)((dev)->priv)))->sppp)
-
-#define PP_KEEPALIVE    0x01    /* use keepalive protocol */
-#define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
-#define PP_TIMO         0x04    /* cp_timeout routine active */
-#define PP_DEBUG	0x08
-
-#define PPP_MTU          1500    /* max. transmit unit */
-
-#define LCP_STATE_CLOSED        0       /* LCP state: closed (conf-req sent) */
-#define LCP_STATE_ACK_RCVD      1       /* LCP state: conf-ack received */
-#define LCP_STATE_ACK_SENT      2       /* LCP state: conf-ack sent */
-#define LCP_STATE_OPENED        3       /* LCP state: opened */
-
-#define IPCP_STATE_CLOSED       0       /* IPCP state: closed (conf-req sent) */
-#define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
-#define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
-#define IPCP_STATE_OPENED       3       /* IPCP state: opened */
-
-#define SPPP_LINK_DOWN		0	/* link down - no keepalive */
-#define SPPP_LINK_UP		1	/* link is up - keepalive ok */
-
-void sppp_attach (struct ppp_device *pd);
-void sppp_detach (struct net_device *dev);
-void sppp_input (struct net_device *dev, struct sk_buff *m);
-int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
-struct sk_buff *sppp_dequeue (struct net_device *dev);
-int sppp_isempty (struct net_device *dev);
-void sppp_flush (struct net_device *dev);
-int sppp_open (struct net_device *dev);
-int sppp_reopen (struct net_device *dev);
-int sppp_close (struct net_device *dev);
-void sync_ppp_init (void);
-#endif
-
-#define SPPPIOCCISCO	(SIOCDEVPRIVATE)
-#define SPPPIOCPPP	(SIOCDEVPRIVATE+1)
-#define SPPPIOCDEBUG	(SIOCDEVPRIVATE+2)
-
-#endif /* _SYNCPPP_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c
--- v2.4.2/linux/drivers/net/wan/z85230.c	Wed Apr 12 09:47:26 2000
+++ linux/drivers/net/wan/z85230.c	Tue Mar  6 19:44:37 2001
@@ -42,14 +42,15 @@
 #include <linux/if_arp.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #define RT_LOCK
 #define RT_UNLOCK
 #include <linux/spinlock.h>
 
+#include <net/syncppp.h>
 #include "z85230.h"
-#include "syncppp.h"
 
 
 static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
@@ -70,7 +71,7 @@
  *	5uS delay rule.
  */
 
-extern __inline__ int z8530_read_port(unsigned long p)
+static inline int z8530_read_port(unsigned long p)
 {
 	u8 r=inb(Z8530_PORT_OF(p));
 	if(p&Z8530_PORT_SLEEP)	/* gcc should figure this out efficiently ! */
@@ -94,7 +95,7 @@
  */
 
 
-extern __inline__ void z8530_write_port(unsigned long p, u8 d)
+static inline void z8530_write_port(unsigned long p, u8 d)
 {
 	outb(d,Z8530_PORT_OF(p));
 	if(p&Z8530_PORT_SLEEP)
@@ -119,7 +120,7 @@
  *	operation.
  */
  
-extern inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
+static inline u8 read_zsreg(struct z8530_channel *c, u8 reg)
 {
 	u8 r;
 	unsigned long flags;
@@ -140,7 +141,7 @@
  *	have all the 5uS delays to worry about.
  */
 
-extern inline u8 read_zsdata(struct z8530_channel *c)
+static inline u8 read_zsdata(struct z8530_channel *c)
 {
 	u8 r;
 	r=z8530_read_port(c->dataio);
@@ -158,7 +159,7 @@
  *	being fast to access.
  */
  
-extern inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
+static inline void write_zsreg(struct z8530_channel *c, u8 reg, u8 val)
 {
 	unsigned long flags;
 	save_flags(flags);
@@ -177,7 +178,7 @@
  *	Write directly to the control register on the Z8530
  */
 
-extern inline void write_zsctrl(struct z8530_channel *c, u8 val)
+static inline void write_zsctrl(struct z8530_channel *c, u8 val)
 {
 	z8530_write_port(c->ctrlio, val);
 }
@@ -191,7 +192,7 @@
  */
 
 
-extern inline void write_zsdata(struct z8530_channel *c, u8 val)
+static inline void write_zsdata(struct z8530_channel *c, u8 val)
 {
 	z8530_write_port(c->dataio, val);
 }
@@ -441,7 +442,7 @@
  *	z8530_status - Handle a PIO status exception
  *	@chan: Z8530 channel to process
  *
- *	A status event occured in PIO synchronous mode. There are several
+ *	A status event occurred in PIO synchronous mode. There are several
  *	reasons the chip will bother us here. A transmit underrun means we
  *	failed to feed the chip fast enough and just broke a packet. A DCD
  *	change is a line up or down. We communicate that back to the protocol
@@ -555,7 +556,7 @@
  *	z8530_dma_status - Handle a DMA status exception
  *	@chan: Z8530 channel to process
  *	
- *	A status event occured on the Z8530. We receive these for two reasons
+ *	A status event occurred on the Z8530. We receive these for two reasons
  *	when in DMA mode. Firstly if we finished a packet transfer we get one
  *	and kick the next packet out. Secondly we may see a DCD change and
  *	have to poke the protocol layer.
@@ -1654,7 +1655,7 @@
  *	thing can only DMA within a 64K block not across the edges of it.
  */
  
-extern inline int spans_boundary(struct sk_buff *skb)
+static inline int spans_boundary(struct sk_buff *skb)
 {
 	unsigned long a=(unsigned long)skb->data;
 	a^=(a+skb->len);
@@ -1735,20 +1736,19 @@
 
 EXPORT_SYMBOL(z8530_get_stats);
 
-#ifdef MODULE
-
 /*
  *	Module support
  */
- 
-int init_module(void)
+static const char banner[] __initdata = KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n";
+
+static int __init z85230_init_driver(void)
 {
-	printk(KERN_INFO "Generic Z85C30/Z85230 interface driver v0.02\n");
+	printk(banner);
 	return 0;
 }
+module_init(z85230_init_driver);
 
-void cleanup_module(void)
+static void __exit z85230_cleanup_driver(void)
 {
 }
-
-#endif
+module_exit(z85230_cleanup_driver);
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.4.2/linux/drivers/net/wavelan.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wavelan.c	Sat Mar  3 10:55:47 2001
@@ -3686,7 +3686,7 @@
 	 * the spinlock. */
 	spin_lock(&lp->spinlock);
 
-	/* Check modem interupt */
+	/* Check modem interrupt */
 	if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
 		u8 dce_status;
 
@@ -3913,8 +3913,6 @@
 	}
 	wv_splx(lp, &flags);
 	
-	MOD_INC_USE_COUNT;
-
 #ifdef DEBUG_CALLBACK_TRACE
 	printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
 #endif
@@ -3947,8 +3945,6 @@
 
 	free_irq(dev->irq, dev);
 
-	MOD_DEC_USE_COUNT;
-
 #ifdef DEBUG_CALLBACK_TRACE
 	printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
 #endif
@@ -4019,8 +4015,10 @@
 
 	/* Initialize device structures */
 	dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL);
-	if (dev->priv == NULL)
+	if (dev->priv == NULL) {
+		release_region(ioaddr, sizeof(ha_t));
 		return -ENOMEM;
+	}
 	memset(dev->priv, 0x00, sizeof(net_local));
 	lp = (net_local *) dev->priv;
 
@@ -4045,6 +4043,7 @@
 	 */
 	ether_setup(dev);
 
+	SET_MODULE_OWNER(dev);
 	dev->open = wavelan_open;
 	dev->stop = wavelan_close;
 	dev->hard_start_xmit = wavelan_packet_xmit;
@@ -4287,7 +4286,7 @@
 
 /*
  * This software may only be used and distributed
- * according to the terms of the GNU Public License.
+ * according to the terms of the GNU General Public License.
  *
  * This software was developed as a component of the
  * Linux operating system.
diff -u --recursive --new-file v2.4.2/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.4.2/linux/drivers/net/wavelan.p.h	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/wavelan.p.h	Tue Mar  6 19:28:34 2001
@@ -420,7 +420,8 @@
 #undef DEBUG_RX_INFO		/* header of the received packet */
 #undef DEBUG_RX_FAIL		/* Normal failure conditions */
 #define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen. */
+
+#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen if defined to 32. */
 #undef DEBUG_IOCTL_TRACE	/* misc. call by Linux */
 #undef DEBUG_IOCTL_INFO		/* various debugging info */
 #define DEBUG_IOCTL_ERROR	/* what's going wrong */
diff -u --recursive --new-file v2.4.2/linux/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c
--- v2.4.2/linux/drivers/net/winbond-840.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/net/winbond-840.c	Tue Mar 20 12:05:00 2001
@@ -1,6 +1,6 @@
 /* winbond-840.c: A Linux PCI network adapter skeleton device driver. */
 /*
-	Written 1998-2000 by Donald Becker.
+	Written 1998-2001 by Donald Becker.
 
 	This software may be used and distributed according to the terms of
 	the GNU General Public License (GPL), incorporated herein by reference.
@@ -198,7 +198,8 @@
         PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
         PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
 };
-enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2};
+enum chip_capability_flags {
+	CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
 #ifdef USE_IO_OPS
 #define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
 #else
@@ -206,8 +207,9 @@
 #endif
 
 static struct pci_device_id w840_pci_tbl[] __devinitdata = {
-	{ 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ 0x1050, 0x0840, PCI_ANY_ID, 0x8153,     0, 0, 0 },
+	{ 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
@@ -223,6 +225,9 @@
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 static struct pci_id_info pci_id_tbl[] = {
+	{"Winbond W89c840",			/* Sometime a Level-One switch card. */
+	 { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
+	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
 	{"Winbond W89c840", { 0x08401050, 0xffffffff, },
 	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
 	{"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
@@ -305,21 +310,17 @@
 enum desc_status_bits {
 	DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
 	DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
-};
-
-/* Bits in w840_tx_desc.length */
-enum desc_length_bits {
 	DescIntr=0x80000000,
 };
 
 #define PRIV_ALIGN	15 	/* Required alignment mask */
+#define MII_CNT		1 /* winbond only supports one MII */
 struct netdev_private {
 	struct w840_rx_desc *rx_ring;
 	dma_addr_t	rx_addr[RX_RING_SIZE];
 	struct w840_tx_desc *tx_ring;
 	dma_addr_t	tx_addr[RX_RING_SIZE];
 	dma_addr_t ring_dma_addr;
-	struct pci_dev *pdev;
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
 	/* The saved address of a sent-in-place packet/buffer, for later free(). */
@@ -329,6 +330,7 @@
 	/* Frequently used values: keep some adjacent for cache effect. */
 	spinlock_t lock;
 	int chip_id, drv_flags;
+	struct pci_dev *pci_dev;
 	int csr6;
 	struct w840_rx_desc *rx_head_desc;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
@@ -344,7 +346,7 @@
 	/* MII transceiver section. */
 	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
+	unsigned char phys[MII_CNT];		/* MII device addresses, but only the first is used */
 };
 
 static int  eeprom_read(long ioaddr, int location);
@@ -377,15 +379,18 @@
 	struct netdev_private *np;
 	static int find_cnt;
 	int chip_idx = ent->driver_data;
-	int irq = pdev->irq;
+	int irq;
 	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	long ioaddr;
 
-	if (pci_enable_device(pdev))
-		return -EIO;
+	i = pci_enable_device(pdev);
+	if (i) return i;
+
 	pci_set_master(pdev);
 
-	if(!pci_dma_supported(pdev,0xFFFFffff)) {
+	irq = pdev->irq;
+
+	if(pci_set_dma_mask(pdev,0xFFFFffff)) {
 		printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
 				pdev->name);
 		return -EIO;
@@ -395,17 +400,16 @@
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
 
+	if (pci_request_regions(pdev, dev->name))
+		goto err_out_netdev;
+
 #ifdef USE_IO_OPS
 	ioaddr = pci_resource_start(pdev, 0);
-	if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name))
-		goto err_out_netdev;
 #else
 	ioaddr = pci_resource_start(pdev, 1);
-	if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name))
-		goto err_out_netdev;
 	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
 	if (!ioaddr)
-		goto err_out_iomem;
+		goto err_out_free_res;
 #endif
 
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
@@ -427,12 +431,12 @@
 	dev->irq = irq;
 
 	np = dev->priv;
+	np->pci_dev = pdev;
 	np->chip_id = chip_idx;
 	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-	np->pdev = pdev;
 	spin_lock_init(&np->lock);
 	
-	pdev->driver_data = dev;
+	pci_set_drvdata(pdev, dev);
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -463,7 +467,7 @@
 
 	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
-		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
+		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
 			int mii_status = mdio_read(dev, phy, 1);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
@@ -484,9 +488,8 @@
 	return 0;
 
 #ifndef USE_IO_OPS
-err_out_iomem:
-	release_mem_region(pci_resource_start(pdev, 1),
-			   pci_id_tbl[chip_idx].io_size);
+err_out_free_res:
+	pci_release_regions(pdev);
 #endif
 err_out_netdev:
 	unregister_netdev (dev);
@@ -535,6 +538,7 @@
 		eeprom_delay(ee_addr);
 	}
 	writel(EE_ChipSelect, ee_addr);
+	eeprom_delay(ee_addr);
 
 	for (i = 16; i > 0; i--) {
 		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
@@ -612,7 +616,7 @@
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
 	int i;
@@ -645,7 +649,7 @@
 
 static int netdev_open(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -680,7 +684,7 @@
 
 static void check_duplex(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
 	int negotiated =  mii_reg5 & np->advertising;
 	int duplex;
@@ -702,7 +706,7 @@
 static void netdev_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 	int old_csr6 = np->csr6;
@@ -725,7 +729,7 @@
 
 static void init_rxtx_rings(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	np->rx_head_desc = &np->rx_ring[0];
@@ -747,7 +751,7 @@
 		if (skb == NULL)
 			break;
 		skb->dev = dev;			/* Mark as being used by this device. */
-		np->rx_addr[i] = pci_map_single(np->pdev,skb->tail,
+		np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail,
 					skb->len,PCI_DMA_FROMDEVICE);
 
 		np->rx_ring[i].buffer1 = cpu_to_le32(np->rx_addr[i]);
@@ -778,7 +782,7 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].status = 0;
 		if (np->rx_skbuff[i]) {
-			pci_unmap_single(np->pdev,
+			pci_unmap_single(np->pci_dev,
 						np->rx_addr[i],
 						np->rx_skbuff[i]->len,
 						PCI_DMA_FROMDEVICE);
@@ -788,7 +792,7 @@
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (np->tx_skbuff[i]) {
-			pci_unmap_single(np->pdev,
+			pci_unmap_single(np->pci_dev,
 						np->tx_addr[i],
 						np->tx_skbuff[i]->len,
 						PCI_DMA_TODEVICE);
@@ -800,7 +804,7 @@
 
 static void init_registers(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -832,7 +836,7 @@
 	if (x86 <= 4)
 		printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
 			   "alignment to %x.\n", dev->name,
-			   (x86 <= 4 ? 0x4810 : 0x8010));
+			   (x86 <= 4 ? 0x4810 : 0xE010));
 #endif
 #else
 	writel(0xE010, ioaddr + PCIBusCfg);
@@ -857,7 +861,7 @@
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
@@ -905,11 +909,11 @@
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static int alloc_ring(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 
 	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
 
-	np->rx_ring = pci_alloc_consistent(np->pdev,
+	np->rx_ring = pci_alloc_consistent(np->pci_dev,
 			sizeof(struct w840_rx_desc)*RX_RING_SIZE +
 			sizeof(struct w840_tx_desc)*TX_RING_SIZE,
 			&np->ring_dma_addr);
@@ -922,7 +926,7 @@
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	unsigned entry;
 	int len1, len2;
 
@@ -933,7 +937,7 @@
 	entry = np->cur_tx % TX_RING_SIZE;
 
 	np->tx_skbuff[entry] = skb;
-	np->tx_addr[entry] = pci_map_single(np->pdev,
+	np->tx_addr[entry] = pci_map_single(np->pci_dev,
 				skb->data,skb->len, PCI_DMA_TODEVICE);
 	np->tx_ring[entry].buffer1 = cpu_to_le32(np->tx_addr[entry]);
 	len2 = 0;
@@ -987,7 +991,7 @@
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int work_limit = max_interrupt_work;
 
@@ -1040,7 +1044,7 @@
 				np->stats.tx_packets++;
 			}
 			/* Free the original skb. */
-			pci_unmap_single(np->pdev,np->tx_addr[entry],
+			pci_unmap_single(np->pci_dev,np->tx_addr[entry],
 						np->tx_skbuff[entry]->len,
 						PCI_DMA_TODEVICE);
 			np->tx_q_bytes -= np->tx_skbuff[entry]->len;
@@ -1082,7 +1086,7 @@
    for clarity and better register allocation. */
 static int netdev_rx(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 
@@ -1136,7 +1140,7 @@
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pdev,np->rx_addr[entry],
+				pci_dma_sync_single(np->pci_dev,np->rx_addr[entry],
 							np->rx_skbuff[entry]->len,
 							PCI_DMA_FROMDEVICE);
 				/* Call copy + cksum if available. */
@@ -1148,7 +1152,7 @@
 					   pkt_len);
 #endif
 			} else {
-				pci_unmap_single(np->pdev,np->rx_addr[entry],
+				pci_unmap_single(np->pci_dev,np->rx_addr[entry],
 							np->rx_skbuff[entry]->len,
 							PCI_DMA_FROMDEVICE);
 				skb_put(skb = np->rx_skbuff[entry], pkt_len);
@@ -1187,7 +1191,7 @@
 			if (skb == NULL)
 				break;			/* Better luck next round. */
 			skb->dev = dev;			/* Mark as being used by this device. */
-			np->rx_addr[entry] = pci_map_single(np->pdev,
+			np->rx_addr[entry] = pci_map_single(np->pci_dev,
 							skb->tail,
 							skb->len, PCI_DMA_FROMDEVICE);
 			np->rx_ring[entry].buffer1 = cpu_to_le32(np->rx_addr[entry]);
@@ -1202,7 +1206,7 @@
 static void netdev_error(struct net_device *dev, int intr_status)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n",
@@ -1243,7 +1247,7 @@
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 
 	/* The chip only need report frame silently dropped. */
 	if (netif_running(dev))
@@ -1270,7 +1274,7 @@
 
 static void set_rx_mode(struct net_device *dev)
 {
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	u32 mc_filter[2];			/* Multicast hash filter */
 	u32 rx_mode;
@@ -1328,7 +1332,7 @@
 static int netdev_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	netif_stop_queue(dev);
@@ -1379,23 +1383,19 @@
 
 static void __devexit w840_remove1 (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	if (dev) {
-		struct netdev_private *np = (void *)(dev->priv);
 		unregister_netdev(dev);
-#ifdef USE_IO_OPS
-		release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size);
-#else
-		release_mem_region(pci_resource_start(pdev, 1),
-				   pci_id_tbl[np->chip_id].io_size);
+		pci_release_regions(pdev);
+#ifndef USE_IO_OPS
 		iounmap((char *)(dev->base_addr));
 #endif
 		kfree(dev);
 	}
 
-	pdev->driver_data = NULL;
+	pci_set_drvdata(pdev, NULL);
 }
 
 static struct pci_driver w840_driver = {
diff -u --recursive --new-file v2.4.2/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.4.2/linux/drivers/net/yellowfin.c	Mon Dec 11 13:38:29 2000
+++ linux/drivers/net/yellowfin.c	Tue Mar  6 19:28:35 2001
@@ -1,33 +1,54 @@
 /* yellowfin.c: A Packet Engines G-NIC ethernet driver for linux. */
 /*
-	Written 1997-1999 by Donald Becker.
+	Written 1997-2001 by Donald Becker.
 
-	This software may be used and distributed according to the terms
-	of the GNU Public License, incorporated herein by reference.
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
 
 	This driver is for the Packet Engines G-NIC PCI Gigabit Ethernet adapter.
 	It also supports the Symbios Logic version of the same chip core.
 
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
 
 	Support and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html
+	http://www.scyld.com/network/yellowfin.html
+
+
+	Linux kernel changelog:
+	-----------------------
+
+	LK1.1.1 (jgarzik): Port to 2.4 kernel
+
+	LK1.1.2 (jgarzik):
+	* Merge in becker version 1.05
+
 */
 
-static const char *version =
-"yellowfin.c:v1.03a 7/30/99  Written by Donald Becker, becker@cesdis.edu\n"
-" http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html\n";
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"yellowfin.c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n";
+static const char version2[] =
+"  http://www.scyld.com/network/yellowfin.html\n";
+static const char version3[] =
+"  (unofficial 2.4.x port, LK1.1.2, January 11, 2001)\n";
 
-/* A few user-configurable values. */
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
 
-static int debug = 1;
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
-static int mtu = 0;
+static int mtu;
 #ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */
 /* System-wide count of bogus-rx frames. */
-static int bogus_rx = 0;
+static int bogus_rx;
 static int dma_ctrl = 0x004A0263; 			/* Constrained by errata */
 static int fifo_cfg = 0x0020;				/* Bypass external Tx FIFO. */
 #elif YF_NEW					/* A future perfect board :->.  */
@@ -40,7 +61,7 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1514 effectively disables this feature. */
-static int rx_copybreak = 0;
+static int rx_copybreak;
 
 /* Used to pass the media type, etc.
    No media types are currently defined.  These exist for driver
@@ -51,12 +72,12 @@
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 /* Do ugly workaround for GX server chipset errata. */
-static int gx_fix = 0;
+static int gx_fix;
 
 /* Operational parameters that are set at compile time. */
 
 /* Keep the ring sizes a power of two for efficiency.
-   Making the Tx queue too long decreases the effectiveness of channel
+   Making the Tx ring too long decreases the effectiveness of channel
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
@@ -66,57 +87,61 @@
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (2*HZ)
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
 #define yellowfin_debug debug
 
-#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#if !defined(__OPTIMIZE__)
 #warning  You must compile this file with the correct options!
 #warning  See the last lines of the source file.
 #error You must compile this driver with "-O".
 #endif
 
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/unaligned.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-/* Condensed operations for readability.
-   Compatibility defines are now in drv_compat.h */
-
+/* Condensed operations for readability. */
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
 
-
-#ifdef USE_IO_OPS
-#define YF_INB	inb
-#define YF_INW	inw
-#define YF_INL	inl
-#define YF_OUTB	outb
-#define YF_OUTW	outw
-#define YF_OUTL	outl
-#else
-#define YF_INB	readb
-#define YF_INW	readw
-#define YF_INL	readl
-#define YF_OUTB	writeb
-#define YF_OUTW	writew
-#define YF_OUTL	writel
-#endif
+#ifndef USE_IO_OPS
+#undef inb
+#undef inw
+#undef inl
+#undef outb
+#undef outw
+#undef outl
+#define inb readb
+#define inw readw
+#define inl readl
+#define outb writeb
+#define outw writew
+#define outl writel
+#endif /* !USE_IO_OPS */
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(mtu, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(gx_fix, "i");
 
 /*
 				Theory of Operation
@@ -193,50 +218,53 @@
 IVc. Errata
 
 See Packet Engines confidential appendix (prototype chips only).
-
 */
-
-/* A few values that may be tweaked. */
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
-/* The rest of these values should never change. */
+
 
+enum pci_id_flags_bits {
+	/* Set PCI command register bits before calling probe1(). */
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	/* Read and map the single following PCI BAR. */
+	PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
+	PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
+	PCI_UNUSED_IRQ=0x800,
+};
 enum capability_flags {
 	HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
-	HasMACAddrBug=32,			/* Really only on early revs.  */
+	HasMACAddrBug=32,			/* Only on early revs.  */
 };
-
-
 /* The PCI I/O space extent. */
 #define YELLOWFIN_SIZE 0x100
+#ifdef USE_IO_OPS
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
+#else
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+#endif
 
-#define YELLOWFIN_MODULE_NAME "yellowfin"
-#define PFX YELLOWFIN_MODULE_NAME ": "
-
-
-typedef enum {
-	YELLOWFIN_GNIC,
-	SYM83C885,
-} chip_t;
-
-
-struct chip_info {
-	const char *name;
-	int flags;
+struct pci_id_info {
+        const char *name;
+        struct match_info {
+                int     pci, pci_mask, subsystem, subsystem_mask;
+                int revision, revision_mask;                            /* Only 8 bits. */
+        } id;
+        enum pci_id_flags_bits pci_flags;
+        int io_size;                            /* Needed for I/O region check or ioremap(). */
+        int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 
-
-/* index by chip_t */
-static struct chip_info chip_info[] = {
-	{"Yellowfin G-NIC Gigabit Ethernet",
+static struct pci_id_info pci_id_tbl[] = {
+	{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
+	 PCI_IOTYPE, YELLOWFIN_SIZE,
 	 FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug},
-	{"Symbios SYM83C885", HasMII },
+	{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
+	 PCI_IOTYPE, YELLOWFIN_SIZE, HasMII },
+	{0,},
 };
 
-
 static struct pci_device_id yellowfin_pci_tbl[] __devinitdata = {
-	{ 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, YELLOWFIN_GNIC },
-	{ 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SYM83C885 },
+	{ 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
@@ -300,21 +328,22 @@
 	IntrEarlyRx=0x100, IntrWakeup=0x200, };
 
 #define PRIV_ALIGN	31 	/* Required alignment mask */
+#define MII_CNT		4
 struct yellowfin_private {
-	/* Descriptor rings first for alignment.  Tx requires a second descriptor
-	   for status. */
+	/* Descriptor rings first for alignment.
+	   Tx requires a second descriptor for status. */
 	struct yellowfin_desc rx_ring[RX_RING_SIZE];
 	struct yellowfin_desc tx_ring[TX_RING_SIZE*2];
 	/* The addresses of receive-in-place skbuffs. */
 	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	/* The saved address of a sent-in-place packet/buffer, for later free(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	struct tx_status_words tx_status[TX_RING_SIZE];
 	struct timer_list timer;	/* Media selection timer. */
 	struct net_device_stats stats;
 	/* Frequently used and paired value: keep adjacent for cache effect. */
+	int chip_id, drv_flags;
 	struct pci_dev *pci_dev;
-	int chip_id, flags;
 	struct yellowfin_desc *rx_head_desc;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
@@ -329,29 +358,14 @@
 	/* MII transceiver section. */
 	int mii_cnt;						/* MII device addresses. */
 	u16 advertising;					/* NWay media advertisement */
-	unsigned char phys[2];				/* MII device addresses. */
-	u32 pad[4];							/* Used for 32-byte alignment */
+	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used */
 	spinlock_t lock;
 };
 
-
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(mtu, "i");
-MODULE_PARM(debug, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(gx_fix, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-
-
 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);
-#ifdef HAVE_PRIVATE_IOCTL
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-#endif
 static int yellowfin_open(struct net_device *dev);
 static void yellowfin_timer(unsigned long data);
 static void yellowfin_tx_timeout(struct net_device *dev);
@@ -365,15 +379,141 @@
 static void set_rx_mode(struct net_device *dev);
 
 
+static int __devinit yellowfin_init_one(struct pci_dev *pdev,
+					const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct yellowfin_private *np;
+	int irq;
+	int chip_idx = ent->driver_data;
+	static int find_cnt = 0;
+	long ioaddr, real_ioaddr;
+	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
+	int drv_flags = pci_id_tbl[chip_idx].drv_flags;
+	
+	i = pci_enable_device(pdev);
+	if (i) return i;
+
+	dev = init_etherdev(NULL, sizeof(*np));
+	if (!dev) {
+		printk (KERN_ERR "yellowfin: cannot allocate ethernet device\n");
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+
+	np = dev->priv;
+
+	if (pci_request_regions(pdev, dev->name))
+		goto err_out_free_netdev;
+
+	pci_set_master (pdev);
+
+#ifdef USE_IO_OPS
+	real_ioaddr = ioaddr = pci_resource_start (pdev, 0);
+#else
+	real_ioaddr = ioaddr = pci_resource_start (pdev, 1);
+	ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);
+	if (!ioaddr)
+		goto err_out_free_res;
+#endif
+	irq = pdev->irq;
+
+	printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
+		   dev->name, pci_id_tbl[chip_idx].name, inl(ioaddr + ChipRev), ioaddr);
+
+	if (drv_flags & IsGigabit)
+		for (i = 0; i < 6; i++)
+			dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
+	else {
+		int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
+		for (i = 0; i < 6; i++)
+			dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
+	}
+	for (i = 0; i < 5; i++)
+			printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+	/* Reset the chip. */
+	outl(0x80000000, ioaddr + DMACtrl);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	pci_set_drvdata(pdev, dev);
+	np->lock = SPIN_LOCK_UNLOCKED;
+
+	np->pci_dev = pdev;
+	np->chip_id = chip_idx;
+	np->drv_flags = drv_flags;
+
+	if (dev->mem_start)
+		option = dev->mem_start;
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		if (option & 0x200)
+			np->full_duplex = 1;
+		np->default_port = option & 15;
+		if (np->default_port)
+			np->medialock = 1;
+	}
+	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
+		np->full_duplex = 1;
+
+	if (np->full_duplex)
+		np->duplex_lock = 1;
+
+	/* The Yellowfin-specific entries in the device structure. */
+	dev->open = &yellowfin_open;
+	dev->hard_start_xmit = &yellowfin_start_xmit;
+	dev->stop = &yellowfin_close;
+	dev->get_stats = &yellowfin_get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &mii_ioctl;
+	dev->tx_timeout = yellowfin_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	if (mtu)
+		dev->mtu = mtu;
+
+	if (np->drv_flags & HasMII) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
+			int mii_status = mdio_read(ioaddr, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				np->phys[phy_idx++] = phy;
+				np->advertising = mdio_read(ioaddr, phy, 4);
+				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);
+			}
+		}
+		np->mii_cnt = phy_idx;
+	}
+
+	find_cnt++;
+	
+	return 0;
+
+#ifndef USE_IO_OPS
+err_out_free_res:
+	pci_release_regions(pdev);
+#endif
+err_out_free_netdev:
+	unregister_netdev (dev);
+	kfree (dev);
+	return -ENODEV;
+}
+
 static int __devinit read_eeprom(long ioaddr, int location)
 {
 	int bogus_cnt = 10000;		/* Typical 33Mhz: 1050 ticks */
 
-	YF_OUTB(location, ioaddr + EEAddr);
-	YF_OUTB(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
-	while ((YF_INB(ioaddr + EEStatus) & 0x80)  &&  --bogus_cnt > 0)
+	outb(location, ioaddr + EEAddr);
+	outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl);
+	while ((inb(ioaddr + EEStatus) & 0x80)  &&  --bogus_cnt > 0)
 		;
-	return YF_INB(ioaddr + EERead);
+	return inb(ioaddr + EERead);
 }
 
 /* MII Managemen Data I/O accesses.
@@ -384,24 +524,24 @@
 {
 	int i;
 
-	YF_OUTW((phy_id<<8) + location, ioaddr + MII_Addr);
-	YF_OUTW(1, ioaddr + MII_Cmd);
+	outw((phy_id<<8) + location, ioaddr + MII_Addr);
+	outw(1, ioaddr + MII_Cmd);
 	for (i = 10000; i >= 0; i--)
-		if ((YF_INW(ioaddr + MII_Status) & 1) == 0)
+		if ((inw(ioaddr + MII_Status) & 1) == 0)
 			break;
-	return YF_INW(ioaddr + MII_Rd_Data);
+	return inw(ioaddr + MII_Rd_Data);
 }
 
 static void mdio_write(long ioaddr, int phy_id, int location, int value)
 {
 	int i;
 
-	YF_OUTW((phy_id<<8) + location, ioaddr + MII_Addr);
-	YF_OUTW(value, ioaddr + MII_Wr_Data);
+	outw((phy_id<<8) + location, ioaddr + MII_Addr);
+	outw(value, ioaddr + MII_Wr_Data);
 
 	/* Wait for the command to finish. */
 	for (i = 10000; i >= 0; i--)
-		if ((YF_INW(ioaddr + MII_Status) & 1) == 0)
+		if ((inw(ioaddr + MII_Status) & 1) == 0)
 			break;
 	return;
 }
@@ -414,10 +554,10 @@
 	int i;
 
 	/* Reset the chip. */
-	YF_OUTL(0x80000000, ioaddr + DMACtrl);
+	outl(0x80000000, ioaddr + DMACtrl);
 
-	if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev))
-		return -EAGAIN;
+	i = request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev);
+	if (i) return i;
 
 	if (yellowfin_debug > 1)
 		printk(KERN_DEBUG "%s: yellowfin_open() irq %d.\n",
@@ -425,58 +565,59 @@
 
 	yellowfin_init_ring(dev);
 
-	YF_OUTL(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);
-	YF_OUTL(virt_to_bus(yp->tx_ring), ioaddr + TxPtr);
+	outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);
+	outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr);
 
 	for (i = 0; i < 6; i++)
-		YF_OUTB(dev->dev_addr[i], ioaddr + StnAddr + i);
+		outb(dev->dev_addr[i], ioaddr + StnAddr + i);
 
 	/* Set up various condition 'select' registers.
 	   There are no options here. */
-	YF_OUTL(0x00800080, ioaddr + TxIntrSel); 	/* Interrupt on Tx abort */
-	YF_OUTL(0x00800080, ioaddr + TxBranchSel);	/* Branch on Tx abort */
-	YF_OUTL(0x00400040, ioaddr + TxWaitSel); 	/* Wait on Tx status */
-	YF_OUTL(0x00400040, ioaddr + RxIntrSel);	/* Interrupt on Rx done */
-	YF_OUTL(0x00400040, ioaddr + RxBranchSel);	/* Branch on Rx error */
-	YF_OUTL(0x00400040, ioaddr + RxWaitSel);	/* Wait on Rx done */
+	outl(0x00800080, ioaddr + TxIntrSel); 	/* Interrupt on Tx abort */
+	outl(0x00800080, ioaddr + TxBranchSel);	/* Branch on Tx abort */
+	outl(0x00400040, ioaddr + TxWaitSel); 	/* Wait on Tx status */
+	outl(0x00400040, ioaddr + RxIntrSel);	/* Interrupt on Rx done */
+	outl(0x00400040, ioaddr + RxBranchSel);	/* Branch on Rx error */
+	outl(0x00400040, ioaddr + RxWaitSel);	/* Wait on Rx done */
 
 	/* Initialize other registers: with so many this eventually this will
 	   converted to an offset/value list. */
-	YF_OUTL(dma_ctrl, ioaddr + DMACtrl);
-	YF_OUTW(fifo_cfg, ioaddr + FIFOcfg);
+	outl(dma_ctrl, ioaddr + DMACtrl);
+	outw(fifo_cfg, ioaddr + FIFOcfg);
 	/* Enable automatic generation of flow control frames, period 0xffff. */
-	YF_OUTL(0x0030FFFF, ioaddr + FlowCtrl);
+	outl(0x0030FFFF, ioaddr + FlowCtrl);
 
 	yp->tx_threshold = 32;
-	YF_OUTL(yp->tx_threshold, ioaddr + TxThreshold);
+	outl(yp->tx_threshold, ioaddr + TxThreshold);
 
 	if (dev->if_port == 0)
 		dev->if_port = yp->default_port;
 
-	netif_start_queue (dev);
+	netif_start_queue(dev);
 
 	/* Setting the Rx mode will start the Rx process. */
-	if (yp->flags & IsGigabit) {
+	if (yp->drv_flags & IsGigabit) {
 		/* We are always in full-duplex mode with gigabit! */
 		yp->full_duplex = 1;
-		YF_OUTW(0x01CF, ioaddr + Cnfg);
+		outw(0x01CF, ioaddr + Cnfg);
 	} else {
-		YF_OUTW(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */
-		YF_OUTW(0x1018, ioaddr + FrameGap1);
-		YF_OUTW(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
+		outw(0x0018, ioaddr + FrameGap0); /* 0060/4060 for non-MII 10baseT */
+		outw(0x1018, ioaddr + FrameGap1);
+		outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
 	}
 	set_rx_mode(dev);
 
 	/* Enable interrupts by setting the interrupt mask. */
-	YF_OUTW(0x81ff, ioaddr + IntrEnb);			/* See enum intr_status_bits */
-	YF_OUTW(0x0000, ioaddr + EventStatus);		/* Clear non-interrupting events */
-	YF_OUTL(0x80008000, ioaddr + RxCtrl);		/* Start Rx and Tx channels. */
-	YF_OUTL(0x80008000, ioaddr + TxCtrl);
+	outw(0x81ff, ioaddr + IntrEnb);			/* See enum intr_status_bits */
+	outw(0x0000, ioaddr + EventStatus);		/* Clear non-interrupting events */
+	outl(0x80008000, ioaddr + RxCtrl);		/* Start Rx and Tx channels. */
+	outl(0x80008000, ioaddr + TxCtrl);
 
 	if (yellowfin_debug > 2) {
 		printk(KERN_DEBUG "%s: Done yellowfin_open().\n",
 			   dev->name);
 	}
+
 	/* Set the timer to check for link beat. */
 	init_timer(&yp->timer);
 	yp->timer.expires = jiffies + 3*HZ;
@@ -496,7 +637,7 @@
 
 	if (yellowfin_debug > 3) {
 		printk(KERN_DEBUG "%s: Yellowfin timer tick, status %8.8x.\n",
-			   dev->name, YF_INW(ioaddr + IntrStatus));
+			   dev->name, inw(ioaddr + IntrStatus));
 	}
 
 	if (yp->mii_cnt) {
@@ -513,7 +654,7 @@
 			  || (negotiated & 0x00C0) == 0x0040)) {
 			yp->full_duplex = 1;
 		}
-		YF_OUTW(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
+		outw(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
 
 		if (mii_reg1 & 0x0004)
 			next_tick = 60*HZ;
@@ -533,7 +674,7 @@
 	printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx "
 		   "status %4.4x, Rx status %4.4x, resetting...\n",
 		   dev->name, yp->cur_tx, yp->dirty_tx,
-		   YF_INL(ioaddr + TxStatus), YF_INL(ioaddr + RxStatus));
+		   inl(ioaddr + TxStatus), inl(ioaddr + RxStatus));
 
 	/* Note: these should be KERN_DEBUG. */
 	if (yellowfin_debug) {
@@ -553,13 +694,12 @@
 	dev->if_port = 0;
 
 	/* Wake the potentially-idle transmit channel. */
-	YF_OUTL(0x10001000, dev->base_addr + TxCtrl);
+	outl(0x10001000, dev->base_addr + TxCtrl);
 	if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
 		netif_wake_queue (dev);		/* Typical path */
 
 	dev->trans_start = jiffies;
 	yp->stats.tx_errors++;
-	return;
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -642,8 +782,8 @@
 
 	netif_stop_queue (dev);
 
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
+	/* Note: Ordering is important here, set the field with the
+	   "ownership" bit last, and only then increment cur_tx. */
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = yp->cur_tx % TX_RING_SIZE;
@@ -691,7 +831,7 @@
 	/* Non-x86 Todo: explicitly flush cache lines here. */
 
 	/* Wake the potentially-idle transmit channel. */
-	YF_OUTL(0x10001000, dev->base_addr + TxCtrl);
+	outl(0x10001000, dev->base_addr + TxCtrl);
 
 	if (yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE)
 		netif_start_queue (dev);		/* Typical path */
@@ -712,7 +852,8 @@
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
 	struct yellowfin_private *yp;
-	long ioaddr, boguscnt = max_interrupt_work;
+	long ioaddr;
+	int boguscnt = max_interrupt_work;
 
 #ifndef final_version			/* Can never occur. */
 	if (dev == NULL) {
@@ -727,7 +868,7 @@
 	spin_lock (&yp->lock);
 
 	do {
-		u16 intr_status = YF_INW(ioaddr + IntrClear);
+		u16 intr_status = inw(ioaddr + IntrClear);
 
 		if (yellowfin_debug > 4)
 			printk(KERN_DEBUG "%s: Yellowfin interrupt, status %4.4x.\n",
@@ -738,7 +879,7 @@
 
 		if (intr_status & (IntrRxDone | IntrEarlyRx)) {
 			yellowfin_rx(dev);
-			YF_OUTL(0x10001000, ioaddr + RxCtrl);		/* Wake Rx engine. */
+			outl(0x10001000, ioaddr + RxCtrl);		/* Wake Rx engine. */
 		}
 
 #ifdef NO_TXSTATS
@@ -746,8 +887,8 @@
 			int entry = yp->dirty_tx % TX_RING_SIZE;
 			if (yp->tx_ring[entry].result_status == 0)
 				break;
-			yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
 			yp->stats.tx_packets++;
+			yp->stats.tx_bytes += yp->tx_skbuff[entry]->len;
 			/* Free the original skb. */
 			dev_kfree_skb_irq(yp->tx_skbuff[entry]);
 			yp->tx_skbuff[entry] = 0;
@@ -756,11 +897,8 @@
 			&& yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) {
 			/* The ring is no longer full, clear tbusy. */
 			yp->tx_full = 0;
-		}
-		if (yp->tx_full)
-			netif_stop_queue(dev);
-		else
 			netif_wake_queue(dev);
+		}
 #else
 		if (intr_status & IntrTxDone
 			|| yp->tx_tail_desc->tx_errs) {
@@ -831,11 +969,8 @@
 				&& yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) {
 				/* The ring is no longer full, clear tbusy. */
 				yp->tx_full = 0;
-			}
-			if (yp->tx_full)
-				netif_stop_queue(dev);
-			else
 				netif_wake_queue(dev);
+			}
 
 			yp->dirty_tx = dirty_tx;
 			yp->tx_tail_desc = &yp->tx_status[dirty_tx % TX_RING_SIZE];
@@ -847,7 +982,8 @@
 			yellowfin_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n",
+			printk(KERN_WARNING "%s: Too much work at interrupt, "
+				   "status=0x%4.4x.\n",
 				   dev->name, intr_status);
 			break;
 		}
@@ -855,19 +991,10 @@
 
 	if (yellowfin_debug > 3)
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-			   dev->name, YF_INW(ioaddr + IntrStatus));
-
-	/* Code that should never be run!  Perhaps remove after testing.. */
-	{
-		static int stopit = 10;
-		if ((!(netif_running(dev)))  &&  --stopit < 0) {
-			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
-				   dev->name);
-			free_irq(irq, dev);
-		}
-	}
+			   dev->name, inw(ioaddr + IntrStatus));
 
 	spin_unlock (&yp->lock);
+	return;
 }
 
 /* This routine is logically part of the interrupt handler, but separated
@@ -876,7 +1003,7 @@
 {
 	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
 	int entry = yp->cur_rx % RX_RING_SIZE;
-	int boguscnt = 20;
+	int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
 
 	if (yellowfin_debug > 4) {
 		printk(KERN_DEBUG " In yellowfin_rx(), entry %d status %8.8x.\n",
@@ -905,7 +1032,7 @@
 			printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
 				   " status %4.4x!\n", dev->name, desc_status);
 			yp->stats.rx_length_errors++;
-		} else if ((yp->flags & IsGigabit)  &&  (frame_status & 0x0038)) {
+		} else if ((yp->drv_flags & IsGigabit)  &&  (frame_status & 0x0038)) {
 			/* There was a error. */
 			if (yellowfin_debug > 3)
 				printk(KERN_DEBUG "  yellowfin_rx() Rx error was %4.4x.\n",
@@ -915,7 +1042,7 @@
 			if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
 			if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
 			if (frame_status < 0) yp->stats.rx_dropped++;
-		} else if ( !(yp->flags & IsGigabit)  &&
+		} else if ( !(yp->drv_flags & IsGigabit)  &&
 				   ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
 			u8 status1 = buf_addr[data_size-2];
 			u8 status2 = buf_addr[data_size-1];
@@ -952,21 +1079,22 @@
 			   without copying to a properly sized skbuff. */
 			if (pkt_len > rx_copybreak) {
 				char *temp = skb_put(skb = yp->rx_skbuff[entry], pkt_len);
-#ifndef final_verison				/* Remove after testing. */
+				yp->rx_skbuff[entry] = NULL;
+#ifndef final_version				/* Remove after testing. */
 				if (le32desc_to_virt(yp->rx_ring[entry].addr) != temp)
-					printk(KERN_WARNING "%s: Warning -- the skbuff addresses "
+					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
 						   "do not match in yellowfin_rx: %p vs. %p / %p.\n",
-						   dev->name, le32desc_to_virt(yp->rx_ring[entry].addr),
+						   dev->name,
+						   le32desc_to_virt(yp->rx_ring[entry].addr),
 						   skb->head, temp);
 #endif
-				yp->rx_skbuff[entry] = NULL;
 			} else {
 				skb = dev_alloc_skb(pkt_len + 2);
 				if (skb == NULL)
 					break;
 				skb->dev = dev;
-				skb_reserve(skb, 2);	/* 16 byte align the data fields */
-#if 1 || USE_IP_CSUM
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, yp->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
@@ -989,9 +1117,9 @@
 		entry = yp->dirty_rx % RX_RING_SIZE;
 		if (yp->rx_skbuff[entry] == NULL) {
 			struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz);
-			if (skb == NULL)
-				break;			/* Better luck next round. */
 			yp->rx_skbuff[entry] = skb;
+			if (skb == NULL)
+				break;				/* Better luck next round. */
 			skb->dev = dev;			/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			yp->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
@@ -1032,29 +1160,30 @@
 	netif_stop_queue (dev);
 
 	if (yellowfin_debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",
-			   dev->name, YF_INW(ioaddr + TxStatus),
-			   YF_INW(ioaddr + RxStatus),
-			   YF_INW(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x "
+			   "Rx %4.4x Int %2.2x.\n",
+			   dev->name, inw(ioaddr + TxStatus),
+			   inw(ioaddr + RxStatus), inw(ioaddr + IntrStatus));
 		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
 			   dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);
 	}
 
 	/* Disable interrupts by clearing the interrupt mask. */
-	YF_OUTW(0x0000, ioaddr + IntrEnb);
+	outw(0x0000, ioaddr + IntrEnb);
 
 	/* Stop the chip's Tx and Rx processes. */
-	YF_OUTL(0x80000000, ioaddr + RxCtrl);
-	YF_OUTL(0x80000000, ioaddr + TxCtrl);
+	outl(0x80000000, ioaddr + RxCtrl);
+	outl(0x80000000, ioaddr + TxCtrl);
 
 	del_timer(&yp->timer);
 
-#if !defined(final_version) && defined(__i386__)
+#if defined(__i386__)
 	if (yellowfin_debug > 2) {
-		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));
+		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+			   (int)virt_to_bus(yp->tx_ring));
 		for (i = 0; i < TX_RING_SIZE*2; i++)
 			printk(" %c #%d desc. %8.8x %8.8x %8.8x %8.8x.\n",
-				   YF_INL(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
+				   inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',
 				   i, yp->tx_ring[i].dbdma_cmd, yp->tx_ring[i].addr,
 				   yp->tx_ring[i].branch_addr, yp->tx_ring[i].result_status);
 		printk(KERN_DEBUG "  Tx status %p:\n", yp->tx_status);
@@ -1063,10 +1192,11 @@
 				   i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,
 				   yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);
 
-		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));
+		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
+			   (int)virt_to_bus(yp->rx_ring));
 		for (i = 0; i < RX_RING_SIZE; i++) {
 			printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x %8.8x\n",
-				   YF_INL(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
+				   inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',
 				   i, yp->rx_ring[i].dbdma_cmd, yp->rx_ring[i].addr,
 				   yp->rx_ring[i].result_status);
 			if (yellowfin_debug > 6) {
@@ -1105,6 +1235,7 @@
 			   dev->name, bogus_rx);
 	}
 #endif
+
 	return 0;
 }
 
@@ -1143,17 +1274,17 @@
 {
 	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	u16 cfg_value = YF_INW(ioaddr + Cnfg);
+	u16 cfg_value = inw(ioaddr + Cnfg);
 
 	/* Stop the Rx process to change any value. */
-	YF_OUTW(cfg_value & ~0x1000, ioaddr + Cnfg);
+	outw(cfg_value & ~0x1000, ioaddr + Cnfg);
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
 		/* Unconditionally log net taps. */
 		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-		YF_OUTW(0x000F, ioaddr + AddrMode);
+		outw(0x000F, ioaddr + AddrMode);
 	} else if ((dev->mc_count > 64)  ||  (dev->flags & IFF_ALLMULTI)) {
 		/* Too many to filter well, or accept all multicasts. */
-		YF_OUTW(0x000B, ioaddr + AddrMode);
+		outw(0x000B, ioaddr + AddrMode);
 	} else if (dev->mc_count > 0) { /* Must use the multicast hash table. */
 		struct dev_mc_list *mclist;
 		u16 hash_table[4];
@@ -1163,7 +1294,7 @@
 			 i++, mclist = mclist->next) {
 			/* Due to a bug in the early chip versions, multiple filter
 			   slots must be set for each address. */
-			if (yp->flags & HasMulticastBug) {
+			if (yp->drv_flags & HasMulticastBug) {
 				set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,
 						hash_table);
 				set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,
@@ -1176,24 +1307,24 @@
 		}
 		/* Copy the hash table to the chip. */
 		for (i = 0; i < 4; i++)
-			YF_OUTW(hash_table[i], ioaddr + HashTbl + i*2);
-		YF_OUTW(0x0003, ioaddr + AddrMode);
+			outw(hash_table[i], ioaddr + HashTbl + i*2);
+		outw(0x0003, ioaddr + AddrMode);
 	} else {					/* Normal, unicast/broadcast-only mode. */
-		YF_OUTW(0x0001, ioaddr + AddrMode);
+		outw(0x0001, ioaddr + AddrMode);
 	}
 	/* Restart the Rx process. */
-	YF_OUTW(cfg_value | 0x1000, ioaddr + Cnfg);
+	outw(cfg_value | 0x1000, ioaddr + Cnfg);
 }
 
-#ifdef HAVE_PRIVATE_IOCTL
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct yellowfin_private *np = (void *)dev->priv;
 	long ioaddr = dev->base_addr;
 	u16 *data = (u16 *)&rq->ifr_data;
 
 	switch(cmd) {
 	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = ((struct yellowfin_private *)dev->priv)->phys[0] & 0x1f;
+		data[0] = np->phys[0] & 0x1f;
 		/* Fall Through */
 	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
 		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
@@ -1201,155 +1332,30 @@
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
+		if (data[0] == np->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				/* Check for autonegotiation on or reset. */
+				np->medialock = (value & 0x9000) ? 0 : 1;
+				if (np->medialock)
+					np->full_duplex = (value & 0x0100) ? 1 : 0;
+				break;
+			case 4: np->advertising = value; break;
+			}
+			/* Perhaps check_duplex(dev), depending on chip semantics. */
+		}
 		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
 		return 0;
 	default:
 		return -EOPNOTSUPP;
 	}
 }
-#endif  /* HAVE_PRIVATE_IOCTL */
 
 
-static int __devinit yellowfin_init_one(struct pci_dev *pdev,
-					const struct pci_device_id *ent)
-{
-	struct net_device *dev;
-	struct yellowfin_private *yp;
-	int option, i, irq;
-	int flags, chip_idx;
-	static int find_cnt = 0;
-	long ioaddr, real_ioaddr;
-	
-	chip_idx = ent->driver_data;
-	flags = chip_info[chip_idx].flags;
-
-	dev = init_etherdev(NULL, sizeof(*yp));
-	if (!dev) {
-		printk (KERN_ERR PFX "cannot allocate ethernet device\n");
-		return -ENOMEM;
-	}
-	SET_MODULE_OWNER(dev);
-
-	yp = dev->priv;
-
-	if (!request_region (pci_resource_start (pdev, 0),
-			     YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
-		printk (KERN_ERR PFX "cannot obtain I/O port region\n");
-		goto err_out_free_netdev;
-	}
-	if (!request_mem_region (pci_resource_start (pdev, 1),
-			         YELLOWFIN_SIZE, YELLOWFIN_MODULE_NAME)) {
-		printk (KERN_ERR PFX "cannot obtain MMIO region\n");
-		goto err_out_free_pio_region;
-	}
-	
-	if (pci_enable_device (pdev))
-		goto err_out_free_mmio_region;
-	pci_set_master (pdev);
-
-#ifdef USE_IO_OPS
-	real_ioaddr = ioaddr = pci_resource_start (pdev, 0);
-#else
-	real_ioaddr = ioaddr = pci_resource_start (pdev, 1);
-	ioaddr = (long) ioremap(ioaddr, YELLOWFIN_SIZE);
-	if (!ioaddr)
-		goto err_out_free_mmio_region;
-#endif
-	irq = pdev->irq;
-
-	printk(KERN_INFO "%s: %s type %8x at 0x%lx, ",
-	       dev->name, chip_info[chip_idx].name,
-	       YF_INL(ioaddr + ChipRev), real_ioaddr);
-
-	if (flags & IsGigabit)
-		for (i = 0; i < 6; i++)
-			dev->dev_addr[i] = YF_INB(ioaddr + StnAddr + i);
-	else {
-		int ee_offset = (read_eeprom(ioaddr, 6) == 0xff ? 0x100 : 0);
-		for (i = 0; i < 6; i++)
-			dev->dev_addr[i] = read_eeprom(ioaddr, ee_offset + i);
-	}
-	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-
-	/* Reset the chip. */
-	YF_OUTL(0x80000000, ioaddr + DMACtrl);
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	pdev->driver_data = dev;
-	yp->chip_id = chip_idx;
-	yp->flags = flags;
-	yp->lock = SPIN_LOCK_UNLOCKED;
-
-	option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
-	if (dev->mem_start)
-		option = dev->mem_start;
-
-	/* The lower four bits are the media type. */
-	if (option > 0) {
-		if (option & 0x200)
-			yp->full_duplex = 1;
-		yp->default_port = option & 15;
-		if (yp->default_port)
-			yp->medialock = 1;
-	}
-	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
-		yp->full_duplex = 1;
-
-	if (yp->full_duplex)
-		yp->duplex_lock = 1;
-
-	/* The Yellowfin-specific entries in the device structure. */
-	dev->open = &yellowfin_open;
-	dev->hard_start_xmit = &yellowfin_start_xmit;
-	dev->stop = &yellowfin_close;
-	dev->get_stats = &yellowfin_get_stats;
-	dev->set_multicast_list = &set_rx_mode;
-#ifdef HAVE_PRIVATE_IOCTL
-	dev->do_ioctl = &mii_ioctl;
-#endif
-	dev->tx_timeout = yellowfin_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	if (mtu)
-		dev->mtu = mtu;
-
-	if (yp->flags & HasMII) {
-		int phy, phy_idx = 0;
-		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 1);
-			if (mii_status != 0xffff  &&
-				mii_status != 0x0000) {
-				yp->phys[phy_idx++] = phy;
-				yp->advertising = mdio_read(ioaddr, phy, 4);
-				printk(KERN_INFO "%s: MII PHY found at address %d, status "
-					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, yp->advertising);
-			}
-		}
-		yp->mii_cnt = phy_idx;
-	}
-
-	find_cnt++;
-	
-	return 0;
-
-err_out_free_mmio_region:
-	release_mem_region (pci_resource_start (pdev, 1), YELLOWFIN_SIZE);
-err_out_free_pio_region:
-	release_region (pci_resource_start (pdev, 0), YELLOWFIN_SIZE);
-err_out_free_netdev:
-	unregister_netdev (dev);
-	kfree (dev);
-	return -ENODEV;
-}
-
 static void __devexit yellowfin_remove_one (struct pci_dev *pdev)
 {
-	struct net_device *dev = pdev->driver_data;
+	struct net_device *dev = pci_get_drvdata(pdev);
 	struct yellowfin_private *np;
 
 	if (!dev)
@@ -1358,19 +1364,19 @@
 
 	unregister_netdev (dev);
 
-	release_region (dev->base_addr, YELLOWFIN_SIZE);
-	release_mem_region (dev->base_addr, YELLOWFIN_SIZE);
+	pci_release_regions (pdev);
 
 #ifndef USE_IO_OPS
 	iounmap ((void *) dev->base_addr);
 #endif
 
 	kfree (dev);
+	pci_set_drvdata(pdev, NULL);
 }
 
 
 static struct pci_driver yellowfin_driver = {
-	name:		YELLOWFIN_MODULE_NAME,
+	name:		"yellowfin",
 	id_table:	yellowfin_pci_tbl,
 	probe:		yellowfin_init_one,
 	remove:		yellowfin_remove_one,
@@ -1380,7 +1386,8 @@
 static int __init yellowfin_init (void)
 {
 	if (debug)					/* Emit version even if no cards detected. */
-		printk(KERN_INFO "%s", version);
+		printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
+		       version1, version2, version3);
 
 	return pci_module_init (&yellowfin_driver);
 }
@@ -1394,12 +1401,12 @@
 
 module_init(yellowfin_init);
 module_exit(yellowfin_cleanup);
-
-
+
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__  -Wall -Wstrict-prototypes -O6 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  compile-command-alphaLX: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c yellowfin.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`  -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
+ *  compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED"
+ *  simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --recursive --new-file v2.4.2/linux/drivers/net/zlib.c linux/drivers/net/zlib.c
--- v2.4.2/linux/drivers/net/zlib.c	Mon Jul  5 20:35:18 1999
+++ linux/drivers/net/zlib.c	Sat Mar  3 10:55:47 2001
@@ -433,7 +433,7 @@
     int nice_match; /* Stop searching when current match exceeds this */
 
                 /* used by trees.c: */
-    /* Didn't use ct_data typedef below to supress compiler warning */
+    /* Didn't use ct_data typedef below to suppress compiler warning */
     struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
     struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
     struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
@@ -689,7 +689,7 @@
 
 /* ===========================================================================
  * Update a hash value with the given input byte
- * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ * IN  assertion: all calls to UPDATE_HASH are made with consecutive
  *    input characters, so that a running hash key can be computed from the
  *    previous key instead of complete recalculation each time.
  */
@@ -700,7 +700,7 @@
  * Insert string str in the dictionary and set match_head to the previous head
  * of the hash chain (the most recent string with same hash key). Return
  * the previous length of the hash chain.
- * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ * IN  assertion: all calls to INSERT_STRING are made with consecutive
  *    input characters and the first MIN_MATCH bytes of str are valid
  *    (except for the last MIN_MATCH-1 bytes of the input file).
  */
diff -u --recursive --new-file v2.4.2/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.4.2/linux/drivers/parport/ieee1284_ops.c	Mon May 15 11:16:30 2000
+++ linux/drivers/parport/ieee1284_ops.c	Fri Mar  2 18:43:03 2001
@@ -50,9 +50,6 @@
 	if (port->irq != PARPORT_IRQ_NONE) {
 		parport_enable_irq (port);
 		no_irq = 0;
-
-		/* Clear out previous irqs. */
-		while (!down_trylock (&port->physport->ieee1284.irq));
 	}
 
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
@@ -192,6 +189,7 @@
 			DPRINTK (KERN_DEBUG
 				 "%s: Nibble timeout at event 9 (%d bytes)\n",
 				 port->name, i/2);
+			parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
 			break;
 		}
 
diff -u --recursive --new-file v2.4.2/linux/drivers/parport/parport_gsc.c linux/drivers/parport/parport_gsc.c
--- v2.4.2/linux/drivers/parport/parport_gsc.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/parport/parport_gsc.c	Tue Mar  6 19:44:37 2001
@@ -19,6 +19,8 @@
  *          Andrea Arcangeli
  */
 
+#undef DEBUG	/* undef for production */
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -42,13 +44,9 @@
 #include <asm/parport_gsc.h>
 
 
-#undef DEBUG	/* undef for production */
-
-#ifdef DEBUG
-#define DPRINTK  printk
-#else
-#define DPRINTK(stuff...)
-#endif
+MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
+MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver");
+MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port");
 
 
 /*
@@ -83,25 +81,18 @@
 
 static void parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	DPRINTK(__FILE__ ": got IRQ\n");
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
 void parport_gsc_write_data(struct parport *p, unsigned char d)
 {
-	DPRINTK(__FILE__ ": write (0x%02x) %c \n", d, d);
 	parport_writeb (d, DATA (p));
 }
 
 unsigned char parport_gsc_read_data(struct parport *p)
 {
-#ifdef DEBUG
 	unsigned char c = parport_readb (DATA (p));
-	DPRINTK(__FILE__ ": read (0x%02x) %c\n", c,c);
 	return c;
-#else
-	return parport_readb (DATA (p));
-#endif
 }
 
 void parport_gsc_write_control(struct parport *p, unsigned char d)
@@ -113,8 +104,8 @@
 
 	/* Take this out when drivers have adapted to the newer interface. */
 	if (d & 0x20) {
-		printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
-			p->name, p->cad->name);
+		pr_debug("%s (%s): use data_reverse for this!\n",
+			    p->name, p->cad->name);
 		parport_gsc_data_reverse (p);
 	}
 
@@ -141,7 +132,7 @@
 
 	/* Take this out when drivers have adapted to the newer interface. */
 	if (mask & 0x20) {
-		printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+		pr_debug("%s (%s): use data_%s for this!\n",
 			p->name, p->cad->name,
 			(val & 0x20) ? "reverse" : "forward");
 		if (val & 0x20)
@@ -199,16 +190,12 @@
 
 void parport_gsc_inc_use_count(void)
 {
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 }
 
 void parport_gsc_dec_use_count(void)
 {
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif
 }
 
 
@@ -360,8 +347,12 @@
 	struct parport tmp;
 	struct parport *p = &tmp;
 
+#if 1
+#warning Take this out when region handling works again, <deller@gmx,de>
+#else
 	if (check_region(base, 3)) 
 	    return NULL;
+#endif
 	    
 	priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL);
 	if (!priv) {
@@ -474,8 +465,7 @@
 
 static int __initdata parport_count;
 
-static int __init 
-parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri)
+static int __init parport_init_chip(struct hp_device *d, struct pa_iodc_driver *dri)
 {
 	unsigned long port;
 	int irq;
@@ -515,32 +505,22 @@
   { 0 }
 };
 
-int __init 
-parport_gsc_init ( void )
+int __init parport_gsc_init(void)
 {
 	parport_count = 0;
 	
 	register_driver(parport_drivers_for);
 
-	return parport_count;
+	return 0;
 }
 
-/* Exported symbols. */
-EXPORT_NO_SYMBOLS;
-
 
-#ifdef MODULE
-
-MODULE_AUTHOR("Helge Deller <deller@gmx.de>");
-MODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver");
-MODULE_SUPPORTED_DEVICE("integrated PC-style parallel port");
-
-int init_module(void)
+static int __init parport_gsc_init_module(void)
 {	
-	return !parport_gsc_init ();
+	return !parport_gsc_init();
 }
 
-void cleanup_module(void)
+static void __exit parport_gsc_exit_module(void)
 {
 	struct parport *p = parport_enumerate(), *tmp;
 	while (p) {
@@ -569,4 +549,8 @@
 		p = tmp;
 	}
 }
-#endif
+
+EXPORT_NO_SYMBOLS;
+
+module_init(parport_gsc_init_module);
+module_exit(parport_gsc_exit_module);
diff -u --recursive --new-file v2.4.2/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.4.2/linux/drivers/parport/parport_pc.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/parport/parport_pc.c	Fri Mar  2 18:43:08 2001
@@ -89,6 +89,7 @@
 } superios[NR_SUPERIOS] __devinitdata = { {0,},};
 
 static int user_specified __devinitdata = 0;
+static int registered_parport;
 
 /* frob_control, but for ECR */
 static void frob_econtrol (struct parport *pb, unsigned char m,
@@ -2605,8 +2606,10 @@
 	count += parport_pc_find_nonpci_ports (autoirq, autodma);
 
 	r = pci_register_driver (&parport_pc_pci_driver);
-	if (r > 0)
+	if (r >= 0) {
+		registered_parport = 1;
 		count += r;
+	}
 
 	return count;
 }
@@ -2667,6 +2670,7 @@
 	/* Work out how many ports we have, then get parport_share to parse
 	   the irq values. */
 	unsigned int i;
+	int ret;
 	for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
 	if (i) {
 		if (parport_parse_irqs(i, irq, irqval)) return 1;
@@ -2691,7 +2695,11 @@
 			}
 	}
 
-	return !parport_pc_init (io, io_hi, irqval, dmaval);
+	ret = !parport_pc_init (io, io_hi, irqval, dmaval);
+	if (ret && registered_parport)
+		pci_unregister_driver (&parport_pc_pci_driver);
+
+	return ret;
 }
 
 void cleanup_module(void)
diff -u --recursive --new-file v2.4.2/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.4.2/linux/drivers/pci/pci.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/pci/pci.c	Tue Mar  6 22:44:15 2001
@@ -39,10 +39,12 @@
 /**
  * pci_find_slot - locate PCI device from a given PCI slot
  * @bus: number of PCI bus on which desired PCI device resides
- * @devfn:  number of PCI slot in which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI 
+ * device resides and the logical device number within that slot 
+ * in case of multi-function devices.
  *
- * Given a PCI bus and slot number, the desired PCI device is
- * located in system global list of PCI devices.  If the device
+ * Given a PCI bus and slot/function number, the desired PCI device 
+ * is located in system global list of PCI devices.  If the device
  * is found, a pointer to its data structure is returned.  If no 
  * device is found, %NULL is returned.
  */
@@ -58,7 +60,20 @@
 	return NULL;
 }
 
-
+/**
+ * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * device structure is returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
 struct pci_dev *
 pci_find_subsys(unsigned int vendor, unsigned int device,
 		unsigned int ss_vendor, unsigned int ss_device,
@@ -82,15 +97,14 @@
 /**
  * pci_find_device - begin or continue searching for a PCI device by vendor/device id
  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
  * @from: Previous PCI device found in search, or %NULL for new search.
  *
  * Iterates through the list of known PCI devices.  If a PCI device is
  * found with a matching @vendor and @device, a pointer to its device structure is
  * returned.  Otherwise, %NULL is returned.
- *
  * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not null, searches continue from that point.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
  */
 struct pci_dev *
 pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
@@ -107,9 +121,9 @@
  * Iterates through the list of known PCI devices.  If a PCI device is
  * found with a matching @class, a pointer to its device structure is
  * returned.  Otherwise, %NULL is returned.
- *
  * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not null, searches continue from that point.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
  */
 struct pci_dev *
 pci_find_class(unsigned int class, const struct pci_dev *from)
@@ -125,7 +139,28 @@
 	return NULL;
 }
 
-
+/**
+ * pci_find_capability - query for devices' capabilities 
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Tell if a device supports a given PCI capability.
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.  Possible values for @cap:
+ *
+ *  %PCI_CAP_ID_PM           Power Management 
+ *
+ *  %PCI_CAP_ID_AGP          Accelerated Graphics Port 
+ *
+ *  %PCI_CAP_ID_VPD          Vital Product Data 
+ *
+ *  %PCI_CAP_ID_SLOTID       Slot Identification 
+ *
+ *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
+ *
+ *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
+ */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
 {
@@ -274,12 +309,93 @@
 	return pin;
 }
 
+/**
+ *	pci_release_regions - Release reserved PCI I/O and memory resources
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_regions
+ *
+ *	Releases all PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_regions.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+void pci_release_regions(struct pci_dev *pdev)
+{
+	int i;
+	
+	for (i = 0; i < 6; i++) {
+		if (pci_resource_len(pdev, i) == 0)
+			continue;
+
+		if (pci_resource_flags(pdev, i) & IORESOURCE_IO)
+			release_region(pci_resource_start(pdev, i),
+				       pci_resource_len(pdev, i));
+
+		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
+			release_mem_region(pci_resource_start(pdev, i),
+					   pci_resource_len(pdev, i));
+	}
+}
+
+/**
+ *	pci_request_regions - Reserved PCI I/O and memory resources
+ *	@pdev: PCI device whose resources are to be reserved
+ *
+ *	Mark all PCI regions associated with PCI device @pdev as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_regions(struct pci_dev *pdev, char *res_name)
+{
+	int i;
+	
+	for (i = 0; i < 6; i++) {
+		if (pci_resource_len(pdev, i) == 0)
+			continue;
+
+		if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
+			if (!request_region(pci_resource_start(pdev, i),
+					    pci_resource_len(pdev, i), res_name))
+				goto err_out;
+		}
+		
+		else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+			if (!request_mem_region(pci_resource_start(pdev, i),
+					        pci_resource_len(pdev, i), res_name))
+				goto err_out;
+		}
+	}
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem",
+		i + 1, /* PCI BAR # */
+		pci_resource_len(pdev, i), pci_resource_start(pdev, i),
+		pdev->slot_name);
+	pci_release_regions(pdev);
+	return -EBUSY;
+}
+
+
 /*
  *  Registration of PCI drivers and handling of hot-pluggable devices.
  */
 
 static LIST_HEAD(pci_drivers);
 
+/**
+ * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ * 
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ */
 const struct pci_device_id *
 pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
 {
@@ -320,6 +436,15 @@
 	return ret;
 }
 
+/**
+ * pci_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
 int
 pci_register_driver(struct pci_driver *drv)
 {
@@ -334,6 +459,16 @@
 	return count;
 }
 
+/**
+ * pci_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PCI drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
@@ -395,6 +530,13 @@
 	call_usermodehelper (argv [0], argv, envp);
 }
 
+/**
+ * pci_insert_device - insert a hotplug device
+ * @dev: the device to insert
+ * @bus: where to insert it
+ *
+ * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ */
 void
 pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
 {
@@ -427,6 +569,13 @@
 	}
 }
 
+/**
+ * pci_remove_device - remove a hotplug device
+ * @dev: the device to remove
+ *
+ * Delete the device structure from the device lists and 
+ * notify userspace (/sbin/hotplug).
+ */
 void
 pci_remove_device(struct pci_dev *dev)
 {
@@ -452,6 +601,13 @@
 	name: "compat"
 };
 
+/**
+ * pci_dev_driver - get the pci_driver of a device
+ * @dev: the device to query
+ *
+ * Returns the appropriate pci_driver structure or %NULL if there is no 
+ * registered driver for the device.
+ */
 struct pci_driver *
 pci_dev_driver(const struct pci_dev *dev)
 {
@@ -503,7 +659,13 @@
 PCI_OP(write, word, u16)
 PCI_OP(write, dword, u32)
 
-
+/**
+ * pci_set_master - enables bus-mastering for device dev
+ * @dev: the PCI device to enable
+ *
+ * Enables bus-mastering on the device and calls pcibios_set_master()
+ * to do the needed arch specific settings.
+ */
 void
 pci_set_master(struct pci_dev *dev)
 {
@@ -518,6 +680,18 @@
 	pcibios_set_master(dev);
 }
 
+int
+pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask)
+{
+    if(! pci_dma_supported(dev, mask))
+        return -EIO;
+
+    dev->dma_mask = mask;
+
+    return 0;
+}
+    
+
 /*
  * Translate the low bits of the PCI base
  * to the resource type
@@ -837,8 +1011,15 @@
 	dev->irq = irq;
 }
 
-/*
- * Fill in class and map information of a device
+/**
+ * pci_setup_device - fill in class and map information of a device
+ * @dev: the device structure to fill
+ *
+ * Initialize the device structure with information about the device's 
+ * vendor,class,memory and IO-space addresses,IRQ lines etc.
+ * Called at initialisation of the PCI subsystem and by CardBus services.
+ * Returns 0 on success and -1 if unknown type of device (not normal, bridge
+ * or CardBus).
  */
 int pci_setup_device(struct pci_dev * dev)
 {
@@ -1201,11 +1382,14 @@
 EXPORT_SYMBOL(pci_root_buses);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pci_find_capability);
+EXPORT_SYMBOL(pci_release_regions);
+EXPORT_SYMBOL(pci_request_regions);
 EXPORT_SYMBOL(pci_find_class);
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_slot);
 EXPORT_SYMBOL(pci_find_subsys);
 EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_set_dma_mask);
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_register_driver);
diff -u --recursive --new-file v2.4.2/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids
--- v2.4.2/linux/drivers/pci/pci.ids	Tue Jan  2 16:58:45 2001
+++ linux/drivers/pci/pci.ids	Tue Mar  6 19:34:25 2001
@@ -85,6 +85,7 @@
 		1de1 3904  DC390F Ultra Wide SCSI Controller
 	0012  53c895a
 	0020  53c1010 Ultra3 SCSI Adapter
+	0021  53c1010 66MHz  Ultra3 SCSI Adapter
 	008f  53c875J
 		1092 8000  FirePort 40 SCSI Controller
 		1092 8760  FirePort 40 Dual SCSI Host Adapter
@@ -1259,7 +1260,7 @@
 109e  Brooktree Corporation
 	0350  Bt848 TV with DMA push
 	0351  Bt849A Video capture
-	036c  Bt879(??) Video Capture
+	036c  Bt879(?) Video Capture
 		13e9 0070  Win/TV (Video Section)
 	036e  Bt878
 		0070 13eb  WinTV/GO
@@ -3936,7 +3937,7 @@
 # 1507  HTEC Ltd
 # Commented out because there are no known HTEC chips and 1507 is already
 # used by mistake by Motorola (see vendor ID 1057)
-1507  Motorola ?? / HTEC
+1507  Motorola ? / HTEC
 	0001  MPC105 [Eagle]
 	0002  MPC106 [Grackle]
 	0003  MPC8240 [Kahlua]
@@ -4254,7 +4255,7 @@
 270b  Xantel Corporation
 270f  Chaintech Computer Co. Ltd
 2711  AVID Technology Inc.
-2a15  3D Vision(???)
+2a15  3D Vision(?)
 3000  Hansol Electronics Inc.
 3142  Post Impression Systems.
 3388  Hint Corp
diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c
--- v2.4.2/linux/drivers/pcmcia/bulkmem.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/pcmcia/bulkmem.c	Tue Mar  6 19:28:32 2001
@@ -41,6 +41,7 @@
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
+#include <linux/proc_fs.h>
 
 #define IN_CARD_SERVICES
 #include <pcmcia/cs_types.h>
diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- v2.4.2/linux/drivers/pcmcia/cardbus.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/pcmcia/cardbus.c	Sat Mar  3 10:49:17 2001
@@ -288,7 +288,6 @@
 			if (res->flags)
 				pci_assign_resource(dev, r);
 		}
-		pci_enable_device(dev); /* XXX check return */
 
 		/* Does this function have an interrupt at all? */
 		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
@@ -297,6 +296,7 @@
 			pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
 		}
 
+		pci_enable_device(dev); /* XXX check return */
 		pci_insert_device(dev, bus);
 	}
 
diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.4.2/linux/drivers/pcmcia/i82365.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/pcmcia/i82365.c	Sat Mar  3 10:50:29 2001
@@ -210,13 +210,13 @@
 		  PCI_COMMAND_MASTER|PCI_COMMAND_WAIT)
 
 /* These definitions must match the pcic table! */
-typedef enum pcic_id {
 #ifdef CONFIG_ISA
+typedef enum pcic_id {
     IS_I82365A, IS_I82365B, IS_I82365DF,
     IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
     IS_PD6710, IS_PD672X, IS_VT83C469,
-#endif
 } pcic_id;
+#endif
 
 /* Flags for classifying groups of controllers */
 #define IS_VADEM	0x0001
diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- v2.4.2/linux/drivers/pcmcia/rsrc_mgr.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/pcmcia/rsrc_mgr.c	Tue Mar  6 19:28:32 2001
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
+#include <linux/proc_fs.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
@@ -251,7 +252,7 @@
 	   base, base+num-1);
     bad = fail = 0;
     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
-    for (i = base; i < base+num; i = j + step) {
+    for (i = j = base; i < base+num; i = j + step) {
 	if (!fail) {	
 	    for (j = i; j < base+num; j += step)
 		if ((check_mem_resource(j, step) == 0) && is_valid(j))
diff -u --recursive --new-file v2.4.2/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c
--- v2.4.2/linux/drivers/pcmcia/tcic.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/pcmcia/tcic.c	Tue Mar  6 19:28:32 2001
@@ -49,6 +49,7 @@
 #include <linux/timer.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/proc_fs.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
diff -u --recursive --new-file v2.4.2/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c
--- v2.4.2/linux/drivers/s390/char/tape34xx.c	Wed Feb 21 18:20:30 2001
+++ linux/drivers/s390/char/tape34xx.c	Fri Mar  2 11:12:07 2001
@@ -1437,7 +1437,7 @@
     debug_text_event (tape_debug_area,6,"xdefhandle");
 #endif /* TAPE_DEBUG */
 	tapestate_set (tape, TS_FAILED);
-	PRINT_ERR ("TAPE34XX: An unexpected Unit Check occured.\n");
+	PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
 	PRINT_ERR ("TAPE34XX: Please read Documentation/s390/TAPE and report it!\n");
 	PRINT_ERR ("TAPE34XX: Current state is: %s",
 		   (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ?
@@ -1804,7 +1804,7 @@
 		tape->wanna_wakeup=1;
 		wake_up (&tape->wq);
 	} else {
-		PRINT_ERR ("TAPE34XX: An unexpected Unit Check occured.\n");
+		PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
 		PRINT_ERR ("TAPE34XX: Please send the following 20 lines of output to cotte@de.ibm.com\n");
 		PRINT_ERR ("TAPE34XX: Current state is: %s",
 			   (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ?
diff -u --recursive --new-file v2.4.2/linux/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- v2.4.2/linux/drivers/s390/net/ctc.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/s390/net/ctc.c	Fri Mar  2 11:12:07 2001
@@ -884,7 +884,7 @@
                 if (sense & 0x01) 
                         printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name);
                 else 
-                        printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name);
+                        printk(KERN_DEBUG "%s: System reset occurred (remote side)\n", dev->name);
 #endif
         } else if (sense & 0x20) {
                 if (sense & 0x04)
diff -u --recursive --new-file v2.4.2/linux/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c
--- v2.4.2/linux/drivers/s390/net/netiucv.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/s390/net/netiucv.c	Tue Mar  6 19:44:37 2001
@@ -65,9 +65,6 @@
 MODULE_PARM_DESC (iucv,
 		  "Specify the userids associated with iucv0-iucv9:\n"
 		  "iucv=userid1,userid2,...,userid10\n");
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
diff -u --recursive --new-file v2.4.2/linux/drivers/s390/s390mach.c linux/drivers/s390/s390mach.c
--- v2.4.2/linux/drivers/s390/s390mach.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/s390/s390mach.c	Fri Mar  2 11:12:07 2001
@@ -139,7 +139,7 @@
 #endif
 
 	memcpy( &mcic,
-	        &S390_lowcore.mcck_interuption_code,
+	        &S390_lowcore.mcck_interruption_code,
 	        sizeof(__u64));
  		
 	if ( mcic.mcc.mcd.cp )	// CRW pending ?
diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.4.2/linux/drivers/sbus/char/aurora.c	Mon Dec 11 12:37:03 2000
+++ linux/drivers/sbus/char/aurora.c	Tue Mar  6 19:44:37 2001
@@ -1942,7 +1942,7 @@
 	change_speed = ((port->flags & ASYNC_SPD_MASK) !=
 			(tmp.flags & ASYNC_SPD_MASK));
 	
-	if (!suser()) {
+	if (!capable(CAP_SYS_ADMIN)) {
 		if ((tmp.close_delay != port->close_delay) ||
 		    (tmp.closing_wait != port->closing_wait) ||
 		    ((tmp.flags & ~ASYNC_USR_MASK) !=
diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c
--- v2.4.2/linux/drivers/sbus/char/flash.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/sbus/char/flash.c	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.22 2001/02/13 01:17:00 davem Exp $
+/* $Id: flash.c,v 1.23 2001/03/02 06:32:40 davem Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -106,12 +106,17 @@
 	   size_t count, loff_t *ppos)
 {
 	unsigned long p = file->f_pos;
+	int i;
 	
 	if (count > flash.read_size - p)
 		count = flash.read_size - p;
 
-	if (copy_to_user(buf, flash.read_base + p, count) < 0)
-		return -EFAULT;
+	for (i = 0; i < count; i++) {
+		u8 data = readb(flash.read_base + p + i);
+		if (put_user(data, buf))
+			return -EFAULT;
+		buf++;
+	}
 
 	file->f_pos += count;
 	return count;
diff -u --recursive --new-file v2.4.2/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.4.2/linux/drivers/sbus/char/vfc_dev.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/sbus/char/vfc_dev.c	Tue Mar  6 22:44:16 2001
@@ -362,7 +362,7 @@
 		vfc_capture_poll(dev);
 		break;
 	case DIAGMODE:
-		if(suser()) {
+		if(capable(CAP_SYS_ADMIN)) {
 			vfc_lock_device(dev);
 			dev->control_reg |= VFC_CONTROL_DIAGMODE;
 			sbus_writel(dev->control_reg, &dev->regs->control);
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c
--- v2.4.2/linux/drivers/scsi/3w-xxxx.c	Wed Nov  8 17:09:50 2000
+++ linux/drivers/scsi/3w-xxxx.c	Fri Mar  2 18:38:38 2001
@@ -5,7 +5,7 @@
    Modifications By: Joel Jacobson <linux@3ware.com>
    		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
-   Copyright (C) 1999-2000 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -67,6 +67,15 @@
                  systems.
    08/21/00    - release previously allocated resources on failure at
                  tw_allocate_memory (acme)
+   1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when
+                 controller status is non-zero.
+                 Added handling of request_sense opcode.
+                 Fix possible null pointer dereference in 
+                 tw_reset_device_extension()
+   1.02.00.004 - Add support for device id of 3ware 7000 series controllers.
+                 Make tw_setfeature() call with interrupts disabled.
+                 Register interrupt handler before enabling interrupts.
+                 Clear attention interrupt before draining aen queue.
 */
 
 #include <linux/module.h>
@@ -112,7 +121,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.002";
+char *tw_driver_version="1.02.00.004";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -581,174 +590,179 @@
 	struct pci_dev *tw_pci_dev = NULL;
 	u32 status_reg_value;
 	unsigned char c = 1;
+	int i;
+	u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
-	while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) {
-		if (pci_enable_device(tw_pci_dev))
-			continue;
-		/* Prepare temporary device extension */
-		tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
-		if (tw_dev == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
-			continue;
-		}
-		memset(tw_dev, 0, sizeof(TW_Device_Extension));
-
-		error = tw_initialize_device_extension(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
 
-		/* Calculate the cards register addresses */
-		tw_dev->registers.base_addr = pci_resource_start(tw_pci_dev, 0);
-		tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0);
-		tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
-		tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
-		tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
-		/* Save pci_dev struct to device extension */
-		tw_dev->tw_pci_dev = tw_pci_dev;
-
-		/* Poll status register for 60 secs for 'Controller Ready' flag */
-		if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Disable interrupts on the card */
-		tw_disable_interrupts(tw_dev);
-
-		while (tries < TW_MAX_RESET_TRIES) {
-			/* Do soft reset */
-			tw_soft_reset(tw_dev);
-
-			error = tw_aen_drain_queue(tw_dev);
-			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
-				tries++;
+	for (i=0;i<TW_NUMDEVICES;i++) {
+		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
+			if (pci_enable_device(tw_pci_dev))
+				continue;
+			/* Prepare temporary device extension */
+			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
+			if (tw_dev == NULL) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
 				continue;
 			}
+			memset(tw_dev, 0, sizeof(TW_Device_Extension));
 
-			/* Check for controller errors */
-			if (tw_check_errors(tw_dev)) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
-				tries++;
+			error = tw_initialize_device_extension(tw_dev);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
 
-			/* Empty the response queue */
-			error = tw_empty_response_que(tw_dev);
-			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
-				tries++;
+			/* Calculate the cards register addresses */
+			tw_dev->registers.base_addr = pci_resource_start(tw_pci_dev, 0);
+			tw_dev->registers.control_reg_addr = pci_resource_start(tw_pci_dev, 0);
+			tw_dev->registers.status_reg_addr = pci_resource_start(tw_pci_dev, 0) + 0x4;
+			tw_dev->registers.command_que_addr = pci_resource_start(tw_pci_dev, 0) + 0x8;
+			tw_dev->registers.response_que_addr = pci_resource_start(tw_pci_dev, 0) + 0xC;
+			/* Save pci_dev struct to device extension */
+			tw_dev->tw_pci_dev = tw_pci_dev;
+
+			/* Poll status register for 60 secs for 'Controller Ready' flag */
+			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
 
-			/* Now the controller is in a good state */
-			break;
-		}
+			/* Disable interrupts on the card */
+			tw_disable_interrupts(tw_dev);
+			
+			while (tries < TW_MAX_RESET_TRIES) {
+				/* Do soft reset */
+				tw_soft_reset(tw_dev);
+			  
+				error = tw_aen_drain_queue(tw_dev);
+				if (error) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
+					tries++;
+					continue;
+				}
 
-		if (tries >= TW_MAX_RESET_TRIES) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
+				/* Check for controller errors */
+				if (tw_check_errors(tw_dev)) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
+					tries++;
+					continue;
+				}
 
-		/* Make sure that io region isn't already taken */
-		if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
-				(tw_dev->tw_pci_dev->resource[0].start), 
-				(tw_dev->tw_pci_dev->resource[0].start) + 
-				TW_IO_ADDRESS_RANGE, numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
+				/* Empty the response queue */
+				error = tw_empty_response_que(tw_dev);
+				if (error) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+
+				/* Now the controller is in a good state */
+				break;
+			}
+
+			if (tries >= TW_MAX_RESET_TRIES) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+
+			/* Make sure that io region isn't already taken */
+			if (check_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE)) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
+				       (tw_dev->tw_pci_dev->resource[0].start), 
+				       (tw_dev->tw_pci_dev->resource[0].start) + 
+				       TW_IO_ADDRESS_RANGE, numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
     
-		/* Reserve the io address space */
-		request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
-		error = tw_initialize_units(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
-			release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
+			/* Reserve the io address space */
+			request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
+			error = tw_initialize_units(tw_dev);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
 
-		error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
-			release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
+			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
 
-		/* Calculate max cmds per lun */
-		if (tw_dev->num_units > 0)
-			tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
+			/* Calculate max cmds per lun */
+			if (tw_dev->num_units > 0)
+				tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
 
 		/* Register the card with the kernel SCSI layer */
-		host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-		if( host == NULL)
-		{
-			release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
+			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
+			if( host == NULL)
+			{
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
 
-		status_reg_value = inl(tw_dev->registers.status_reg_addr);
+			status_reg_value = inl(tw_dev->registers.status_reg_addr);
 
-		dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
+			dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
 				(u32)(tw_pci_dev->resource[0].start), tw_pci_dev->irq, 
 				(status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, 
 				(status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24);
 
-		if (host->hostdata) {
-			tw_dev2 = (TW_Device_Extension *)host->hostdata;
-			memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
-			tw_device_extension_list[tw_device_extension_count] = tw_dev2;
-			numcards++;
-			tw_device_extension_count = numcards;
-			tw_dev2->host = host;
-		} else { 
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
-			scsi_unregister(host);
-			release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-    
-		/* Re-enable interrupts on the card */
-		tw_enable_interrupts(tw_dev2);
+			if (host->hostdata) {
+				tw_dev2 = (TW_Device_Extension *)host->hostdata;
+				memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+				tw_device_extension_list[tw_device_extension_count] = tw_dev2;
+				numcards++;
+				tw_device_extension_count = numcards;
+				tw_dev2->host = host;
+			} else { 
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
 
-		/* Now setup the interrupt handler */
-		error = tw_setup_irq(tw_dev2);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
-			scsi_unregister(host);
-			release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
-
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			numcards--;
-			continue;
-		}
+			/* Tell the firmware we support shutdown notification*/
+			tw_setfeature(tw_dev2, 2, 1, &c);
 
-		/* Free the temporary device extension */
-		if (tw_dev)
-			kfree(tw_dev);
+			/* Now setup the interrupt handler */
+			error = tw_setup_irq(tw_dev2);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
+
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				numcards--;
+				continue;
+			}
 
-		/* Tell the firmware we support shutdown notification*/
-		tw_setfeature(tw_dev2, 2, 1, &c);
+			/* Re-enable interrupts on the card */
+			tw_enable_interrupts(tw_dev2);
+
+			/* Free the temporary device extension */
+			if (tw_dev)
+				kfree(tw_dev);
+		}
 	}
 
 	if (numcards == 0) 
@@ -1089,15 +1103,14 @@
 		/* Handle attention interrupt */
 		if (do_attention_interrupt) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
+			tw_clear_attention_interrupt(tw_dev);
 			tw_state_request_start(tw_dev, &request_id);
 			error = tw_aen_read_queue(tw_dev, request_id);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n");
 				tw_dev->state[request_id] = TW_S_COMPLETED;
 				tw_state_request_finish(tw_dev, request_id);
-			} else {
-				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
-				tw_clear_attention_interrupt(tw_dev);
 			}
 		}
 
@@ -1133,13 +1146,15 @@
 				response_que.value = inl(response_que_addr);
 				request_id = response_que.u.response_id;
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+				error = 0;
 				if (command_packet->status != 0) {
-					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
+					error = 1;
 				}
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode);
+					error = 1;
 				}
-				error = 0;
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 				/* Check for internal command */
 				if (tw_dev->srb[request_id] == 0) {
@@ -1183,8 +1198,8 @@
 					}
 					if (error) {
 						/* Tell scsi layer there was an error */
-						printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
-						tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
+						tw_dev->srb[request_id]->result = (DID_RESET << 16);
 					} else {
 						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
@@ -1467,8 +1482,11 @@
 		    (tw_dev->state[i] != TW_S_INITIAL) &&
 		    (tw_dev->state[i] != TW_S_COMPLETED)) {
 			srb = tw_dev->srb[i];
-			srb->result = (DID_RESET << 16);
-			tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+			if (srb != NULL) {
+				srb = tw_dev->srb[i];
+				srb->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+			}
 		}
 	}
 
@@ -1573,6 +1591,8 @@
 /* This function will find and initialize any cards */
 int tw_scsi_detect(Scsi_Host_Template *tw_host)
 {
+	int ret;
+	
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n");
 
 	/* Check if the kernel has PCI interface compiled in */
@@ -1581,7 +1601,11 @@
 		return 0;
 	}
 
-	return(tw_findcards(tw_host));
+	spin_unlock_irq(&io_request_lock);
+	ret = tw_findcards(tw_host);
+	spin_lock_irq(&io_request_lock);
+	
+	return ret;
 } /* End tw_scsi_detect() */
 
 /* This is the new scsi eh abort function */
@@ -1812,6 +1836,10 @@
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
 			error = tw_scsiop_read_capacity(tw_dev, request_id);
 			break;
+	        case REQUEST_SENSE:
+		        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
+		        error = tw_scsiop_request_sense(tw_dev, request_id);
+		        break;
 		case TW_IOCTL:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
 			error = tw_ioctl(tw_dev, request_id);
@@ -2166,6 +2194,23 @@
 
 	return 0;
 } /* End tw_scsiop_read_write() */
+
+/* This function will handle the request sense scsi command */
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+  
+       /* For now we just zero the sense buffer */
+       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+       tw_dev->state[request_id] = TW_S_COMPLETED;
+       tw_state_request_finish(tw_dev, request_id);
+  
+       /* If we got a request_sense, we probably want a reset, return error */
+       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+  
+       return 0;
+} /* End tw_scsiop_request_sense() */
 
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h
--- v2.4.2/linux/drivers/scsi/3w-xxxx.h	Mon Dec 11 13:19:49 2000
+++ linux/drivers/scsi/3w-xxxx.h	Fri Mar  2 18:38:38 2001
@@ -3,8 +3,9 @@
    
    Written By: Adam Radford <linux@3ware.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
+   		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
-   Copyright (C) 1999 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -97,6 +98,8 @@
 #define TW_DEVICE_NAME			       "3ware Storage Controller"
 #define TW_VENDOR_ID (0x13C1)	/* 3ware */
 #define TW_DEVICE_ID (0x1000)	/* Storage Controller */
+#define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
+#define TW_NUMDEVICES 2
 
 /* Command packet opcodes */
 #define TW_OP_NOP	      0x0
@@ -289,7 +292,7 @@
 	unsigned short		aen_queue[TW_Q_LENGTH];
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
-	u32			flags;
+	long			flags; /* long req'd for set_bit --RR */
 } TW_Device_Extension;
 
 /* Function prototypes */
@@ -328,6 +331,7 @@
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, 
 		  unsigned char *val);
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- v2.4.2/linux/drivers/scsi/AM53C974.c	Sun Nov 12 20:40:42 2000
+++ linux/drivers/scsi/AM53C974.c	Fri Mar  2 18:38:38 2001
@@ -676,6 +676,10 @@
 #endif
 
 	instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata));
+	if (!instance) {
+		printk(KERN_WARNING "AM53C974: Unable to register host, aborting.\n");
+		return 0;
+	}
 	hostdata = (struct AM53C974_hostdata *) instance->hostdata;
 	instance->base = 0;
 	instance->io_port = pci_resource_start(pdev, 0);
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.4.2/linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon Jun 19 17:59:41 2000
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Tue Mar  6 19:34:25 2001
@@ -1,3 +1,35 @@
+Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.3
+	- Call pci_enable_device() as AC wants this to be done.
+	- Get both the BAR cookies actual and PCI BAR values.
+	  (see Changelog.sym53c8xx rev. 1.7.3 for details)
+	- Merge changes for linux-2.4 that declare the host template 
+	  in the driver object also when the driver is statically 
+	  linked with the kernel.
+
+Sun Sep 24 21:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.2
+	- See Changelog.sym53c8xx, driver version 1.7.2.
+
+Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.1
+	- Provide OpenFirmare path through the proc FS on PPC.
+	- Remove trailing argument #2 from a couple of #undefs.
+
+Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.0
+	- Remove the PROFILE C and SCRIPTS code.
+	  This facility was not this useful and thus was not longer 
+	  desirable given the increasing complexity of the driver code.
+	- Merges from FreeBSD sym-1.6.2 driver:
+	  * Clarify memory barriers needed by the driver for architectures 
+	    that implement a weak memory ordering.
+	- General cleanup:
+	  Move definitions for barriers and IO/MMIO operations to the 
+	  sym53c8xx_defs.h header files. They are now shared by the 
+	  both drivers.
+	  Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED.
+
 Thu May 11   12:30 2000 Pam Delaney (pam.delaney@lsil.com)
 	* revision 3.3b
  
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx
--- v2.4.2/linux/drivers/scsi/ChangeLog.sym53c8xx	Mon Jun 19 17:59:41 2000
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Tue Mar  6 19:34:25 2001
@@ -1,3 +1,92 @@
+Sun Mar 4 18:30 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.3a
+	- Fix an issue in the ncr_int_udc() (unexpected disconnect)
+	  handling. If the DSA didn't match a CCB, a bad write to 
+	  memory could happen.
+
+Mon Feb 12 22:30 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.3
+	- Support for hppa.
+	  Tiny patch sent to me by Robert Hirst.
+	- Tiny patch for ia64 sent to me by Pamela Delaney.
+
+Tue Feb 6 13:30 2001 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.3-pre1
+	- Call pci_enable_device() as AC wants this to be done.
+	- Get both the BAR cookies used by CPU and actual PCI BAR 
+	  values used from SCRIPTS. Recent PCI chips are able to 
+	  access themselves using internal cycles, but they compare 
+	  BAR values to destination address to make decision.
+	  Earlier chips simply use PCI transactions to access IO 
+	  registers from SCRIPTS.
+	  The bus_dvma_to_mem() interface that reverses the actual 
+	  PCI BAR value from the BAR cookie is now useless.
+	  This point had been discussed at the list and the solution 
+	  got approved by PCI code maintainer (Martin Mares).
+	- Merge changes for linux-2.4 that declare the host template 
+	  in the driver object also when the driver is statically 
+	  linked with the kernel.
+	- Increase SCSI message size up to 12 bytes, given that 8 
+	  bytes was not enough for the PPR message (fix).
+	- Add field 'maxoffs_st' (max offset for ST data transfers).
+	  The C1010 supports offset 62 in DT mode but only 31 in 
+	  ST mode, to 2 different values for the max SCSI offset 
+	  are needed. Replace the obviously wrong masking of the 
+	  offset against 0x1f for ST mode by a lowering to 
+	  maxoffs_st of the SCSI offset in ST mode.
+	- Refine a work-around for the C1010-66. Revision 1 does 
+	  not requires extra cycles in DT DATA OUT phase.
+	- Add a missing endian-ization (abrt_tbl.addr).
+	- Minor clean-up in the np structure for fields accessed 
+	  from SCRIPTS that requires special alignments.
+
+Sun Sep 24 21:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.2
+	- Remove the hack for PPC added in previous driver version.
+	- Add FE_DAC feature bit to distinguish between 64 bit PCI 
+	  addressing (FE_DAC) and 64 bit PCI interface (FE_64BIT).
+	- Get rid of the boot command line "ultra:" argument.
+	  This parameter wasn't that clever since we can use "sync:" 
+	  for Ultra/Ultra2 settings, and for Ultra3 we may want to 
+	  pass PPR options (for now only DT clocking).
+	- Add FE_VARCLK feature bit that indicates that SCSI clock 
+	  frequency may vary depending on board design and thus, 
+	  the driver should try to evaluate the SCSI clock.
+	- Simplify the way the driver determine the SCSI clock:
+	  ULTRA3 -> 160 MHz, ULTRA2 -> 80 MHz otherwise 40 MHz.
+	  Measure the SCSI clock frequency if FE_VARCLK is set.
+	- Remove FE_CLK80 feature bit that got useless.
+	- Add support for the SYM53C875A (Pamela Delaney).
+
+Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.1
+	- Provide OpenFirmare path through the proc FS on PPC.
+	- Download of on-chip SRAM using memcpy_toio() doesn't work 
+	  on PPC. Restore previous method (MEMORY MOVE from SCRIPTS).
+	- Remove trailing argument #2 from a couple of #undefs.
+
+Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.0
+	- Remove the PROFILE C and SCRIPTS code.
+	  This facility was not this useful and thus was not longer 
+	  desirable given the increasing complexity of the driver code.
+	- Merges from FreeBSD sym-1.6.2 driver:
+	  * Clarify memory barriers needed by the driver for architectures 
+	    that implement a weak memory ordering.
+	  * Simpler handling of illegal phases and data overrun from 
+	    SCRIPTS. These errors are now immediately reported to 
+	    the C code by an interrupt.
+	  * Sync the residual handling code with sym-1.6.2 and now 
+	    report `resid' to user for linux version >= 2.3.99 
+	- General cleanup:
+	  Move definitions for barriers and IO/MMIO operations to the 
+	  sym53c8xx_defs.h header files. They are now shared by the 
+	  both drivers.
+	  Remove unused options that claimed to optimize for the 896.
+	  If fact, they were not this clever. :)
+	  Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED.
+	  Remove a couple of unused fields from data structures.
+
 Thu May 11 12:40 2000 Pam Delaney (pam.delaney@lsil.com)
 	* version sym53c8xx-1.6b
 	- Merged version.
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.4.2/linux/drivers/scsi/Config.in	Sat Dec 30 18:38:37 2000
+++ linux/drivers/scsi/Config.in	Sun Mar  4 14:30:18 2001
@@ -50,12 +50,14 @@
 dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
-dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
-if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
-   bool '  Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
-   int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
-   bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
-   int  '  Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
+source drivers/scsi/aic7xxx/Config.in
+if [ "$CONFIG_SCSI_AIC7XXX" != "y" ]; then
+   dep_tristate 'Old Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX_OLD $CONFIG_SCSI
+   if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "n" ]; then
+      bool '  Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+      int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE 8
+      bool '  Collect statistics to report in /proc' CONFIG_AIC7XXX_OLD_PROC_STATS
+   fi
 fi
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.4.2/linux/drivers/scsi/Makefile	Sat Dec 30 11:23:14 2000
+++ linux/drivers/scsi/Makefile	Tue Mar  6 19:44:37 2001
@@ -14,6 +14,8 @@
 MOD_IN_SUB_DIRS	:=
 ALL_SUB_DIRS	:= $(SUB_DIRS) pcmcia
 
+subdir-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx
+
 ifeq ($(CONFIG_PCMCIA),y)
   SUB_DIRS += pcmcia
   MOD_IN_SUB_DIRS += pcmcia
@@ -63,7 +65,7 @@
 obj-$(CONFIG_SCSI_AHA152X)	+= aha152x.o
 obj-$(CONFIG_SCSI_AHA1542)	+= aha1542.o
 obj-$(CONFIG_SCSI_AHA1740)	+= aha1740.o
-obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx.o
+obj-$(CONFIG_SCSI_AIC7XXX_OLD)	+= aic7xxx_old.o
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
 obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
 obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
@@ -112,14 +114,18 @@
 obj-$(CONFIG_SCSI_DEBUG)	+= scsi_debug.o
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 
+ifeq ($(CONFIG_ARCH_ACORN),y)
+mod-subdirs	+= ../acorn/scsi
+subdir-y	+= ../acorn/scsi
+obj-y		+= ../acorn/scsi/acorn-scsi.o
+endif
+
 obj-$(CONFIG_CHR_DEV_ST)	+= st.o
 obj-$(CONFIG_CHR_DEV_OSST)	+= osst.o
 obj-$(CONFIG_BLK_DEV_SD)	+= sd_mod.o
 obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 
-
-
 scsi_mod-objs	:= scsi.o hosts.o scsi_ioctl.o constants.o \
 			scsicam.o scsi_proc.o scsi_error.o \
 			scsi_obsolete.o scsi_queue.o scsi_lib.o \
@@ -147,7 +153,6 @@
 
 a100u2w.o: $(a100u2w-objs)
 	$(LD) -r -o $@ $(a100u2w-objs)
-
 
 53c8xx_d.h: 53c7,8xx.scr script_asm.pl
 	ln -sf 53c7,8xx.scr fake8.c
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/NCR53C9x.c linux/drivers/scsi/NCR53C9x.c
--- v2.4.2/linux/drivers/scsi/NCR53C9x.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/scsi/NCR53C9x.c	Tue Mar  6 19:44:37 2001
@@ -1820,7 +1820,7 @@
 		 * with ESP_CMD_DMA ...
 		 */
 
-		/* figure out how much needs to be transfered */
+		/* figure out how much needs to be transferred */
 		hmuch = SCptr->SCp.this_residual;
 		ESPDATA(("hmuch<%d> pio ", hmuch));
 		esp->current_transfer_size = hmuch;
@@ -1942,18 +1942,18 @@
 			/* check int. status */
 			if (esp->ireg & ESP_INTR_DC) {
 				/* disconnect */
-				ESPDATA(("disconnect; %d transfered ... ", i));
+				ESPDATA(("disconnect; %d transferred ... ", i));
 				break;
 			} else if (esp->ireg & ESP_INTR_FDONE) {
 				/* function done */
-				ESPDATA(("function done; %d transfered ... ", i));
+				ESPDATA(("function done; %d transferred ... ", i));
 				break;
 			}
 
 			/* XXX fixme: bail out on stall */
 			if (fifo_stuck > 10) {
 				/* we're stuck */
-				ESPDATA(("fifo stall; %d transfered ... ", i));
+				ESPDATA(("fifo stall; %d transferred ... ", i));
 				break;
 			}
 		}
@@ -1964,7 +1964,7 @@
 		if (thisphase == in_dataout)
 			hmuch += fifocnt; /* stuck?? adjust data pointer ...*/
 
-		/* tell do_data_finale how much was transfered */
+		/* tell do_data_finale how much was transferred */
 		esp->current_transfer_size -= hmuch;
 
 		/* still not completely sure on this one ... */		
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- v2.4.2/linux/drivers/scsi/NCR53c406a.c	Mon Sep 18 13:36:24 2000
+++ linux/drivers/scsi/NCR53c406a.c	Fri Mar  2 11:12:11 2001
@@ -184,13 +184,13 @@
 /* ================================================================= */
 
 #if USE_BIOS
-static void *bios_base = (void *)0;
+static void *bios_base;
 #endif
 
 #if PORT_BASE
 static int   port_base = PORT_BASE;
 #else
-static int   port_base = 0;
+static int   port_base;
 #endif
 
 #if IRQ_LEV
@@ -200,16 +200,16 @@
 #endif
 
 #if USE_DMA
-static int   dma_chan = 0;
+static int   dma_chan;
 #endif
 
 #if USE_PIO
 static int   fast_pio = USE_FAST_PIO;
 #endif
 
-static Scsi_Cmnd         *current_SC       = NULL;
-static volatile int internal_done_flag = 0;
-static volatile int internal_done_errcode = 0;
+static Scsi_Cmnd         *current_SC;
+static volatile int internal_done_flag;
+static volatile int internal_done_errcode;
 static char info_msg[256];
 
 /* ================================================================= */
@@ -484,17 +484,17 @@
 #endif USE_BIOS
     
 #ifdef PORT_BASE
-    if (check_region(port_base, 0x10)) /* ports already snatched */
+    if (!request_region(port_base, 0x10, "NCR53c406a")) /* ports already snatched */
         port_base = 0;
     
 #else  /* autodetect */
     if (port_base) {		/* LILO override */
-        if (check_region(port_base, 0x10))
+        if (!request_region(port_base, 0x10, "NCR53c406a"))
             port_base = 0;
     }
     else {
         for(i=0;  i<PORT_COUNT && !port_base; i++){
-            if(check_region(ports[i], 0x10)){
+            if(!request_region(ports[i], 0x10, "NCR53c406a")){
                 DEB(printk("NCR53c406a: port %x in use\n", ports[i]));
             }
             else {
@@ -503,9 +503,10 @@
                 if(   (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7
                    && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7
                    && (inb(ports[i] + 0x0e) & 0xf8) == 0x58 ) {
+                    port_base = ports[i];
                     VDEB(printk("NCR53c406a: Sig register valid\n"));
                     VDEB(printk("port_base=%x\n", port_base));
-                    port_base = ports[i];
+                    break;
                 }
             }
         }
@@ -527,18 +528,17 @@
         irq_level=irq_probe();
         if (irq_level < 0) {		/* Trouble */
             printk("NCR53c406a: IRQ problem, irq_level=%d, giving up\n", irq_level);
-            return 0;
+            goto err_release;
         }
     }
 #endif
     
     DEB(printk("NCR53c406a: using port_base %x\n", port_base));
-    request_region(port_base, 0x10, "NCR53c406a");
     
     if(irq_level > 0) {
         if(request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", NULL)){
             printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
-            return 0;
+            goto err_release;
         }
         tpnt->can_queue = 1;
         DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level));
@@ -548,19 +548,19 @@
         DEB(printk("NCR53c406a: No interrupts detected\n"));
 #if USE_DMA
         printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n");
-        return 0;
+        goto err_release;
 #endif USE_DMA
     }
     else {
         DEB(printk("NCR53c406a: Shouldn't get here!\n"));
-        return 0;
+        goto err_free_irq;
     }
     
 #if USE_DMA
     dma_chan = DMA_CHAN;
     if(request_dma(dma_chan, "NCR53c406a") != 0){
         printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan);
-        return 0;
+        goto err_release;
     }
     
     DEB(printk("Allocated DMA channel %d\n", dma_chan));
@@ -570,6 +570,10 @@
     tpnt->proc_name = "NCR53c406a";
     
     shpnt = scsi_register(tpnt, 0);
+    if (!shpnt) {
+            printk("NCR53c406a: Unable to register host, giving up.\n");
+            goto err_free_dma;
+    }
     shpnt->irq = irq_level;
     shpnt->io_port = port_base;
     shpnt->n_io_port = 0x10;
@@ -586,6 +590,17 @@
 #endif
     
     return (tpnt->present);
+
+
+ err_free_dma:
+#if USE_DMA
+    free_dma(dma_chan);
+#endif
+ err_free_irq:
+    free_irq(irq_level, do_NCR53c406a_intr);
+ err_release:
+    release_region(port_base, 0x10);
+    return 0;
 }
 
 /* called from init/main.c */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
--- v2.4.2/linux/drivers/scsi/README.aic7xxx	Thu Feb 10 19:00:35 2000
+++ linux/drivers/scsi/README.aic7xxx	Wed Dec 31 16:00:00 1969
@@ -1,511 +0,0 @@
-			    AIC7xxx Driver for Linux
-
-Introduction
-----------------------------
-The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
-SCSI controllers and chipsets. Major portions of the driver and driver
-development are shared between both Linux and FreeBSD. Support for the
-AIC-7xxx chipsets have been in the default Linux kernel since approximately
-linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
-2.1.0 or later.
-
-  Supported cards/chipsets
-  ----------------------------
-    Adaptec Cards
-    ----------------------------
-    AHA-274x
-    AHA-274xT               
-    AHA-2842
-    AHA-2910B               
-    AHA-2920C
-    AHA-2930
-    AHA-2930U
-    AHA-2930CU
-    AHA-2930U2
-    AHA-2940               
-    AHA-2940W              
-    AHA-2940U              
-    AHA-2940UW
-    AHA-2940UW-PRO
-    AHA-2940AU 
-    AHA-2940U2W
-    AHA-2940U2
-    AHA-2940U2B
-    AHA-2940U2BOEM
-    AHA-2944D              
-    AHA-2944WD
-    AHA-2944UD
-    AHA-2944UWD
-    AHA-2950U2
-    AHA-2950U2W
-    AHA-2950U2B
-    AHA-29160M
-    AHA-3940
-    AHA-3940U
-    AHA-3940W
-    AHA-3940UW
-    AHA-3940AUW
-    AHA-3940U2W
-    AHA-3950U2B
-    AHA-3950U2D
-    AHA-3960D
-    AHA-39160M
-    AHA-3985
-    AHA-3985U
-    AHA-3985W
-    AHA-3985UW
-
-    Motherboard Chipsets
-    ----------------------------
-    AIC-777x   
-    AIC-785x
-    AIC-786x
-    AIC-787x
-    AIC-788x
-    AIC-789x
-    AIC-3860
-
-    Bus Types
-    ----------------------------
-    W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
-        SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
-    U - Ultra SCSI, transfer rates up to 40MB/s.
-    U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
-    D - Differential SCSI.
-    T - Twin Channel SCSI. Up to 14 SCSI devices.
-
-    AHA-274x - EISA SCSI controller
-    AHA-284x - VLB SCSI controller
-    AHA-29xx - PCI SCSI controller
-    AHA-394x - PCI controllers with two separate SCSI controllers on-board.
-    AHA-398x - PCI RAID controllers with three separate SCSI controllers
-               on-board.
-
-  Not Supported Devices
-  ------------------------------
-    Adaptec Cards
-    ----------------------------
-    AHA-2920 (Only the cards that use the Future Domain chipset are not
-              supported, any 2920 cards based on Adaptec AIC chipsets,
-	      such as the 2920C, are supported)
-    AAA-13x Raid Adapters
-    AAA-113x Raid Port Card
-
-    Motherboard Chipsets
-    ----------------------------
-    AIC-7810
-
-    Bus Types
-    ----------------------------
-    R - Raid Port busses are not supported.
-
-    The hardware RAID devices sold by Adaptec are *NOT* supported by this
-    driver (and will people please stop emailing me about them, they are
-    a totally separate beast from the bare SCSI controllers and this driver
-    can not be retrofitted in any sane manner to support the hardware RAID
-    features on those cards - Doug Ledford).
-    
-
-  People
-  ------------------------------
-    Justin T Gibbs  gibbs@plutotech.com
-      (BSD Driver Author)
-    Dan Eischen     deischen@iworks.InterWorks.org
-      (Original Linux Driver Co-maintainer)
-    Dean Gehnert    deang@teleport.com
-      (Original Linux FTP/patch maintainer)
-    Jess Johnson    jester@frenzy.com
-      (AIC7xxx FAQ author)
-    Doug Ledford    dledford@redhat.com
-      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
-    
-    Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
-    author of the driver. John has since retired from the project. Thanks
-    again for all his work!
-    
-  Mailing list
-  ------------------------------
-    There is a mailing list available for users who want to track development
-    and converse with other users and developers. This list is for both
-    FreeBSD and Linux support of the AIC7xxx chipsets.
-
-    To subscribe to the AIC7xxx mailing list send mail to the list server,
-    with "subscribe AIC7xxx" in the body (no Subject: required):
-        To: majordomo@FreeBSD.ORG
-        ---
-        subscribe AIC7xxx
-
-    To unsubscribe from the list, send mail to the list server with:
-        To: majordomo@FreeBSD.ORG
-        ---
-        unsubscribe AIC7xxx
-
-    Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
-    
-  Boot Command line options
-  ------------------------------
-    "aic7xxx=no_reset" -  Eliminate the SCSI bus reset during startup.
-        Some SCSI devices need the initial reset that this option disables
-	in order to work.  If you have problems at bootup, please make sure
-	you aren't using this option.
-	
-    "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at
-        bootup by scanning from the highest numbered PCI device to the
-	lowest numbered PCI device, others do just the opposite and scan
-	from lowest to highest numbered PCI device.  There is no reliable
-	way to autodetect this ordering.  So, we default to the most common
-	order, which is lowest to highest.  Then, in case your motherboard
-	scans from highest to lowest, we have this option.  If your BIOS
-	finds the drives on controller A before controller B but the linux
-	kernel finds your drives on controller B before A, then you should
-	use this option.
-	
-    "aic7xxx=extended" - Force the driver to detect extended drive translation
-        on your controller.  This helps those people who have cards without
-        a SEEPROM make sure that linux and all other operating systems think
-        the same way about your hard drives.
-
-    "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
-        give the card more hardware SCB slots.  This allows the driver to use
-	that SCB RAM.  Without this option, the driver won't touch the SCB
-	RAM because it is known to cause problems on a few cards out there
-	(such as 3985 class cards).
-	
-    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
-        to use the correct IRQ type for your card.  This only applies to EISA
-        based controllers.  On these controllers, 0 is for Edge triggered
-        interrupts, and 1 is for Level triggered interrupts.  If you aren't
-        sure or don't know which IRQ trigger type your EISA card uses, then
-        let the kernel autodetect the trigger type.
-	
-    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
-        simply specify aic7xxx=verbose, then the kernel will automatically
-	pick the default set of verbose messages for you to see.
-	Alternatively, you can specify the command as 
-	"aic7xxx=verbose:0xXXXX" where the X entries are replaced with
-	hexadecimal digits.  This option is a bit field type option.  For
-	a full listing of the available options, search for the 
-	#define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want
-	verbose messages, then it is recommended that you simply use the
-	aic7xxx=verbose variant of this command.
-	
-    "aic7xxx=pci_parity:x" - This option controls whether or not the driver
-        enables PCI parity error checking on the PCI bus.  By default, this
-        checking is disabled.  To enable the checks, simply specify pci_parity
-        with no value afterwords.  To reverse the parity from even to odd,
-        supply any number other than 0 or 255.  In short:
-          pci_parity     - Even parity checking (even is the normal PCI parity)
-          pci_parity:x   - Where x > 0, Odd parity checking
-          pci_parity:0   - No check (default)
-        NOTE: In order to get Even PCI parity checking, you must use the
-        version of the option that does not include the : and a number at
-        the end (unless you want to enter exactly 2^32 - 1 as the number).
-	
-    "aic7xxx=no_probe" - This option will disable the probing for any VLB
-        based 2842 controllers and any EISA based controllers.  This is
-	needed on certain newer motherboards where the normal EISA I/O ranges
-	have been claimed by other PCI devices.  Probing on those machines
-	will often result in the machine crashing or spontaneously rebooting
-	during startup.  Examples of machines that need this are the
-	Dell PowerEdge 6300 machines.
-
-    "aic7xxx=seltime:2" - This option controls how long the card waits
-        during a device selection sequence for the device to respond.
-	The original SCSI spec says that this "should be" 256ms.  This
-	is generally not required with modern devices.  However, some
-	very old SCSI I devices need the full 256ms.  Most modern devices
-	can run fine with only 64ms.  The default for this option is
-	64ms.  If you need to change this option, then use the following
-	table to set the proper value in the example above:
-	  0  -  256ms
-	  1  -  128ms
-	  2  -   64ms
-	  3  -   32ms
-	
-    "aic7xxx=panic_on_abort" - This option is for debugging and will cause
-        the driver to panic the linux kernel and freeze the system the first
-	time the drivers abort or reset routines are called.  This is most
-	helpful when some problem causes infinite reset loops that scroll too
-	fast to see.  By using this option, you can write down what the errors
-	actually are and send that information to me so it can be fixed.
-	
-    "aic7xxx=dump_card" - This option will print out the *entire* set of
-        configuration registers on the card during the init sequence.  This
-	is a debugging aid used to see exactly what state the card is in
-	when we finally finish our initialization routines.  If you don't
-	have documentation on the chipsets, this will do you absolutely
-	no good unless you are simply trying to write all the information
-	down in order to send it to me.
-	
-    "aic7xxx=dump_sequencer" - This is the same as the above options except
-        that instead of dumping the register contents on the card, this
-	option dumps the contents of the sequencer program RAM.  This gives
-	the ability to verify that the instructions downloaded to the
-	card's sequencer are indeed what they are suppossed to be.  Again,
-	unless you have documentation to tell you how to interpret these
-	numbers, then it is totally useless.
-	
-    "aic7xxx=override_term:0xffffffff" - This option is used to force the
-    	termination on your SCSI controllers to a particular setting.  This
-	is a bit mask variable that applies for up to 8 aic7xxx SCSI channels.
-	Each channel gets 4 bits, divided as follows:
-	bit   3   2   1   0
-	      |   |   |   Enable/Disable Single Ended Low Byte Termination
-	      |   |   En/Disable Single Ended High Byte Termination
-	      |   En/Disable Low Byte LVD Termination
-	      En/Disable High Byte LVD Termination
-
-	The upper 2 bits that deal with LVD termination only apply to Ultra2
-	controllers.  Futhermore, due to the current Ultra2 controller
-	designs, these bits are tied together such that setting either bit
-	enables both low and high byte LVD termination.  It is not possible
-	to only set high or low byte LVD termination in this manner.  This is
-	an artifact of the BIOS definition on Ultra2 controllers.  For other
-	controllers, the only important bits are the two lowest bits.  Setting
-	the higher bits on non-Ultra2 controllers has no effect.  A few
-	examples of how to use this option:
-
-	Enable low and high byte termination on a non-ultra2 controller that
-	is the first aic7xxx controller (the correct bits are 0011), 
-	aic7xxx=override_term:0x3
-
-	Enable all termination on the third aic7xxx controller, high byte
-	termination on the second aic7xxx controller, and low and high byte
-	SE termination on the first aic7xxx controller 
-	(bits are 1111 0010 0011), 
-	aic7xxx=override_term:0xf23
-	
-	No attempt has been made to make this option non-cryptic.  It really
-	shouldn't be used except in dire circumstances, and if that happens,
-	I'm probably going to be telling you what to set this to anyway :)
-
-    "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV
-        bit in the DEVCONFIG PCI register.  Currently, this is one of the
-	very few registers that we have absolutely *no* way of detecting
-	what the variable should be.  It depends entirely on how the chipset
-	and external terminators were coupled by the card/motherboard maker.
-	Further, a chip reset (at power up) always sets this bit to 0.  If
-	there is no BIOS to run on the chipset/card (such as with a 2910C
-	or a motherboard controller with the BIOS totally disabled) then
-	the variable may not get set properly.  Of course, if the proper
-	setting was 0, then that's what it would be after the reset, but if
-	the proper setting is actually 1.....you get the picture.  Now, since
-	we can't detect this at all, I've added this option to force the
-	setting.  If you have a BIOS on your controller then you should never
-	need to use this option.  However, if you are having lots of SCSI
-	reset problems and can't seem to get them knocked out, this may help.
-
-	Here's a test to know for certain if you need this option.  Make
-	a boot floppy that you can use to boot your computer up and that
-	will detect the aic7xxx controller.  Next, power down your computer.
-	While it's down, unplug all SCSI cables from your Adaptec SCSI
-	controller.  Boot the system back up to the Adaptec EZ-SCSI BIOS
-	and then make sure that termination is enabled on your adapter (if
-	you have an Adaptec BIOS of course).  Next, boot up the floppy you
-	made and wait for it to detect the aic7xxx controller.  If the kernel
-	finds the controller fine, says scsi : x hosts and then tries to
-	detect your devices like normal, up to the point where it fails to
-	mount your root file system and panics, then you're fine.  If, on
-	the other hand, the system goes into an infinite reset loop, then
-	you need to use this option and/or the previous option to force the
-	proper termination settings on your controller.   If this happens,
-	then you next need to figure out what your settings should be.
-
-	To find the correct settings, power your machine back down, connect
-	back up the SCSI cables, and boot back into your machine like normal.
-	However, boot with the aic7xxx=verbose:0x39 option.  Record the
-	initial DEVCONFIG values for each of your aic7xxx controllers as
-	they are listed, and also record what the machine is detecting as
-	the proper termination on your controllers.  NOTE: the order in
-	which the initial DEVCONFIG values are printed out is not gauranteed
-	to be the same order as the SCSI controllers are registered.  The
-	above option and this option both work on the order of the SCSI
-	controllers as they are registered, so make sure you match the right
-	DEVCONFIG values with the right controllers if you have more than
-	one aic7xxx controller.
-
-	Once you have the detected termination settings and the initial
-	DEVCONFIG values for each controller, then figure out what the
-	termination on each of the controllers *should* be.  Hopefully, that
-	part is correct, but it could possibly be wrong if there is
-	bogus cable detection logic on your controller or something similar.
-	If all the controllers have the correct termination settings, then
-	don't set the aic7xxx=override_term variable at all, leave it alone.
-	Next, on any controllers that go into an infinite reset loop when
-	you unplug all the SCSI cables, get the starting DEVCONFIG value.
-	If the initial DEVCONFIG value is divisible by 2, then the correct
-	setting for that controller is 0.  If it's an odd number, then
-	the correct setting for that controller is 1.  For any other
-	controllers that didn't have an infinite reset problem, then reverse
-	the above options.  If DEVCONFIG was even, then the correct setting
-	is 1, if not then the correct setting is 0.
-
-	Now that you know what the correct setting was for each controller,
-	we need to encode that into the aic7xxx=stpwlev:0x... variable.
-	This variable is a bit field encoded variable.  Bit 0 is for the first
-	aic7xxx controller, bit 1 for the next, etc.  Put all these bits
-	together and you get a number.  For example, if the third aic7xxx
-	needed a 1, but the second and first both needed a 0, then the bits
-	would be 100 in binary.  This then translates to 0x04.  You would
-	therefore set aic7xxx=stpwlev:0x04.  This is fairly standard binary
-	to hexadecimal conversions here.  If you aren't up to speed on the
-	binary->hex conversion then send an email to the aic7xxx mailing
-	list and someone can help you out.
-
-    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
-        or enable Tagged Command Queueing (TCQ) on specific devices.  As of
-	driver version 5.1.11, TCQ is now either on or off by default
-	according to the setting you choose during the make config process.
-	In order to en/disable TCQ for certian devices at boot time, a user
-	may use this boot param.  The driver will then parse this message out
-        and en/disable the specific device entries that are present based upon
-        the value given.  The param line is parsed in the following manner:
-
-          { - first instance indicates the start of this parameter values
-              second instance is the start of entries for a particular
-              device entry
-          } - end the entries for a particular host adapter, or end the entire
-              set of parameter entries
-          , - move to next entry.  Inside of a set of device entries, this
-              moves us to the next device on the list.  Outside of device
-              entries, this moves us to the next host adapter
-          . - Same effect as , but is safe to use with insmod.
-          x - the number to enter into the array at this position.  
-              0 = Enable tagged queueing on this device and use the default
-                  queue depth
-              1-254 = Enable tagged queueing on this device and use this
-                      number as the queue depth
-              255 = Disable tagged queueing on this device.
-              Note: anything above 32 for an actual queue depth is wasteful
-                    and not recommended.
-
-        A few examples of how this can be used:
-
-        tag_info:{{8,12,,0,,255,4}}
-          This line will only effect the first aic7xxx card registered.  It
-          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
-          at the default, set id 3 to tagged queueing enabled and use the
-          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
-          Any not specified entries stay at the default value, repeated
-          commas with no value specified will simply increment to the next id
-          without changing anything for the missing values.
-
-        tag_info:{,,,{,,,255}}
-          First, second, and third adapters at default values.  Fourth
-          adapter, id 3 is disabled.  Notice that leading commas simply
-	  increment what the first number effects, and there are no need
-	  for trailing commas.  When you close out an adapter, or the
-	  entire entry, anything not explicitly set stays at the default
-	  value.
-
-        A final note on this option.  The scanner I used for this isn't
-        perfect or highly robust.  If you mess the line up, the worst that
-        should happen is that the line will get ignored.  If you don't
-        close out the entire entry with the final bracket, then any other
-        aic7xxx options after this will get ignored.  So, in general, be
-        sure of what you are entering, and after you have it right, just
-        add it to the lilo.conf file so there won't be any mistakes.  As
-        a means of checking this parser, the entire tag_info array for
-        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
-        can use that to verify that your options were parsed correctly. 
-        
-    Boot command line options may be combined to form the proper set of options
-    a user might need.  For example, the following is valid:
-    
-    aic7xxx=verbose,extended,irq_trigger:1
-    
-    The only requirement is that individual options be separated by a comma or
-    a period on the command line.
-        
-  Module Loading command options
-  ------------------------------
-    When loading the aic7xxx driver as a module, the exact same options are
-    available to the user.  However, the syntax to specify the options changes
-    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
-    and replace all ',' with '.'.  So, for example, a valid insmod line
-    would be:
-
-    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
-
-    This line should result in the *exact* same behaviour as if you typed
-    it in at the lilo prompt and the driver was compiled into the kernel
-    instead of being a module.  The reason for the single quote is so that
-    the shell won't try to interpret anything in the line, such as {. 
-    Insmod assumes any options starting with a letter instead of a number
-    is a character string (which is what we want) and by switching all of
-    the commas to periods, insmod won't interpret this as more than one
-    string and write junk into our binary image.  I consider it a bug in
-    the insmod program that even if you wrap your string in quotes (quotes
-    that pass the shell mind you and that insmod sees) it still treates
-    a comma inside of those quotes as starting a new variable, resulting
-    in memory scribbles if you don't switch the commas to periods.
-
-
-  Kernel Compile options
-  ------------------------------
-    The various kernel compile time options for this driver are now fairly
-    well documented in the file Documentation/Configure.help.  In order to
-    see this documentation, you need to use one of the advanced configuration
-    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
-    method of configuring your kernel, then you would simply highlight the
-    option in question and hit the ? key.  If you are using the "make xconfig"
-    method of configuring your kernel, then simply click on the help button
-    next to the option you have questions about.  The help information from
-    the Configure.help file will then get automatically displayed.
-
-  /proc support
-  ------------------------------
-    The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
-    directory. That directory contains a file for each SCSI controller in
-    the system. Each file presents the current configuration and transfer
-    statistics (enabled with #define in aic7xxx.c) for each controller.
-
-    Thanks to Michael Neuffer for his upper-level SCSI help, and
-    Matthew Jacob for statistics support.
-
-  Debugging the driver
-  ------------------------------
-    Should you have problems with this driver, and would like some help in
-    getting them solved, there are a couple debugging items built into
-    the driver to facilitate getting the needed information from the system.
-    In general, I need a complete description of the problem, with as many
-    logs as possible concerning what happens.  To help with this, there is
-    a command option aic7xxx=panic_on_abort.  This option, when set, forces
-    the driver to panic the kernel on the first SCSI abort issued by the
-    mid level SCSI code.  If your system is going to reset loops and you
-    can't read the screen, then this is what you need.  Not only will it
-    stop the system, but it also prints out a large amount of state
-    information in the process.  Second, if you specify the option
-    "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
-    information as it runs that you won't be able to see anything.
-    However, this can actually be very usefull if your machine simply
-    locks up when trying to boot, since it will pin-point what was last
-    happening (in regards to the aic7xxx driver) immediately prior to
-    the lockup.  This is really only usefull if your machine simply can
-    not boot up successfully.  If you can get your machine to run, then
-    this will produce far too much information.
-
-  FTP sites
-  ------------------------------
-    ftp://ftp.redhat.com/pub/aic/
-      - Out of date.  I used to keep stuff here, but too many people
-        complained about having a hard time getting into Red Hat's ftp
-	server.  So use the web site below instead.
-    ftp://ftp.pcnet.com/users/eischen/Linux/
-      - Dan Eischen's driver distribution area
-    ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
-      - European Linux mirror of Teleport site
-
-  Web sites
-  ------------------------------
-    http://people.redhat.com/dledford/
-      - My web site, also the primary aic7xxx site with several related
-        pages.
-
-Dean W. Gehnert
-deang@teleport.com
-
-$Revision: 3.0 $
-
-Modified by Doug Ledford 1998-2000
-
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.4.2/linux/drivers/scsi/aha152x.c	Wed Feb 21 18:20:31 2001
+++ linux/drivers/scsi/aha152x.c	Tue Mar  6 19:44:37 2001
@@ -2755,7 +2755,7 @@
 	if(TESTLO(DMASTAT, DFIFOEMP)) {
 		int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
 
-		DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transfered)\n",
+		DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
 			CMDINFO(CURRENT_SC),
 			data_count,
 			DATA_LEN-CURRENT_SC->resid,
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.4.2/linux/drivers/scsi/aha1542.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/aha1542.c	Tue Mar  6 19:44:37 2001
@@ -103,16 +103,17 @@
 
 /* Boards 3,4 slots are reserved for ISAPnP/MCA scans */
 
-static unsigned int bases[MAXBOARDS] = {0x330, 0x334, 0, 0};
+static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0};
 
-/* set by aha1542_setup according to the command line */
+/* set by aha1542_setup according to the command line; they also may
+   be marked __initdata, but require zero initializers then */
 
 static int setup_called[MAXBOARDS];
 static int setup_buson[MAXBOARDS];
 static int setup_busoff[MAXBOARDS];
-static int setup_dmaspeed[MAXBOARDS] = { -1, -1, -1, -1 };
+static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 };
 
-static char *setup_str[MAXBOARDS];
+static char *setup_str[MAXBOARDS] __initdata;
 
 /*
  * LILO/Module params:  aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]
@@ -132,12 +133,12 @@
  */
 
 #if defined(MODULE)
-int isapnp=0;
+int isapnp = 0;
 int aha1542[] = {0x330, 11, 4, -1};
 MODULE_PARM(aha1542, "1-4i");
 MODULE_PARM(isapnp, "i");
 
-static struct isapnp_device_id id_table[] __devinitdata = {
+static struct isapnp_device_id id_table[] __initdata = {
 	{
 		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1542),
@@ -149,7 +150,7 @@
 MODULE_DEVICE_TABLE(isapnp, id_table);
 
 #else
-int isapnp=1;
+static int isapnp = 1;
 #endif
 
 #define BIOS_TRANSLATION_1632 0	/* Used by some old 1542A boards */
@@ -348,7 +349,7 @@
 	return scsierr | (hosterr << 16);
 }
 
-static int aha1542_test_port(int bse, struct Scsi_Host *shpnt)
+static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt)
 {
 	unchar inquiry_cmd[] = {CMD_INQUIRY};
 	unchar inquiry_result[4];
@@ -595,7 +596,7 @@
 	};
 }
 
-int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	unchar ahacmd = CMD_START_SCSI;
 	unchar direction;
@@ -777,7 +778,7 @@
 	SCpnt->SCp.Status++;
 }
 
-int aha1542_command(Scsi_Cmnd * SCpnt)
+static int aha1542_command(Scsi_Cmnd * SCpnt)
 {
 	DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n"));
 
@@ -816,7 +817,7 @@
 	aha1542_intr_reset(bse);
 }
 
-static int aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id)
+static int __init aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id)
 {
 	unchar inquiry_cmd[] = {CMD_RETCONF};
 	unchar inquiry_result[3];
@@ -920,7 +921,7 @@
 }
 
 /* Query the board to find out if it is a 1542 or a 1740, or whatever. */
-static int aha1542_query(int base_io, int *transl)
+static int __init aha1542_query(int base_io, int *transl)
 {
 	unchar inquiry_cmd[] = {CMD_INQUIRY};
 	unchar inquiry_result[4];
@@ -1034,7 +1035,7 @@
 #endif
 
 /* return non-zero on detection */
-int aha1542_detect(Scsi_Host_Template * tpnt)
+static int __init aha1542_detect(Scsi_Host_Template * tpnt)
 {
 	unsigned char dma_chan;
 	unsigned char irq_level;
@@ -1052,7 +1053,7 @@
 
 #ifdef MODULE
 	bases[0] = aha1542[0];
-	setup_buson[0]=aha1542[1];
+	setup_buson[0] = aha1542[1];
 	setup_busoff[0] = aha1542[2];
 	{
 		int atbt = -1;
@@ -1344,7 +1345,7 @@
 	return 0;
 }
 
-int aha1542_abort(Scsi_Cmnd * SCpnt)
+static int aha1542_abort(Scsi_Cmnd * SCpnt)
 {
 
 	/*
@@ -1362,7 +1363,7 @@
  * This is a device reset.  This is handled by sending a special command
  * to the device.
  */
-int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
+static int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
 {
 	unsigned long flags;
 	struct mailbox *mb;
@@ -1456,7 +1457,7 @@
 #endif				/* ERIC_neverdef */
 }
 
-int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
+static int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
 {
 	int i;
 
@@ -1520,7 +1521,7 @@
 	return FAILED;
 }
 
-int aha1542_host_reset(Scsi_Cmnd * SCpnt)
+static int aha1542_host_reset(Scsi_Cmnd * SCpnt)
 {
 	int i;
 
@@ -1593,7 +1594,7 @@
  * These are the old error handling routines.  They are only temporarily
  * here while we play with the new error handling code.
  */
-int aha1542_old_abort(Scsi_Cmnd * SCpnt)
+static int aha1542_old_abort(Scsi_Cmnd * SCpnt)
 {
 #if 0
 	unchar ahacmd = CMD_START_SCSI;
@@ -1666,7 +1667,7 @@
    For a first go, we assume that the 1542 notifies us with all of the
    pending commands (it does implement soft reset, after all). */
 
-int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
 	unchar ahacmd = CMD_START_SCSI;
 	int i;
@@ -1779,7 +1780,7 @@
 
 #include "sd.h"
 
-int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
+static int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip)
 {
 	int translation_algorithm;
 	int size = disk->capacity;
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h
--- v2.4.2/linux/drivers/scsi/aha1542.h	Mon Dec 11 13:19:05 2000
+++ linux/drivers/scsi/aha1542.h	Tue Mar  6 19:44:37 2001
@@ -130,16 +130,16 @@
 				/* REQUEST SENSE */
 };
 
-int aha1542_detect(Scsi_Host_Template *);
-int aha1542_command(Scsi_Cmnd *);
-int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int aha1542_abort(Scsi_Cmnd * SCpnt);
-int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
-int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
-int aha1542_host_reset(Scsi_Cmnd * SCpnt);
-extern int aha1542_old_abort(Scsi_Cmnd * SCpnt);
-int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
-int aha1542_biosparam(Disk *, kdev_t, int*);
+static int aha1542_detect(Scsi_Host_Template *);
+static int aha1542_command(Scsi_Cmnd *);
+static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int aha1542_abort(Scsi_Cmnd * SCpnt);
+static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
+static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
+static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
+static int aha1542_old_abort(Scsi_Cmnd * SCpnt);
+static int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
+static int aha1542_biosparam(Disk *, kdev_t, int*);
 
 #define AHA1542_MAILBOXES 8
 #define AHA1542_SCATTER 16
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
--- v2.4.2/linux/drivers/scsi/aha1740.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/aha1740.c	Tue Mar  6 19:44:37 2001
@@ -319,11 +319,16 @@
 
     if(*cmd == REQUEST_SENSE)
     {
+#if 0
+	/* scsi_request_sense() provides a buffer of size 256,
+	   so there is no reason to expect equality */
+
 	if (bufflen != sizeof(SCpnt->sense_buffer))
 	{
 	    printk("Wrong buffer length supplied for request sense (%d)\n",
 		   bufflen);
 	}
+#endif	
 	SCpnt->result = 0;
 	done(SCpnt); 
 	return 0;
@@ -521,10 +526,10 @@
 	 * check/allocate region code, but this may change at some point,
 	 * so we go through the motions.
 	 */
-	if (check_region(slotbase, SLOTSIZE))  /* See if in use */
+	if (!request_region(slotbase, SLOTSIZE, "aha1740"))  /* See if in use */
 	    continue;
 	if (!aha1740_test_port(slotbase))
-	    continue;
+	    goto err_release;
 	aha1740_getconfig(slotbase,&irq_level,&translation);
 	if ((inb(G2STAT(slotbase)) &
 	     (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT)
@@ -538,15 +543,12 @@
 	DEB(printk("aha1740_detect: enable interrupt channel %d\n",irq_level));
 	if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",NULL)) {
 	    printk("Unable to allocate IRQ for adaptec controller.\n");
-	    continue;
+	    goto err_release;
 	}
 	shpnt = scsi_register(tpnt, sizeof(struct aha1740_hostdata));
 	if(shpnt == NULL)
-	{
-		free_irq(irq_level, NULL);
-		continue;
-	}
-	request_region(slotbase, SLOTSIZE, "aha1740");
+		goto err_free_irq;
+
 	shpnt->base = 0;
 	shpnt->io_port = slotbase;
 	shpnt->n_io_port = SLOTSIZE;
@@ -557,6 +559,12 @@
 	host->translation = translation;
 	aha_host[irq_level - 9] = shpnt;
 	count++;
+	continue;
+
+    err_free_irq:
+	free_irq(irq_level, aha1740_intr_handle);
+    err_release:
+	release_region(slotbase, SLOTSIZE);
     }
     return count;
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/Config.in linux/drivers/scsi/aic7xxx/Config.in
--- v2.4.2/linux/drivers/scsi/aic7xxx/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/Config.in	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,7 @@
+if [ "$CONFIG_SCSI_AIC7XXX_OLD" != "y" ]; then
+   dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+   if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
+      int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253
+      int  '  Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000
+   fi
+fi
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/Makefile linux/drivers/scsi/aic7xxx/Makefile
--- v2.4.2/linux/drivers/scsi/aic7xxx/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/Makefile	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,32 @@
+#
+# drivers/scsi/aic7xxx/Makefile
+#
+# Makefile for the Linux aic7xxx SCSI driver.
+#
+
+O_TARGET = aic7xxx_drv.o
+
+list-multi	:= aic7xxx_mod.o
+
+obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx_mod.o
+
+# Platform Specific Files
+AIC7XXX_OBJS = aic7xxx_linux.o aic7xxx_linux_pci.o
+AIC7XXX_OBJS += aic7xxx_proc.o aic7770_linux.o
+# Core Files
+AIC7XXX_OBJS += aic7xxx.o aic7xxx_pci.o aic7xxx_93cx6.o aic7770.o
+
+# Override our module desitnation
+MOD_DESTDIR = $(shell cd .. && $(CONFIG_SHELL) $(TOPDIR)/scripts/pathdown.sh)
+MOD_TARGET = aic7xxx.o
+
+include $(TOPDIR)/Rules.make
+
+aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS)
+
+aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm
+	aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq
+
+aicasm/aicasm: aicasm/*.[chyl]
+	$(MAKE) -C aicasm
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7770.c linux/drivers/scsi/aic7xxx/aic7770.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7770.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7770.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,346 @@
+/*
+ * Product specific probe and attach routines for:
+ * 	27/284X and aic7770 motherboard SCSI controllers
+ *
+ * Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs.
+ * 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 immediately at the beginning of the file, without modification,
+ *    this list of conditions, and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7770.c#6 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $
+ */
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+
+#define ID_AIC7770	0x04907770
+#define ID_AHA_274x	0x04907771
+#define ID_AHA_284xB	0x04907756 /* BIOS enabled */
+#define ID_AHA_284x	0x04907757 /* BIOS disabled*/
+
+static void aha2840_load_seeprom(struct ahc_softc *ahc);
+static ahc_device_setup_t ahc_aic7770_VL_setup;
+static ahc_device_setup_t ahc_aic7770_EISA_setup;;
+static ahc_device_setup_t ahc_aic7770_setup;
+
+
+struct aic7770_identity aic7770_ident_table [] =
+{
+	{
+		ID_AHA_274x,
+		0xFFFFFFFF,
+		"Adaptec 274X SCSI adapter",
+		ahc_aic7770_EISA_setup
+	},
+	{
+		ID_AHA_284xB,
+		0xFFFFFFFE,
+		"Adaptec 284X SCSI adapter",
+		ahc_aic7770_VL_setup
+	},
+	/* Generic chip probes for devices we don't know 'exactly' */
+	{
+		ID_AIC7770,
+		0xFFFFFFFF,
+		"Adaptec aic7770 SCSI adapter",
+		ahc_aic7770_EISA_setup
+	}
+};
+const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table);
+
+struct aic7770_identity *
+aic7770_find_device(uint32_t id)
+{
+	struct	aic7770_identity *entry;
+	int	i;
+
+	for (i = 0; i < ahc_num_aic7770_devs; i++) {
+		entry = &aic7770_ident_table[i];
+		if (entry->full_id == (id & entry->id_mask))
+			return (entry);
+	}
+	return (NULL);
+}
+
+int
+aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry)
+{
+	struct	ahc_probe_config probe_config;
+	int	error;
+	u_int	hostconf;
+	u_int   irq;
+	u_int	intdef;
+	u_int	hcntrl;
+	int	shared;
+
+	ahc_init_probe_config(&probe_config);
+	error = entry->setup(ahc->dev_softc, &probe_config);
+	if (error != 0)
+		return (error);
+
+	error = aic7770_map_registers(ahc);
+	if (error != 0)
+		return (error);
+
+	/* Pause the card preseving the IRQ type */
+	hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS;
+	ahc_outb(ahc, HCNTRL, hcntrl | PAUSE);
+	while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0)
+		;
+
+	/* Make sure we have a valid interrupt vector */
+	intdef = ahc_inb(ahc, INTDEF);
+	shared = (intdef & EDGE_TRIG) ? 0 : 1;
+	irq = intdef & VECTOR;
+	switch (irq) {
+	case 9:
+	case 10:
+	case 11:
+	case 12:
+	case 14:
+	case 15:
+		break;
+	default:
+		printf("aic7770_config: illegal irq setting %d\n", intdef);
+		return (ENXIO);
+	}
+
+	probe_config.description = entry->name;
+	error = ahc_softc_init(ahc, &probe_config);
+
+	error = aic7770_map_int(ahc, irq, shared);
+	if (error != 0)
+		return (error);
+
+	error = ahc_reset(ahc);
+	if (error != 0)
+		return (error);
+
+	switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
+	case AHC_EISA:
+	{
+		u_int biosctrl;
+		u_int scsiconf;
+		u_int scsiconf1;
+
+		biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
+		scsiconf = ahc_inb(ahc, SCSICONF);
+		scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
+
+		/* Get the primary channel information */
+		if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
+			ahc->flags |= AHC_CHANNEL_B_PRIMARY;
+
+		if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
+			ahc->flags |= AHC_USEDEFAULTS;
+		} else {
+			if ((ahc->features & AHC_WIDE) != 0) {
+				ahc->our_id = scsiconf1 & HWSCSIID;
+				if (scsiconf & TERM_ENB)
+					ahc->flags |= AHC_TERM_ENB_A;
+			} else {
+				ahc->our_id = scsiconf & HSCSIID;
+				ahc->our_id_b = scsiconf1 & HSCSIID;
+				if (scsiconf & TERM_ENB)
+					ahc->flags |= AHC_TERM_ENB_A;
+				if (scsiconf1 & TERM_ENB)
+					ahc->flags |= AHC_TERM_ENB_B;
+			}
+		}
+		/*
+		 * We have no way to tell, so assume extended
+		 * translation is enabled.
+		 */
+		ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
+		break;
+	}
+	case AHC_VL:
+	{
+		aha2840_load_seeprom(ahc);
+		break;
+	}
+	default:
+		break;
+	}
+
+	/*
+	 * Ensure autoflush is enabled
+	 */
+	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
+
+	/* Setup the FIFO threshold and the bus off time */
+	hostconf = ahc_inb(ahc, HOSTCONF);
+	ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
+	ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
+
+	/*
+	 * Generic aic7xxx initialization.
+	 */
+	error = ahc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Link this softc in with all other ahc instances.
+	 */
+	ahc_softc_insert(ahc);
+
+	/*
+	 * Enable the board's BUS drivers
+	 */
+	ahc_outb(ahc, BCTL, ENABLE);
+
+	return (0);
+}
+
+/*
+ * Read the 284x SEEPROM.
+ */
+static void
+aha2840_load_seeprom(struct ahc_softc *ahc)
+{
+	struct	  seeprom_descriptor sd;
+	struct	  seeprom_config sc;
+	uint16_t  checksum = 0;
+	uint8_t   scsi_conf;
+	int	  have_seeprom;
+
+	sd.sd_ahc = ahc;
+	sd.sd_control_offset = SEECTL_2840;
+	sd.sd_status_offset = STATUS_2840;
+	sd.sd_dataout_offset = STATUS_2840;		
+	sd.sd_chip = C46;
+	sd.sd_MS = 0;
+	sd.sd_RDY = EEPROM_TF;
+	sd.sd_CS = CS_2840;
+	sd.sd_CK = CK_2840;
+	sd.sd_DO = DO_2840;
+	sd.sd_DI = DI_2840;
+
+	if (bootverbose)
+		printf("%s: Reading SEEPROM...", ahc_name(ahc));
+	have_seeprom = read_seeprom(&sd,
+				    (uint16_t *)&sc,
+				    /*start_addr*/0,
+				    sizeof(sc)/2);
+
+	if (have_seeprom) {
+		/* Check checksum */
+		int i;
+		int maxaddr = (sizeof(sc)/2) - 1;
+		uint16_t *scarray = (uint16_t *)&sc;
+
+		for (i = 0; i < maxaddr; i++)
+			checksum = checksum + scarray[i];
+		if (checksum != sc.checksum) {
+			if(bootverbose)
+				printf ("checksum error\n");
+			have_seeprom = 0;
+		} else if (bootverbose) {
+			printf("done.\n");
+		}
+	}
+
+	if (!have_seeprom) {
+		if (bootverbose)
+			printf("%s: No SEEPROM available\n", ahc_name(ahc));
+		ahc->flags |= AHC_USEDEFAULTS;
+	} else {
+		/*
+		 * Put the data we've collected down into SRAM
+		 * where ahc_init will find it.
+		 */
+		int i;
+		int max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
+		uint16_t discenable;
+
+		discenable = 0;
+		for (i = 0; i < max_targ; i++){
+	                uint8_t target_settings;
+			target_settings = (sc.device_flags[i] & CFXFER) << 4;
+			if (sc.device_flags[i] & CFSYNCH)
+				target_settings |= SOFS;
+			if (sc.device_flags[i] & CFWIDEB)
+				target_settings |= WIDEXFER;
+			if (sc.device_flags[i] & CFDISC)
+				discenable |= (0x01 << i);
+			ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
+		}
+		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+
+		ahc->our_id = sc.brtime_id & CFSCSIID;
+
+		scsi_conf = (ahc->our_id & 0x7);
+		if (sc.adapter_control & CFSPARITY)
+			scsi_conf |= ENSPCHK;
+		if (sc.adapter_control & CFRESETB)
+			scsi_conf |= RESET_SCSI;
+
+		if (sc.bios_control & CF284XEXTEND)		
+			ahc->flags |= AHC_EXTENDED_TRANS_A;
+		/* Set SCSICONF info */
+		ahc_outb(ahc, SCSICONF, scsi_conf);
+
+		if (sc.adapter_control & CF284XSTERM)
+			ahc->flags |= AHC_TERM_ENB_A;
+	}
+}
+
+static int
+ahc_aic7770_VL_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7770_setup(dev, probe_config);
+	probe_config->chip |= AHC_VL;
+	return (error);
+}
+
+static int
+ahc_aic7770_EISA_setup(ahc_dev_softc_t dev,
+		       struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7770_setup(dev, probe_config);
+	probe_config->chip |= AHC_EISA;
+	return (error);
+}
+
+static int
+ahc_aic7770_setup(ahc_dev_softc_t dev, struct ahc_probe_config *probe_config)
+{
+	probe_config->channel = 'A';
+	probe_config->channel_b = 'B';
+	probe_config->chip = AHC_AIC7770;
+	probe_config->features = AHC_AIC7770_FE;
+	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
+	probe_config->flags |= AHC_PAGESCBS;
+	return (0);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7770_linux.c linux/drivers/scsi/aic7xxx/aic7770_linux.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7770_linux.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7770_linux.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,146 @@
+/*
+ * Linux driver attachment glue for aic7770 based controllers.
+ *
+ * Copyright (c) 2000 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $
+ */
+
+#include "aic7xxx_osm.h"
+
+#define MINSLOT			1
+#define NUMSLOTS		16
+#define IDOFFSET		0x80
+
+int
+aic7770_linux_probe(Scsi_Host_Template *template)
+{
+#if defined(__i386__) || defined(__alpha__)
+	struct aic7770_identity *entry;
+	struct ahc_softc *ahc;
+	int i, slot;
+	int eisaBase;
+	int found;
+
+	if (aic7xxx_no_probe)
+		return (0);
+
+	eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET;
+	found = 0;
+	for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) {
+		uint32_t eisa_id;
+		size_t	 id_size;
+
+		if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0)
+			continue;
+
+		eisa_id = 0;
+		id_size = sizeof(eisa_id);
+		for (i = 0; i < 4; i++) {
+			/* VLcards require priming*/
+			outb(0x80 + i, eisaBase + IDOFFSET);
+			eisa_id |= inb(eisaBase + IDOFFSET + i)
+				   << ((id_size-i-1) * 8);
+		}
+		if (eisa_id & 0x80000000)
+			continue;  /* no EISA card in slot */
+
+		entry = aic7770_find_device(eisa_id);
+		if (entry != NULL) {
+			char	 buf[80];
+			char	*name;
+			int	 error;
+
+			/*
+			 * Allocate a softc for this card and
+			 * set it up for attachment by our
+			 * common detect routine.
+			 */
+			sprintf(buf, "ahc_eisa:%d", slot);
+			name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+			if (name == NULL)
+				break;
+			strcpy(name, buf);
+			ahc = ahc_alloc(template, name);
+			if (ahc == NULL) {
+				/*
+				 * If we can't allocate this one,
+				 * chances are we won't be able to
+				 * allocate future card structures.
+				 */
+				break;
+			}
+			ahc->tag = BUS_SPACE_PIO;
+			ahc->bsh.ioport = eisaBase;
+			error = aic7770_config(ahc, entry);
+			if (error != 0) {
+				ahc_free(ahc);
+				continue;
+			}
+			found++;
+		}
+	}
+	return (found);
+#else
+	return (0);
+#endif
+}
+
+int
+aic7770_map_registers(struct ahc_softc *ahc)
+{
+	/*
+	 * Lock out other contenders for our i/o space.
+	 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+	request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx");
+#else
+	if (request_region(ahc->bsh.ioport, AHC_EISA_IOSIZE, "aic7xxx") == 0)
+		return (ENOMEM);
+#endif
+
+	return (0);
+}
+
+int
+aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared)
+{
+	int error;
+
+	if (shared)
+		shared = SA_SHIRQ;
+
+	ahc->platform_data->irq = irq;
+	error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
+			    SA_INTERRUPT|shared, "aic7xxx", ahc);
+	if (error < 0)
+		error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
+				    shared, "aic7xxx", ahc);
+	
+	return (-error);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,6673 @@
+/*
+ * Core routines and tables shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $
+ */
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aicasm/aicasm_insformat.h"
+
+/****************************** Softc Data ************************************/
+struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq);
+
+/***************************** Lookup Tables **********************************/
+char *ahc_chip_names[] =
+{
+	"NONE",
+	"aic7770",
+	"aic7850",
+	"aic7855",
+	"aic7859",
+	"aic7860",
+	"aic7870",
+	"aic7880",
+	"aic7895",
+	"aic7895C",
+	"aic7890/91",
+	"aic7896/97",
+	"aic7892",
+	"aic7899"
+};
+const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
+
+struct hard_error_entry hard_error[] = {
+	{ ILLHADDR,	"Illegal Host Access" },
+	{ ILLSADDR,	"Illegal Sequencer Address referrenced" },
+	{ ILLOPCODE,	"Illegal Opcode in sequencer program" },
+	{ SQPARERR,	"Sequencer Parity Error" },
+	{ DPARERR,	"Data-path Parity Error" },
+	{ MPARERR,	"Scratch or SCB Memory Parity Error" },
+	{ PCIERRSTAT,	"PCI Error detected" },
+	{ CIOPARERR,	"CIOBUS Parity Error" },
+};
+const u_int num_errors = NUM_ELEMENTS(hard_error);
+
+struct phase_table_entry phase_table[] =
+{
+	{ P_DATAOUT,	MSG_NOOP,		"in Data-out phase"	},
+	{ P_DATAIN,	MSG_INITIATOR_DET_ERR,	"in Data-in phase"	},
+	{ P_DATAOUT_DT,	MSG_NOOP,		"in DT Data-out phase"	},
+	{ P_DATAIN_DT,	MSG_INITIATOR_DET_ERR,	"in DT Data-in phase"	},
+	{ P_COMMAND,	MSG_NOOP,		"in Command phase"	},
+	{ P_MESGOUT,	MSG_NOOP,		"in Message-out phase"	},
+	{ P_STATUS,	MSG_INITIATOR_DET_ERR,	"in Status phase"	},
+	{ P_MESGIN,	MSG_PARITY_ERROR,	"in Message-in phase"	},
+	{ P_BUSFREE,	MSG_NOOP,		"while idle"		},
+	{ 0,		MSG_NOOP,		"in unknown phase"	}
+};
+
+/*
+ * In most cases we only wish to itterate over real phases, so
+ * exclude the last element from the count.
+ */
+const u_int num_phases = NUM_ELEMENTS(phase_table) - 1;
+
+/*
+ * Valid SCSIRATE values.  (p. 3-17)
+ * Provides a mapping of tranfer periods in ns to the proper value to
+ * stick in the scsixfer reg.
+ */
+struct ahc_syncrate ahc_syncrates[] =
+{
+      /* ultra2    fast/ultra  period     rate */
+	{ 0x42,      0x000,      9,      "80.0" },
+	{ 0x03,      0x000,     10,      "40.0" },
+	{ 0x04,      0x000,     11,      "33.0" },
+	{ 0x05,      0x100,     12,      "20.0" },
+	{ 0x06,      0x110,     15,      "16.0" },
+	{ 0x07,      0x120,     18,      "13.4" },
+	{ 0x08,      0x000,     25,      "10.0" },
+	{ 0x19,      0x010,     31,      "8.0"  },
+	{ 0x1a,      0x020,     37,      "6.67" },
+	{ 0x1b,      0x030,     43,      "5.7"  },
+	{ 0x1c,      0x040,     50,      "5.0"  },
+	{ 0x00,      0x050,     56,      "4.4"  },
+	{ 0x00,      0x060,     62,      "4.0"  },
+	{ 0x00,      0x070,     68,      "3.6"  },
+	{ 0x00,      0x000,      0,      NULL   }
+};
+
+/* Our Sequencer Program */
+#include "aic7xxx_seq.h"
+
+/**************************** Function Declarations ***************************/
+static struct tmode_tstate*
+			ahc_alloc_tstate(struct ahc_softc *ahc,
+					 u_int scsi_id, char channel);
+#ifdef AHC_TARGET_MODE
+static void		ahc_free_tstate(struct ahc_softc *ahc,
+					u_int scsi_id, char channel, int force);
+#endif
+static struct ahc_syncrate*
+			ahc_devlimited_syncrate(struct ahc_softc *ahc,
+					        struct ahc_initiator_tinfo *,
+						u_int *period,
+						u_int *ppr_options,
+						role_t role);
+static void		ahc_update_pending_syncrates(struct ahc_softc *ahc);
+static void		ahc_fetch_devinfo(struct ahc_softc *ahc,
+					  struct ahc_devinfo *devinfo);
+static void		ahc_scb_devinfo(struct ahc_softc *ahc,
+					struct ahc_devinfo *devinfo,
+					struct scb *scb);
+static void		ahc_setup_initiator_msgout(struct ahc_softc *ahc,
+						   struct ahc_devinfo *devinfo,
+						   struct scb *scb);
+static void		ahc_build_transfer_msg(struct ahc_softc *ahc,
+					       struct ahc_devinfo *devinfo);
+static void		ahc_construct_sdtr(struct ahc_softc *ahc,
+					   struct ahc_devinfo *devinfo,
+					   u_int period, u_int offset);
+static void		ahc_construct_wdtr(struct ahc_softc *ahc,
+					   struct ahc_devinfo *devinfo,
+					   u_int bus_width);
+static void		ahc_construct_ppr(struct ahc_softc *ahc,
+					  struct ahc_devinfo *devinfo,
+					  u_int period, u_int offset,
+					  u_int bus_width, u_int ppr_options);
+static void		ahc_clear_msg_state(struct ahc_softc *ahc);
+static void		ahc_handle_message_phase(struct ahc_softc *ahc);
+typedef enum {
+	AHCMSG_1B,
+	AHCMSG_2B,
+	AHCMSG_EXT
+} ahc_msgtype;
+static int		ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type,
+				     u_int msgval, int full);
+static int		ahc_parse_msg(struct ahc_softc *ahc,
+				      struct ahc_devinfo *devinfo);
+static int		ahc_handle_msg_reject(struct ahc_softc *ahc,
+					      struct ahc_devinfo *devinfo);
+static void		ahc_handle_ign_wide_residue(struct ahc_softc *ahc,
+						struct ahc_devinfo *devinfo);
+static void		ahc_handle_devreset(struct ahc_softc *ahc,
+					    struct ahc_devinfo *devinfo,
+					    cam_status status, char *message,
+					    int verbose_level);
+
+static bus_dmamap_callback_t	ahc_dmamap_cb; 
+static void			ahc_build_free_scb_list(struct ahc_softc *ahc);
+static int			ahc_init_scbdata(struct ahc_softc *ahc);
+static void			ahc_fini_scbdata(struct ahc_softc *ahc);
+static void		ahc_qinfifo_requeue(struct ahc_softc *ahc,
+					    struct scb *prev_scb,
+					    struct scb *scb);
+static int		ahc_qinfifo_count(struct ahc_softc *ahc);
+static u_int		ahc_rem_scb_from_disc_list(struct ahc_softc *ahc,
+						   u_int prev, u_int scbptr);
+static void		ahc_add_curscb_to_free_list(struct ahc_softc *ahc);
+static u_int		ahc_rem_wscb(struct ahc_softc *ahc,
+				     u_int scbpos, u_int prev);
+static int		ahc_abort_scbs(struct ahc_softc *ahc, int target,
+				       char channel, int lun, u_int tag,
+				       role_t role, uint32_t status);
+static void		ahc_reset_current_bus(struct ahc_softc *ahc);
+static void		ahc_calc_residual(struct scb *scb);
+#ifdef AHC_DUMP_SEQ
+static void		ahc_dumpseq(struct ahc_softc *ahc);
+#endif
+static void		ahc_loadseq(struct ahc_softc *ahc);
+static int		ahc_check_patch(struct ahc_softc *ahc,
+					struct patch **start_patch,
+					u_int start_instr, u_int *skip_addr);
+static void		ahc_download_instr(struct ahc_softc *ahc,
+					   u_int instrptr, uint8_t *dconsts);
+#ifdef AHC_TARGET_MODE
+static void		ahc_queue_lstate_event(struct ahc_softc *ahc,
+					       struct tmode_lstate *lstate,
+					       u_int initiator_id,
+					       u_int event_type,
+					       u_int event_arg);
+static void		ahc_update_scsiid(struct ahc_softc *ahc,
+					  u_int targid_mask);
+static int		ahc_handle_target_cmd(struct ahc_softc *ahc,
+					      struct target_cmd *cmd);
+#endif
+/************************* Sequencer Execution Control ************************/
+/*
+ * Restart the sequencer program from address zero
+ */
+void
+restart_sequencer(struct ahc_softc *ahc)
+{
+
+	pause_sequencer(ahc);
+
+	ahc_outb(ahc, SCSISIGO, 0);		/* De-assert BSY */
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);	/* No message to send */
+	ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
+
+	/*
+	 * Ensure that the sequencer's idea of TQINPOS
+	 * matches our own.  The sequencer increments TQINPOS
+	 * only after it sees a DMA complete and a reset could
+	 * occur before the increment leaving the kernel to believe
+	 * the command arrived but the sequencer to not.
+	 */
+	ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+
+	/* Always allow reselection */
+	ahc_outb(ahc, SCSISEQ,
+		 ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		/* Ensure that no DMA operations are in progress */
+		ahc_outb(ahc, CCSCBCNT, 0);
+		ahc_outb(ahc, CCSGCTL, 0);
+		ahc_outb(ahc, CCSCBCTL, 0);
+	}
+	/*
+	 * If we were in the process of DMA'ing SCB data into
+	 * an SCB, replace that SCB on the free list.  This prevents
+	 * an SCB leak.
+	 */
+	if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) {
+		ahc_add_curscb_to_free_list(ahc);
+		ahc_outb(ahc, SEQ_FLAGS2,
+			 ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
+	}
+	ahc_outb(ahc, MWI_RESIDUAL, 0);
+	ahc_outb(ahc, SEQCTL, FASTMODE);
+	ahc_outb(ahc, SEQADDR0, 0);
+	ahc_outb(ahc, SEQADDR1, 0);
+	unpause_sequencer(ahc);
+}
+
+/************************* Input/Output Queues ********************************/
+void
+ahc_run_qoutfifo(struct ahc_softc *ahc)
+{
+	struct scb *scb;
+	u_int  scb_index;
+
+	while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) {
+
+		scb_index = ahc->qoutfifo[ahc->qoutfifonext];
+		if ((ahc->qoutfifonext & 0x03) == 0x03) {
+			u_int modnext;
+
+			/*
+			 * Clear 32bits of QOUTFIFO at a time
+			 * so that we don't clobber an incomming
+			 * byte DMA to the array on architectures
+			 * that only support 32bit load and store
+			 * operations.
+			 */
+			modnext = ahc->qoutfifonext & ~0x3;
+			*((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL;
+		}
+		ahc->qoutfifonext++;
+
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("%s: WARNING no command for scb %d "
+			       "(cmdcmplt)\nQOUTPOS = %d\n",
+			       ahc_name(ahc), scb_index,
+			       ahc->qoutfifonext - 1);
+			continue;
+		}
+
+		/*
+		 * Save off the residual
+		 * if there is one.
+		 */
+		if (ahc_check_residual(scb) != 0)
+			ahc_calc_residual(scb);
+		else
+			ahc_set_residual(scb, 0);
+		ahc_done(ahc, scb);
+	}
+}
+
+void
+ahc_run_untagged_queues(struct ahc_softc *ahc)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]);
+}
+
+void
+ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
+{
+	struct scb *scb;
+
+	if (ahc->untagged_queue_lock != 0)
+		return;
+
+	if ((scb = TAILQ_FIRST(queue)) != NULL
+	 && (scb->flags & SCB_ACTIVE) == 0) {
+		scb->flags |= SCB_ACTIVE;
+		ahc_queue_scb(ahc, scb);
+	}
+}
+
+/************************* Interrupt Handling *********************************/
+void
+ahc_handle_brkadrint(struct ahc_softc *ahc)
+{
+	/*
+	 * We upset the sequencer :-(
+	 * Lookup the error message
+	 */
+	int i, error, num_errors;
+
+	error = ahc_inb(ahc, ERROR);
+	num_errors =  sizeof(hard_error)/sizeof(hard_error[0]);
+	for (i = 0; error != 1 && i < num_errors; i++)
+		error >>= 1;
+	printf("%s: brkadrint, %s at seqaddr = 0x%x\n",
+	       ahc_name(ahc), hard_error[i].errmesg,
+	       ahc_inb(ahc, SEQADDR0) |
+	       (ahc_inb(ahc, SEQADDR1) << 8));
+
+	ahc_dump_card_state(ahc);
+
+	/* Tell everyone that this HBA is no longer availible */
+	ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+		       CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,
+		       CAM_NO_HBA);
+
+	/* Disable all interrupt sources by resetting the controller */
+	ahc_shutdown(ahc);
+}
+
+void
+ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
+{
+	struct scb *scb;
+	struct ahc_devinfo devinfo;
+	
+	ahc_fetch_devinfo(ahc, &devinfo);
+
+	/*
+	 * Clear the upper byte that holds SEQINT status
+	 * codes and clear the SEQINT bit. We will unpause
+	 * the sequencer, if appropriate, after servicing
+	 * the request.
+	 */
+	ahc_outb(ahc, CLRINT, CLRSEQINT);
+	switch (intstat & SEQINT_MASK) {
+	case BAD_STATUS:
+	{
+		u_int  scb_index;
+		struct hardware_scb *hscb;
+
+		/*
+		 * Set the default return value to 0 (don't
+		 * send sense).  The sense code will change
+		 * this if needed.
+		 */
+		ahc_outb(ahc, RETURN_1, 0);
+
+		/*
+		 * The sequencer will notify us when a command
+		 * has an error that would be of interest to
+		 * the kernel.  This allows us to leave the sequencer
+		 * running in the common case of command completes
+		 * without error.  The sequencer will already have
+		 * dma'd the SCB back up to us, so we can reference
+		 * the in kernel copy directly.
+		 */
+		scb_index = ahc_inb(ahc, SCB_TAG);
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("%s:%c:%d: ahc_intr - referenced scb "
+			       "not valid during seqint 0x%x scb(%d)\n",
+			       ahc_name(ahc), devinfo.channel,
+			       devinfo.target, intstat, scb_index);
+			ahc_dump_card_state(ahc);
+			panic("for safety");
+			goto unpause;
+		}
+
+		hscb = scb->hscb; 
+
+		/* Don't want to clobber the original sense code */
+		if ((scb->flags & SCB_SENSE) != 0) {
+			/*
+			 * Clear the SCB_SENSE Flag and have
+			 * the sequencer do a normal command
+			 * complete.
+			 */
+			scb->flags &= ~SCB_SENSE;
+			ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+			break;
+		}
+		ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR);
+		/* Freeze the queue until the client sees the error. */
+		ahc_freeze_devq(ahc, scb);
+		ahc_freeze_scb(scb);
+		ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status);
+		switch (hscb->shared_data.status.scsi_status) {
+		case SCSI_STATUS_OK:
+			printf("%s: Interrupted for staus of 0???\n",
+			       ahc_name(ahc));
+			break;
+		case SCSI_STATUS_CMD_TERMINATED:
+		case SCSI_STATUS_CHECK_COND:
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOWSENSE) {
+				ahc_print_path(ahc, scb);
+				printf("SCB %d: requests Check Status\n",
+				       scb->hscb->tag);
+			}
+#endif
+
+			if (ahc_perform_autosense(scb)) {
+				struct ahc_dma_seg *sg;
+				struct scsi_sense *sc;
+				struct ahc_initiator_tinfo *targ_info;
+				struct tmode_tstate *tstate;
+				struct ahc_transinfo *tinfo;
+
+				targ_info =
+				    ahc_fetch_transinfo(ahc,
+							devinfo.channel,
+							devinfo.our_scsiid,
+							devinfo.target,
+							&tstate);
+				tinfo = &targ_info->current;
+				sg = scb->sg_list;
+				sc = (struct scsi_sense *)
+				     (&hscb->shared_data.cdb); 
+				/*
+				 * Save off the residual if there is one.
+				 */
+				if (ahc_check_residual(scb))
+					ahc_calc_residual(scb);
+				else
+					ahc_set_residual(scb, 0);
+#ifdef AHC_DEBUG
+				if (ahc_debug & AHC_SHOWSENSE) {
+					ahc_print_path(ahc, scb);
+					printf("Sending Sense\n");
+				}
+#endif
+				sg->addr = ahc_get_sense_bufaddr(ahc, scb);
+				sg->len = ahc_get_sense_bufsize(ahc, scb);
+				sg->len |= AHC_DMA_LAST_SEG;
+
+				/* Fixup byte order */
+				sg->addr = ahc_htole32(sg->addr);
+				sg->len = ahc_htole32(sg->len);
+
+				sc->opcode = REQUEST_SENSE;
+				sc->byte2 = 0;
+				if (tinfo->protocol_version <= SCSI_REV_2
+				 && SCB_GET_LUN(scb) < 8)
+					sc->byte2 = SCB_GET_LUN(scb) << 5;
+				sc->unused[0] = 0;
+				sc->unused[1] = 0;
+				sc->length = sg->len;
+				sc->control = 0;
+
+				/*
+				 * XXX Still true???
+				 * Would be nice to preserve DISCENB here,
+				 * but due to the way we manage busy targets,
+				 * we can't.
+				 */
+				hscb->control = 0;
+
+				/*
+				 * This request sense could be because the
+				 * the device lost power or in some other
+				 * way has lost our transfer negotiations.
+				 * Renegotiate if appropriate.  Unit attention
+				 * errors will be reported before any data
+				 * phases occur.
+				 */
+				if (ahc_get_residual(scb) 
+				 == ahc_get_transfer_length(scb)) {
+					ahc_update_target_msg_request(ahc,
+							      &devinfo,
+							      targ_info,
+							      /*force*/TRUE,
+							      /*paused*/TRUE);
+				}
+				hscb->cdb_len = sizeof(*sc);
+				hscb->dataptr = sg->addr; 
+				hscb->datacnt = sg->len;
+				hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
+				hscb->sgptr = ahc_htole32(hscb->sgptr);
+				scb->sg_count = 1;
+				scb->flags |= SCB_SENSE;
+				ahc_qinfifo_requeue_tail(ahc, scb);
+				ahc_outb(ahc, RETURN_1, SEND_SENSE);
+#ifdef __FreeBSD__
+				/*
+				 * Ensure we have enough time to actually
+				 * retrieve the sense.
+				 */
+				untimeout(ahc_timeout, (caddr_t)scb,
+					  scb->io_ctx->ccb_h.timeout_ch);
+				scb->io_ctx->ccb_h.timeout_ch =
+				    timeout(ahc_timeout, (caddr_t)scb, 5 * hz);
+#endif
+			}
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+	case NO_MATCH:
+	{
+		/* Ensure we don't leave the selection hardware on */
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+
+		printf("%s:%c:%d: no active SCB for reconnecting "
+		       "target - issuing BUS DEVICE RESET\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target);
+		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		       "ARG_1 == 0x%x ACCUM = 0x%x\n",
+		       ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
+		       ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
+		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		       "SINDEX == 0x%x\n",
+		       ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
+		       ahc_index_busy_tcl(ahc,
+			    BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
+				      ahc_inb(ahc, SAVED_LUN))),
+		       ahc_inb(ahc, SINDEX));
+		printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		       "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
+		       ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
+		       ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
+		       ahc_inb(ahc, SCB_CONTROL));
+		printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+		       ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
+		printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0));
+		printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL));
+		ahc_dump_card_state(ahc);
+		ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
+		ahc->msgout_len = 1;
+		ahc->msgout_index = 0;
+		ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+		ahc_outb(ahc, MSG_OUT, HOST_MSG);
+		ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO);
+		break;
+	}
+	case SEND_REJECT: 
+	{
+		u_int rejbyte = ahc_inb(ahc, ACCUM);
+		printf("%s:%c:%d: Warning - unknown message received from "
+		       "target (0x%x).  Rejecting\n", 
+		       ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
+		break; 
+	}
+	case NO_IDENT: 
+	{
+		/*
+		 * The reconnecting target either did not send an identify
+		 * message, or did, but we didn't find an SCB to match and
+		 * before it could respond to our ATN/abort, it hit a dataphase.
+		 * The only safe thing to do is to blow it away with a bus
+		 * reset.
+		 */
+		int found;
+
+		printf("%s:%c:%d: Target did not send an IDENTIFY message. "
+		       "LASTPHASE = 0x%x, SAVED_SCSIID == 0x%x\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_SCSIID));
+		found = ahc_reset_channel(ahc, devinfo.channel, 
+					  /*initiate reset*/TRUE);
+		printf("%s: Issued Channel %c Bus Reset. "
+		       "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel,
+		       found);
+		return;
+	}
+	case IGN_WIDE_RES:
+		ahc_handle_ign_wide_residue(ahc, &devinfo);
+		break;
+	case BAD_PHASE:
+	{
+		u_int lastphase;
+
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		printf("%s:%c:%d: unknown scsi bus phase %x, "
+		       "lastphase = 0x%x.  Attempting to continue\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       lastphase, ahc_inb(ahc, SCSISIGI));
+		break;
+	}
+	case MISSED_BUSFREE:
+	{
+		u_int lastphase;
+
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		printf("%s:%c:%d: Missed busfree. "
+		       "Lastphase = 0x%x, Curphase = 0x%x\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       lastphase, ahc_inb(ahc, SCSISIGI));
+		restart_sequencer(ahc);
+		return;
+	}
+	case HOST_MSG_LOOP:
+	{
+		/*
+		 * The sequencer has encountered a message phase
+		 * that requires host assistance for completion.
+		 * While handling the message phase(s), we will be
+		 * notified by the sequencer after each byte is
+		 * transfered so we can track bus phase changes.
+		 *
+		 * If this is the first time we've seen a HOST_MSG_LOOP
+		 * interrupt, initialize the state of the host message
+		 * loop.
+		 */
+		if (ahc->msg_type == MSG_TYPE_NONE) {
+			u_int bus_phase;
+
+			bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+			if (bus_phase != P_MESGIN
+			 && bus_phase != P_MESGOUT) {
+				printf("ahc_intr: HOST_MSG_LOOP bad "
+				       "phase 0x%x\n",
+				      bus_phase);
+				/*
+				 * Probably transitioned to bus free before
+				 * we got here.  Just punt the message.
+				 */
+				ahc_clear_intstat(ahc);
+				restart_sequencer(ahc);
+				return;
+			}
+
+			if (devinfo.role == ROLE_INITIATOR) {
+				struct scb *scb;
+				u_int scb_index;
+
+				scb_index = ahc_inb(ahc, SCB_TAG);
+				scb = ahc_lookup_scb(ahc, scb_index);
+
+				if (scb == NULL)
+					panic("HOST_MSG_LOOP with "
+					      "invalid SCB %x\n", scb_index);
+
+				if (bus_phase == P_MESGOUT)
+					ahc_setup_initiator_msgout(ahc,
+								   &devinfo,
+								   scb);
+				else {
+					ahc->msg_type =
+					    MSG_TYPE_INITIATOR_MSGIN;
+					ahc->msgin_index = 0;
+				}
+			} else {
+				if (bus_phase == P_MESGOUT) {
+					ahc->msg_type =
+					    MSG_TYPE_TARGET_MSGOUT;
+					ahc->msgin_index = 0;
+				}
+#if AHC_TARGET_MODE
+				else 
+					ahc_setup_target_msgin(ahc, &devinfo);
+#endif
+			}
+		}
+
+		ahc_handle_message_phase(ahc);
+		break;
+	}
+	case PERR_DETECTED:
+	{
+		/*
+		 * If we've cleared the parity error interrupt
+		 * but the sequencer still believes that SCSIPERR
+		 * is true, it must be that the parity error is
+		 * for the currently presented byte on the bus,
+		 * and we are not in a phase (data-in) where we will
+		 * eventually ack this byte.  Ack the byte and
+		 * throw it away in the hope that the target will
+		 * take us to message out to deliver the appropriate
+		 * error message.
+		 */
+		if ((intstat & SCSIINT) == 0
+		 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) {
+			u_int curphase;
+
+			/*
+			 * The hardware will only let you ack bytes
+			 * if the expected phase in SCSISIGO matches
+			 * the current phase.  Make sure this is
+			 * currently the case.
+			 */
+			curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+			ahc_outb(ahc, LASTPHASE, curphase);
+			ahc_outb(ahc, SCSISIGO, curphase);
+			ahc_inb(ahc, SCSIDATL);
+		}
+		break;
+	}
+	case DATA_OVERRUN:
+	{
+		/*
+		 * When the sequencer detects an overrun, it
+		 * places the controller in "BITBUCKET" mode
+		 * and allows the target to complete its transfer.
+		 * Unfortunately, none of the counters get updated
+		 * when the controller is in this mode, so we have
+		 * no way of knowing how large the overrun was.
+		 */
+		u_int scbindex = ahc_inb(ahc, SCB_TAG);
+		u_int lastphase = ahc_inb(ahc, LASTPHASE);
+		u_int i;
+
+		scb = ahc_lookup_scb(ahc, scbindex);
+		for (i = 0; i < num_phases; i++) {
+			if (lastphase == phase_table[i].phase)
+				break;
+		}
+		ahc_print_path(ahc, scb);
+		printf("data overrun detected %s."
+		       "  Tag == 0x%x.\n",
+		       phase_table[i].phasemsg,
+  		       scb->hscb->tag);
+		ahc_print_path(ahc, scb);
+		printf("%s seen Data Phase.  Length = %ld.  NumSGs = %d.\n",
+		       ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+		       ahc_get_transfer_length(scb), scb->sg_count);
+		if (scb->sg_count > 0) {
+			for (i = 0; i < scb->sg_count; i++) {
+				printf("sg[%d] - Addr 0x%x : Length %d\n",
+				       i,
+				       ahc_le32toh(scb->sg_list[i].addr),
+				       ahc_le32toh(scb->sg_list[i].len)
+				       & AHC_SG_LEN_MASK);
+			}
+		}
+		/*
+		 * Set this and it will take effect when the
+		 * target does a command complete.
+		 */
+		ahc_freeze_devq(ahc, scb);
+		ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		ahc_freeze_scb(scb);
+		break;
+	}
+	case MKMSG_FAILED:
+	{
+		u_int scbindex;
+
+		printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       devinfo.lun);
+		scbindex = ahc_inb(ahc, SCB_TAG);
+		scb = ahc_lookup_scb(ahc, scbindex);
+		if (scb != NULL
+		 && (scb->flags & SCB_RECOVERY_SCB) != 0)
+			/*
+			 * Ensure that we didn't put a second instance of this
+			 * SCB into the QINFIFO.
+			 */
+			ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb),
+					   SCB_GET_CHANNEL(ahc, scb),
+					   SCB_GET_LUN(scb), scb->hscb->tag,
+					   ROLE_INITIATOR, /*status*/0,
+					   SEARCH_REMOVE);
+		break;
+	}
+	case NO_FREE_SCB:
+	{
+		printf("%s: No free or disconnected SCBs\n", ahc_name(ahc));
+		ahc_dump_card_state(ahc);
+		panic("for safety");
+		break;
+	}
+	case SCB_MISMATCH:
+	{
+		u_int scbptr;
+
+		scbptr = ahc_inb(ahc, SCBPTR);
+		printf("Bogus TAG after DMA.  SCBPTR %d, tag %d, our tag %d\n",
+		       scbptr, ahc_inb(ahc, ARG_1),
+		       ahc->scb_data->hscbs[scbptr].tag);
+		ahc_dump_card_state(ahc);
+		panic("for saftey");
+		break;
+	}
+	case OUT_OF_RANGE:
+	{
+		printf("%s: BTT calculation out of range\n", ahc_name(ahc));
+		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		       "ARG_1 == 0x%x ACCUM = 0x%x\n",
+		       ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
+		       ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
+		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		       "SINDEX == 0x%x\n, A == 0x%x\n",
+		       ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
+		       ahc_index_busy_tcl(ahc,
+			    BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
+				      ahc_inb(ahc, SAVED_LUN))),
+		       ahc_inb(ahc, SINDEX),
+		       ahc_inb(ahc, ACCUM));
+		printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		       "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
+		       ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
+		       ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
+		       ahc_inb(ahc, SCB_CONTROL));
+		printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+		       ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
+		ahc_dump_card_state(ahc);
+		panic("for safety");
+		break;
+	}
+	default:
+		printf("ahc_intr: seqint, "
+		       "intstat == 0x%x, scsisigi = 0x%x\n",
+		       intstat, ahc_inb(ahc, SCSISIGI));
+		break;
+	}
+unpause:
+	/*
+	 *  The sequencer is paused immediately on
+	 *  a SEQINT, so we should restart it when
+	 *  we're done.
+	 */
+	unpause_sequencer(ahc);
+}
+
+void
+ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
+{
+	u_int	scb_index;
+	u_int	status0;
+	u_int	status;
+	struct	scb *scb;
+	char	cur_channel;
+	char	intr_channel;
+
+	/* Make sure the sequencer is in a safe location. */
+	ahc_clear_critical_section(ahc);
+
+	if ((ahc->features & AHC_TWIN) != 0
+	 && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0))
+		cur_channel = 'B';
+	else
+		cur_channel = 'A';
+	intr_channel = cur_channel;
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		status0 = ahc_inb(ahc, SSTAT0) & IOERR;
+	else
+		status0 = 0;
+	status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
+	if (status == 0 && status0 == 0) {
+		if ((ahc->features & AHC_TWIN) != 0) {
+			/* Try the other channel */
+		 	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
+			status = ahc_inb(ahc, SSTAT1)
+			       & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
+			intr_channel = (cur_channel == 'A') ? 'B' : 'A';
+		}
+		if (status == 0) {
+			printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
+			ahc_outb(ahc, CLRINT, CLRSCSIINT);
+			unpause_sequencer(ahc);
+			return;
+		}
+	}
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	if (scb != NULL
+	 && (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0)
+		scb = NULL;
+
+	if ((ahc->features & AHC_ULTRA2) != 0
+	 && (status0 & IOERR) != 0) {
+		int now_lvd;
+
+		now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40;
+		printf("%s: Transceiver State Has Changed to %s mode\n",
+		       ahc_name(ahc), now_lvd ? "LVD" : "SE");
+		ahc_outb(ahc, CLRSINT0, CLRIOERR);
+		/*
+		 * When transitioning to SE mode, the reset line
+		 * glitches, triggering an arbitration bug in some
+		 * Ultra2 controllers.  This bug is cleared when we
+		 * assert the reset line.  Since a reset glitch has
+		 * already occurred with this transition and a
+		 * transceiver state change is handled just like
+		 * a bus reset anyway, asserting the reset line
+		 * ourselves is safe.
+		 */
+		ahc_reset_channel(ahc, intr_channel,
+				 /*Initiate Reset*/now_lvd == 0);
+	} else if ((status & SCSIRSTI) != 0) {
+		printf("%s: Someone reset channel %c\n",
+			ahc_name(ahc), intr_channel);
+		if (intr_channel != cur_channel)
+		 	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
+		ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/FALSE);
+	} else if ((status & SCSIPERR) != 0) {
+		/*
+		 * Determine the bus phase and queue an appropriate message.
+		 * SCSIPERR is latched true as soon as a parity error
+		 * occurs.  If the sequencer acked the transfer that
+		 * caused the parity error and the currently presented
+		 * transfer on the bus has correct parity, SCSIPERR will
+		 * be cleared by CLRSCSIPERR.  Use this to determine if
+		 * we should look at the last phase the sequencer recorded,
+		 * or the current phase presented on the bus.
+		 */
+		u_int mesg_out;
+		u_int curphase;
+		u_int errorphase;
+		u_int lastphase;
+		u_int scsirate;
+		u_int i;
+		u_int sstat2;
+
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+		sstat2 = ahc_inb(ahc, SSTAT2);
+		ahc_outb(ahc, CLRSINT1, CLRSCSIPERR);
+		/*
+		 * For all phases save DATA, the sequencer won't
+		 * automatically ack a byte that has a parity error
+		 * in it.  So the only way that the current phase
+		 * could be 'data-in' is if the parity error is for
+		 * an already acked byte in the data phase.  During
+		 * synchronous data-in transfers, we may actually
+		 * ack bytes before latching the current phase in
+		 * LASTPHASE, leading to the discrepancy between
+		 * curphase and lastphase.
+		 */
+		if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0
+		 || curphase == P_DATAIN || curphase == P_DATAIN_DT)
+			errorphase = curphase;
+		else
+			errorphase = lastphase;
+
+		for (i = 0; i < num_phases; i++) {
+			if (errorphase == phase_table[i].phase)
+				break;
+		}
+		mesg_out = phase_table[i].mesg_out;
+		if (scb != NULL)
+			ahc_print_path(ahc, scb);
+		else
+			printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
+			       SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
+		scsirate = ahc_inb(ahc, SCSIRATE);
+		printf("parity error detected %s. "
+		       "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
+		       phase_table[i].phasemsg,
+		       ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8),
+		       scsirate);
+
+		if ((ahc->features & AHC_DT) != 0) {
+
+			if ((sstat2 & CRCVALERR) != 0)
+				printf("\tCRC Value Mismatch\n");
+			if ((sstat2 & CRCENDERR) != 0)
+				printf("\tNo terminal CRC packet recevied\n");
+			if ((sstat2 & CRCREQERR) != 0)
+				printf("\tIllegal CRC packet request\n");
+			if ((sstat2 & DUAL_EDGE_ERR) != 0)
+				printf("\tUnexpected %sDT Data Phase\n",
+				       (scsirate & SINGLE_EDGE) ? "" : "non-");
+		}
+
+		/*
+		 * We've set the hardware to assert ATN if we   
+		 * get a parity error on "in" phases, so all we  
+		 * need to do is stuff the message buffer with
+		 * the appropriate message.  "In" phases have set
+		 * mesg_out to something other than MSG_NOP.
+		 */
+		if (mesg_out != MSG_NOOP) {
+			if (ahc->msg_type != MSG_TYPE_NONE)
+				ahc->send_msg_perror = TRUE;
+			else
+				ahc_outb(ahc, MSG_OUT, mesg_out);
+		}
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		unpause_sequencer(ahc);
+	} else if ((status & BUSFREE) != 0
+		&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
+		u_int lastphase;
+		u_int saved_scsiid;
+		u_int saved_lun;
+		u_int target;
+		u_int initiator_role_id;
+		char channel;
+		int printerror;
+
+		/*
+		 * Clear our selection hardware as soon as possible.
+		 * We may have an entry in the waiting Q for this target,
+		 * that is affected by this busfree and we don't want to
+		 * go about selecting the target while we handle the event.
+		 */
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+
+		/*
+		 * Disable busfree interrupts and clear the busfree
+		 * interrupt status.  We do this here so that several
+		 * bus transactions occur prior to clearing the SCSIINT
+		 * latch.  It can take a bit for the clearing to take effect.
+		 */
+		ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+		ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR);
+
+		/*
+		 * Look at what phase we were last in.
+		 * If its message out, chances are pretty good
+		 * that the busfree was in response to one of
+		 * our abort requests.
+		 */
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+		saved_lun = ahc_inb(ahc, SAVED_LUN);
+		target = SCSIID_TARGET(ahc, saved_scsiid);
+		initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
+		channel = SCSIID_CHANNEL(ahc, saved_scsiid);
+		printerror = 1;
+
+		if (lastphase == P_MESGOUT) {
+			struct ahc_devinfo devinfo;
+			u_int tag;
+
+			ahc_fetch_devinfo(ahc, &devinfo);
+			tag = SCB_LIST_NULL;
+			if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE)
+			 || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
+				if (ahc->msgout_buf[ahc->msgout_index - 1]
+				 == MSG_ABORT_TAG)
+					tag = scb->hscb->tag;
+				ahc_print_path(ahc, scb);
+				printf("SCB %d - Abort%s Completed.\n",
+				       scb->hscb->tag, tag == SCB_LIST_NULL ?
+				       "" : " Tag");
+				ahc_abort_scbs(ahc, target, channel,
+					       saved_lun, tag,
+					       ROLE_INITIATOR,
+					       CAM_REQ_ABORTED);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_1B,
+						MSG_BUS_DEV_RESET, TRUE)) {
+				struct ahc_devinfo devinfo;
+#ifdef __FreeBSD__
+				/*
+				 * Don't mark the user's request for this BDR
+				 * as completing with CAM_BDR_SENT.  CAM3
+				 * specifies CAM_REQ_CMP.
+				 */
+				if (scb != NULL
+				 && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV
+				 && ahc_match_scb(ahc, scb, target, channel,
+						  CAM_LUN_WILDCARD,
+						  SCB_LIST_NULL,
+						  ROLE_INITIATOR)) {
+					ahc_set_transaction_status(scb, CAM_REQ_CMP);
+				}
+#endif
+				ahc_compile_devinfo(&devinfo,
+						    initiator_role_id,
+						    target,
+						    CAM_LUN_WILDCARD,
+						    channel,
+						    ROLE_INITIATOR);
+				ahc_handle_devreset(ahc, &devinfo,
+						    CAM_BDR_SENT,
+						    "Bus Device Reset",
+						    /*verbose_level*/0);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
+						MSG_EXT_PPR, FALSE)) {
+				struct ahc_initiator_tinfo *tinfo;
+				struct tmode_tstate *tstate;
+
+				/*
+				 * PPR Rejected.  Try non-ppr negotiation
+				 * and retry command.
+				 */
+				tinfo = ahc_fetch_transinfo(ahc,
+							    devinfo.channel,
+							    devinfo.our_scsiid,
+							    devinfo.target,
+							    &tstate);
+				tinfo->current.transport_version = 2;
+				tinfo->goal.transport_version = 2;
+				tinfo->goal.ppr_options = 0;
+				ahc_qinfifo_requeue_tail(ahc, scb);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
+						MSG_EXT_WDTR, FALSE)
+				|| ahc_sent_msg(ahc, AHCMSG_EXT,
+						MSG_EXT_SDTR, FALSE)) {
+				/*
+				 * Negotiation Rejected.  Go-async and
+				 * retry command.
+				 */
+				ahc_set_width(ahc, &devinfo,
+					      MSG_EXT_WDTR_BUS_8_BIT,
+					      AHC_TRANS_CUR|AHC_TRANS_GOAL,
+					      /*paused*/TRUE);
+				ahc_set_syncrate(ahc, &devinfo,
+						/*syncrate*/NULL,
+						/*period*/0, /*offset*/0,
+						/*ppr_options*/0,
+						AHC_TRANS_CUR|AHC_TRANS_GOAL,
+						/*paused*/TRUE);
+				ahc_qinfifo_requeue_tail(ahc, scb);
+				printerror = 0;
+			}
+		}
+		if (printerror != 0) {
+			u_int i;
+
+			if (scb != NULL) {
+				u_int tag;
+
+				if ((scb->hscb->control & TAG_ENB) != 0)
+					tag = scb->hscb->tag;
+				else
+					tag = SCB_LIST_NULL;
+				ahc_print_path(ahc, scb);
+				ahc_abort_scbs(ahc, target, channel,
+					       SCB_GET_LUN(scb), tag,
+					       ROLE_INITIATOR,
+					       CAM_UNEXP_BUSFREE);
+			} else {
+				/*
+				 * We had not fully identified this connection,
+				 * so we cannot abort anything.
+				 */
+				printf("%s: ", ahc_name(ahc));
+			}
+			for (i = 0; i < num_phases; i++) {
+				if (lastphase == phase_table[i].phase)
+					break;
+			}
+			printf("Unexpected busfree %s\n"
+			       "SEQADDR == 0x%x\n",
+			       phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0)
+				| (ahc_inb(ahc, SEQADDR1) << 8));
+		}
+		ahc_clear_msg_state(ahc);
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		restart_sequencer(ahc);
+	} else if ((status & SELTO) != 0) {
+		u_int scbptr;
+
+		/* Stop the selection */
+		ahc_outb(ahc, SCSISEQ, 0);
+
+		/* No more pending messages */
+		ahc_clear_msg_state(ahc);
+
+		/* Clear interrupt state */
+		ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
+
+		/*
+		 * Although the driver does not care about the
+		 * 'Selection in Progress' status bit, the busy
+		 * LED does.  SELINGO is only cleared by a sucessful
+		 * selection, so we must manually clear it to insure
+		 * the LED turns off just incase no future successful
+		 * selections occur (e.g. no devices on the bus).
+		 */
+		ahc_outb(ahc, CLRSINT0, CLRSELINGO);
+
+		scbptr = ahc_inb(ahc, WAITING_SCBH);
+		ahc_outb(ahc, SCBPTR, scbptr);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("%s: ahc_intr - referenced scb not "
+			       "valid during SELTO scb(%d, %d)\n",
+			       ahc_name(ahc), scbptr, scb_index);
+		} else {
+			ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
+			ahc_freeze_devq(ahc, scb);
+		}
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		restart_sequencer(ahc);
+	} else {
+		printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
+		       ahc_name(ahc), status);
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+	}
+}
+
+#define AHC_MAX_STEPS 2000
+void
+ahc_clear_critical_section(struct ahc_softc *ahc)
+{
+	int	stepping;
+	int	steps;
+	u_int	simode0;
+	u_int	simode1;
+
+	if (ahc->num_critical_sections == 0)
+		return;
+
+	stepping = FALSE;
+	steps = 0;
+	simode0 = 0;
+	simode1 = 0;
+	for (;;) {
+		struct	cs *cs;
+		u_int	seqaddr;
+		u_int	i;
+
+		seqaddr = ahc_inb(ahc, SEQADDR0)
+			| (ahc_inb(ahc, SEQADDR1) << 8);
+
+		cs = ahc->critical_sections;
+		for (i = 0; i < ahc->num_critical_sections; i++, cs++) {
+			
+			if (cs->begin < seqaddr && cs->end >= seqaddr)
+				break;
+		}
+
+		if (i == ahc->num_critical_sections)
+			break;
+
+		if (steps > AHC_MAX_STEPS) {
+			printf("%s: Infinite loop in critical section\n",
+			       ahc_name(ahc));
+			ahc_dump_card_state(ahc);
+			panic("critical section loop");
+		}
+
+		steps++;
+		if (stepping == FALSE) {
+
+			/*
+			 * Disable all interrupt sources so that the
+			 * sequencer will not be stuck by a pausing
+			 * interrupt condition while we attempt to
+			 * leave a critical section.
+			 */
+			simode0 = ahc_inb(ahc, SIMODE0);
+			ahc_outb(ahc, SIMODE0, 0);
+			simode1 = ahc_inb(ahc, SIMODE1);
+			ahc_outb(ahc, SIMODE1, 0);
+			ahc_outb(ahc, CLRINT, CLRSCSIINT);
+			ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP);
+			stepping = TRUE;
+		}
+		ahc_outb(ahc, HCNTRL, ahc->unpause);
+		do {
+			ahc_delay(200);
+		} while (!sequencer_paused(ahc));
+	}
+	if (stepping) {
+		ahc_outb(ahc, SIMODE0, simode0);
+		ahc_outb(ahc, SIMODE1, simode1);
+		ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP);
+	}
+}
+
+/*
+ * Clear any pending interrupt status.
+ */
+void
+ahc_clear_intstat(struct ahc_softc *ahc)
+{
+	/* Clear any interrupt conditions this may have caused */
+	ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
+				|CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG|
+				CLRREQINIT);
+	ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
+	ahc_outb(ahc, CLRINT, CLRSCSIINT);
+}
+
+/**************************** Debugging Routines ******************************/
+void
+ahc_print_scb(struct scb *scb)
+{
+	int i;
+
+	struct hardware_scb *hscb = scb->hscb;
+
+	printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+	       scb,
+	       hscb->control,
+	       hscb->scsiid,
+	       hscb->lun,
+	       hscb->cdb_len);
+	i = 0;
+	printf("Shared Data: %#02x %#02x %#02x %#02x\n",
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++]);
+	printf("             %#02x %#02x %#02x %#02x\n",
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++]);
+	printf("             %#02x %#02x %#02x %#02x\n",
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++],
+	       hscb->shared_data.cdb[i++]);
+	printf("        dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
+		ahc_le32toh(hscb->dataptr),
+		ahc_le32toh(hscb->datacnt),
+		ahc_le32toh(hscb->sgptr),
+		hscb->tag);
+	if (scb->sg_count > 0) {
+		for (i = 0; i < scb->sg_count; i++) {
+			printf("sg[%d] - Addr 0x%x : Length %d\n",
+			       i,
+			       ahc_le32toh(scb->sg_list[i].addr),
+			       ahc_le32toh(scb->sg_list[i].len));
+		}
+	}
+}
+
+/************************* Transfer Negotiation *******************************/
+/*
+ * Allocate per target mode instance (ID we respond to as a target)
+ * transfer negotiation data structures.
+ */
+static struct tmode_tstate *
+ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
+{
+	struct tmode_tstate *master_tstate;
+	struct tmode_tstate *tstate;
+	int i;
+
+	master_tstate = ahc->enabled_targets[ahc->our_id];
+	if (channel == 'B') {
+		scsi_id += 8;
+		master_tstate = ahc->enabled_targets[ahc->our_id_b + 8];
+	}
+	if (ahc->enabled_targets[scsi_id] != NULL
+	 && ahc->enabled_targets[scsi_id] != master_tstate)
+		panic("%s: ahc_alloc_tstate - Target already allocated",
+		      ahc_name(ahc));
+	tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT);
+	if (tstate == NULL)
+		return (NULL);
+
+	/*
+	 * If we have allocated a master tstate, copy user settings from
+	 * the master tstate (taken from SRAM or the EEPROM) for this
+	 * channel, but reset our current and goal settings to async/narrow
+	 * until an initiator talks to us.
+	 */
+	if (master_tstate != NULL) {
+		memcpy(tstate, master_tstate, sizeof(*tstate));
+		memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
+		tstate->ultraenb = 0;
+		for (i = 0; i < 16; i++) {
+			memset(&tstate->transinfo[i].current, 0,
+			      sizeof(tstate->transinfo[i].current));
+			memset(&tstate->transinfo[i].goal, 0,
+			      sizeof(tstate->transinfo[i].goal));
+		}
+	} else
+		memset(tstate, 0, sizeof(*tstate));
+	ahc->enabled_targets[scsi_id] = tstate;
+	return (tstate);
+}
+
+#ifdef AHC_TARGET_MODE
+/*
+ * Free per target mode instance (ID we respond to as a target)
+ * transfer negotiation data structures.
+ */
+static void
+ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
+{
+	struct tmode_tstate *tstate;
+
+	/* Don't clean up the entry for our initiator role */
+	if ((ahc->flags & AHC_INITIATORROLE) != 0
+	 && ((channel == 'B' && scsi_id == ahc->our_id_b)
+	  || (channel == 'A' && scsi_id == ahc->our_id))
+	 && force == FALSE)
+		return;
+
+	if (channel == 'B')
+		scsi_id += 8;
+	tstate = ahc->enabled_targets[scsi_id];
+	if (tstate != NULL)
+		free(tstate, M_DEVBUF);
+	ahc->enabled_targets[scsi_id] = NULL;
+}
+#endif
+
+/*
+ * Called when we have an active connection to a target on the bus,
+ * this function finds the nearest syncrate to the input period limited
+ * by the capabilities of the bus connectivity of and sync settings for
+ * the target.
+ */
+struct ahc_syncrate *
+ahc_devlimited_syncrate(struct ahc_softc *ahc,
+			struct ahc_initiator_tinfo *tinfo,
+			u_int *period, u_int *ppr_options, role_t role) {
+	struct	ahc_transinfo *transinfo;
+	u_int	maxsync;
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0
+		 && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) {
+			maxsync = AHC_SYNCRATE_DT;
+		} else {
+			maxsync = AHC_SYNCRATE_ULTRA;
+			/* Can't do DT on an SE bus */
+			*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+		}
+	} else if ((ahc->features & AHC_ULTRA) != 0
+		&& (ahc->flags & AHC_ULTRA_DISABLED) == 0) {
+		maxsync = AHC_SYNCRATE_ULTRA;
+	} else {
+		maxsync = AHC_SYNCRATE_FAST;
+	}
+	/*
+	 * Never allow a value higher than our current goal
+	 * period otherwise we may allow a target initiated
+	 * negotiation to go above the limit as set by the
+	 * user.  In the case of an initiator initiated
+	 * sync negotiation, we limit based on the user
+	 * setting.  This allows the system to still accept
+	 * incoming negotiations even if target initiated
+	 * negotiation is not performed.
+	 */
+	if (role == ROLE_TARGET)
+		transinfo = &tinfo->user;
+	else 
+		transinfo = &tinfo->goal;
+	*ppr_options &= transinfo->ppr_options;
+	if (transinfo->period == 0) {
+		*period = 0;
+		*ppr_options = 0;
+		return (NULL);
+	}
+	*period = MAX(*period, transinfo->period);
+	return (ahc_find_syncrate(ahc, period, ppr_options, maxsync));
+}
+
+/*
+ * Look up the valid period to SCSIRATE conversion in our table.
+ * Return the period and offset that should be sent to the target
+ * if this was the beginning of an SDTR.
+ */
+struct ahc_syncrate *
+ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
+		  u_int *ppr_options, u_int maxsync)
+{
+	struct ahc_syncrate *syncrate;
+
+	if ((ahc->features & AHC_DT) == 0)
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+	
+	for (syncrate = &ahc_syncrates[maxsync];
+	     syncrate->rate != NULL;
+	     syncrate++) {
+
+		/*
+		 * The Ultra2 table doesn't go as low
+		 * as for the Fast/Ultra cards.
+		 */
+		if ((ahc->features & AHC_ULTRA2) != 0
+		 && (syncrate->sxfr_u2 == 0))
+			break;
+
+		/* Skip any DT entries if DT is not available */
+		if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+		 && (syncrate->sxfr_u2 & DT_SXFR) != 0)
+			continue;
+
+		if (*period <= syncrate->period) {
+			/*
+			 * When responding to a target that requests
+			 * sync, the requested rate may fall between
+			 * two rates that we can output, but still be
+			 * a rate that we can receive.  Because of this,
+			 * we want to respond to the target with
+			 * the same rate that it sent to us even
+			 * if the period we use to send data to it
+			 * is lower.  Only lower the response period
+			 * if we must.
+			 */
+			if (syncrate == &ahc_syncrates[maxsync])
+				*period = syncrate->period;
+
+			/*
+			 * At some speeds, we only support
+			 * ST transfers.
+			 */
+		 	if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
+				*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+			break;
+		}
+	}
+
+	if ((*period == 0)
+	 || (syncrate->rate == NULL)
+	 || ((ahc->features & AHC_ULTRA2) != 0
+	  && (syncrate->sxfr_u2 == 0))) {
+		/* Use asynchronous transfers. */
+		*period = 0;
+		syncrate = NULL;
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+	}
+	return (syncrate);
+}
+
+/*
+ * Convert from an entry in our syncrate table to the SCSI equivalent
+ * sync "period" factor.
+ */
+u_int
+ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
+{
+	struct ahc_syncrate *syncrate;
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		scsirate &= SXFR_ULTRA2;
+	else
+		scsirate &= SXFR;
+
+	syncrate = &ahc_syncrates[maxsync];
+	while (syncrate->rate != NULL) {
+
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			if (syncrate->sxfr_u2 == 0)
+				break;
+			else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2))
+				return (syncrate->period);
+		} else if (scsirate == (syncrate->sxfr & SXFR)) {
+				return (syncrate->period);
+		}
+		syncrate++;
+	}
+	return (0); /* async */
+}
+
+/*
+ * Truncate the given synchronous offset to a value the
+ * current adapter type and syncrate are capable of.
+ */
+void
+ahc_validate_offset(struct ahc_softc *ahc,
+		    struct ahc_initiator_tinfo *tinfo,
+		    struct ahc_syncrate *syncrate,
+		    u_int *offset, int wide, role_t role)
+{
+	u_int maxoffset;
+
+	/* Limit offset to what we can do */
+	if (syncrate == NULL) {
+		maxoffset = 0;
+	} else if ((ahc->features & AHC_ULTRA2) != 0) {
+		maxoffset = MAX_OFFSET_ULTRA2;
+	} else {
+		if (wide)
+			maxoffset = MAX_OFFSET_16BIT;
+		else
+			maxoffset = MAX_OFFSET_8BIT;
+	}
+	*offset = MIN(*offset, maxoffset);
+	if (tinfo != NULL) {
+		if (role == ROLE_TARGET)
+			*offset = MIN(*offset, tinfo->user.offset);
+		else
+			*offset = MIN(*offset, tinfo->goal.offset);
+	}
+}
+
+/*
+ * Truncate the given transfer width parameter to a value the
+ * current adapter type is capable of.
+ */
+void
+ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
+		   u_int *bus_width, role_t role)
+{
+	switch (*bus_width) {
+	default:
+		if (ahc->features & AHC_WIDE) {
+			/* Respond Wide */
+			*bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+			break;
+		}
+		/* FALLTHROUGH */
+	case MSG_EXT_WDTR_BUS_8_BIT:
+		*bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+		break;
+	}
+	if (tinfo != NULL) {
+		if (role == ROLE_TARGET)
+			*bus_width = MIN(tinfo->user.width, *bus_width);
+		else
+			*bus_width = MIN(tinfo->goal.width, *bus_width);
+	}
+}
+
+/*
+ * Update the bitmask of targets for which the controller should
+ * negotiate with at the next convenient oportunity.  This currently
+ * means the next time we send the initial identify messages for
+ * a new transaction.
+ */
+void
+ahc_update_target_msg_request(struct ahc_softc *ahc,
+			      struct ahc_devinfo *devinfo,
+			      struct ahc_initiator_tinfo *tinfo,
+			      int force, int paused)
+{
+	u_int targ_msg_req_orig;
+
+	targ_msg_req_orig = ahc->targ_msg_req;
+	if (tinfo->current.period != tinfo->goal.period
+	 || tinfo->current.width != tinfo->goal.width
+	 || tinfo->current.offset != tinfo->goal.offset
+	 || tinfo->current.ppr_options != tinfo->goal.ppr_options
+	 || (force
+	  && (tinfo->goal.period != 0
+	   || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
+	   || tinfo->goal.ppr_options != 0)))
+		ahc->targ_msg_req |= devinfo->target_mask;
+	else
+		ahc->targ_msg_req &= ~devinfo->target_mask;
+
+	if (ahc->targ_msg_req != targ_msg_req_orig) {
+		/* Update the message request bit for this target */
+		if (!paused)
+			pause_sequencer(ahc);
+
+		ahc_outb(ahc, TARGET_MSG_REQUEST,
+			 ahc->targ_msg_req & 0xFF);
+		ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
+			 (ahc->targ_msg_req >> 8) & 0xFF);
+
+		if (!paused)
+			unpause_sequencer(ahc);
+	}
+}
+
+/*
+ * Update the user/goal/current tables of synchronous negotiation
+ * parameters as well as, in the case of a current or active update,
+ * any data structures on the host controller.  In the case of an
+ * active update, the specified target is currently talking to us on
+ * the bus, so the transfer parameter update must take effect
+ * immediately.
+ */
+void
+ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		 struct ahc_syncrate *syncrate, u_int period,
+		 u_int offset, u_int ppr_options, u_int type, int paused)
+{
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	tmode_tstate *tstate;
+	u_int	old_period;
+	u_int	old_offset;
+	u_int	old_ppr;
+	int	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+
+	if (syncrate == NULL) {
+		period = 0;
+		offset = 0;
+	}
+
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	if ((type & AHC_TRANS_USER) != 0) {
+		tinfo->user.period = period;
+		tinfo->user.offset = offset;
+		tinfo->user.ppr_options = ppr_options;
+	}
+
+	if ((type & AHC_TRANS_GOAL) != 0) {
+		tinfo->goal.period = period;
+		tinfo->goal.offset = offset;
+		tinfo->goal.ppr_options = ppr_options;
+	}
+
+	old_period = tinfo->current.period;
+	old_offset = tinfo->current.offset;
+	old_ppr	   = tinfo->current.ppr_options;
+
+	if ((type & AHC_TRANS_CUR) != 0
+	 && (old_period != period
+	  || old_offset != offset
+	  || old_ppr != ppr_options)) {
+		u_int	scsirate;
+
+		scsirate = tinfo->scsirate;
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+
+			scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC);
+			if (syncrate != NULL) {
+				scsirate |= syncrate->sxfr_u2;
+				if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0)
+					scsirate |= ENABLE_CRC;
+				else
+					scsirate |= SINGLE_EDGE;
+			}
+		} else {
+
+			scsirate &= ~(SXFR|SOFS);
+			/*
+			 * Ensure Ultra mode is set properly for
+			 * this target.
+			 */
+			tstate->ultraenb &= ~devinfo->target_mask;
+			if (syncrate != NULL) {
+				if (syncrate->sxfr & ULTRA_SXFR) {
+					tstate->ultraenb |=
+						devinfo->target_mask;
+				}
+				scsirate |= syncrate->sxfr & SXFR;
+				scsirate |= offset & SOFS;
+			}
+			if (active) {
+				u_int sxfrctl0;
+
+				sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
+				sxfrctl0 &= ~FAST20;
+				if (tstate->ultraenb & devinfo->target_mask)
+					sxfrctl0 |= FAST20;
+				ahc_outb(ahc, SXFRCTL0, sxfrctl0);
+			}
+		}
+		if (active) {
+			ahc_outb(ahc, SCSIRATE, scsirate);
+			if ((ahc->features & AHC_ULTRA2) != 0)
+				ahc_outb(ahc, SCSIOFFSET, offset);
+		}
+
+		tinfo->scsirate = scsirate;
+		tinfo->current.period = period;
+		tinfo->current.offset = offset;
+		tinfo->current.ppr_options = ppr_options;
+
+		/* Update the syncrates in any pending scbs */
+		ahc_update_pending_syncrates(ahc);
+
+		ahc_send_async(ahc, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
+		if (bootverbose) {
+			if (offset != 0) {
+				printf("%s: target %d synchronous at %sMHz%s, "
+				       "offset = 0x%x\n", ahc_name(ahc),
+				       devinfo->target, syncrate->rate,
+				       (ppr_options & MSG_EXT_PPR_DT_REQ)
+				       ? " DT" : "", offset);
+			} else {
+				printf("%s: target %d using "
+				       "asynchronous transfers\n",
+				       ahc_name(ahc), devinfo->target);
+			}
+		}
+	}
+
+	ahc_update_target_msg_request(ahc, devinfo, tinfo,
+				      /*force*/FALSE,
+				      paused);
+}
+
+/*
+ * Update the user/goal/current tables of wide negotiation
+ * parameters as well as, in the case of a current or active update,
+ * any data structures on the host controller.  In the case of an
+ * active update, the specified target is currently talking to us on
+ * the bus, so the transfer parameter update must take effect
+ * immediately.
+ */
+void
+ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+	      u_int width, u_int type, int paused)
+{
+	struct ahc_initiator_tinfo *tinfo;
+	struct tmode_tstate *tstate;
+	u_int  oldwidth;
+	int    active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	if ((type & AHC_TRANS_USER) != 0)
+		tinfo->user.width = width;
+
+	if ((type & AHC_TRANS_GOAL) != 0)
+		tinfo->goal.width = width;
+
+	oldwidth = tinfo->current.width;
+	if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) {
+		u_int	scsirate;
+
+		scsirate =  tinfo->scsirate;
+		scsirate &= ~WIDEXFER;
+		if (width == MSG_EXT_WDTR_BUS_16_BIT)
+			scsirate |= WIDEXFER;
+
+		tinfo->scsirate = scsirate;
+
+		if (active)
+			ahc_outb(ahc, SCSIRATE, scsirate);
+
+		tinfo->current.width = width;
+
+		ahc_send_async(ahc, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
+		if (bootverbose) {
+			printf("%s: target %d using %dbit transfers\n",
+			       ahc_name(ahc), devinfo->target,
+			       8 * (0x01 << width));
+		}
+	}
+
+	ahc_update_target_msg_request(ahc, devinfo, tinfo,
+				      /*force*/FALSE, paused);
+}
+
+/*
+ * Update the current state of tagged queuing for a given target.
+ */
+void
+ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable)
+{
+	struct ahc_initiator_tinfo *tinfo;
+	struct tmode_tstate *tstate;
+	uint16_t orig_tagenable;
+
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	orig_tagenable = tstate->tagenable;
+	if (enable)
+		tstate->tagenable |= devinfo->target_mask;
+	else
+		tstate->tagenable &= ~devinfo->target_mask;
+
+	if (orig_tagenable != tstate->tagenable) {
+		ahc_platform_set_tags(ahc, devinfo, enable);
+		ahc_send_async(ahc, devinfo->channel, devinfo->target,
+			       devinfo->lun, AC_TRANSFER_NEG);
+	}
+
+}
+
+/*
+ * When the transfer settings for a connection change, update any
+ * in-transit SCBs to contain the new data so the hardware will
+ * be set correctly during future (re)selections.
+ */
+static void
+ahc_update_pending_syncrates(struct ahc_softc *ahc)
+{
+	struct	scb *pending_scb;
+	int	pending_scb_count;
+	int	i;
+	u_int	saved_scbptr;
+
+	/*
+	 * Traverse the pending SCB list and ensure that all of the
+	 * SCBs there have the proper settings.
+	 */
+	pending_scb_count = 0;
+	LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
+		struct ahc_devinfo devinfo;
+		struct hardware_scb *pending_hscb;
+		struct ahc_initiator_tinfo *tinfo;
+		struct tmode_tstate *tstate;
+		
+		ahc_scb_devinfo(ahc, &devinfo, pending_scb);
+		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
+					    devinfo.our_scsiid,
+					    devinfo.target, &tstate);
+		pending_hscb = pending_scb->hscb;
+		pending_hscb->control &= ~ULTRAENB;
+		if ((tstate->ultraenb & devinfo.target_mask) != 0)
+			pending_hscb->control |= ULTRAENB;
+		pending_hscb->scsirate = tinfo->scsirate;
+		pending_hscb->scsioffset = tinfo->current.offset;
+		pending_scb_count++;
+	}
+
+	if (pending_scb_count == 0)
+		return;
+
+	saved_scbptr = ahc_inb(ahc, SCBPTR);
+	/* Ensure that the hscbs down on the card match the new information */
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		struct	hardware_scb *pending_hscb;
+		u_int	control;
+		u_int	scb_tag;
+
+		ahc_outb(ahc, SCBPTR, i);
+		scb_tag = ahc_inb(ahc, SCB_TAG);
+		pending_scb = ahc_lookup_scb(ahc, scb_tag);
+		if (pending_scb == NULL)
+			continue;
+
+		pending_hscb = pending_scb->hscb;
+		control = ahc_inb(ahc, SCB_CONTROL);
+		control &= ~ULTRAENB;
+		if ((pending_hscb->control & ULTRAENB) != 0)
+			control |= ULTRAENB;
+		ahc_outb(ahc, SCB_CONTROL, control);
+		ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate);
+		ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset);
+	}
+	ahc_outb(ahc, SCBPTR, saved_scbptr);
+}
+
+/**************************** Pathing Information *****************************/
+static void
+ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	u_int	saved_scsiid;
+	role_t	role;
+	int	our_id;
+
+	if (ahc_inb(ahc, SSTAT0) & TARGET)
+		role = ROLE_TARGET;
+	else
+		role = ROLE_INITIATOR;
+
+	if (role == ROLE_TARGET
+	 && (ahc->features & AHC_MULTI_TID) != 0
+	 && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) {
+		/* We were selected, so pull our id from TARGIDIN */
+		our_id = ahc_inb(ahc, TARGIDIN) & OID;
+	} else if ((ahc->features & AHC_ULTRA2) != 0)
+		our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
+	else
+		our_id = ahc_inb(ahc, SCSIID) & OID;
+
+	saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+	ahc_compile_devinfo(devinfo,
+			    our_id,
+			    SCSIID_TARGET(ahc, saved_scsiid),
+			    ahc_inb(ahc, SAVED_LUN),
+			    SCSIID_CHANNEL(ahc, saved_scsiid),
+			    role);
+}
+
+void
+ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
+		    u_int lun, char channel, role_t role)
+{
+	devinfo->our_scsiid = our_id;
+	devinfo->target = target;
+	devinfo->lun = lun;
+	devinfo->target_offset = target;
+	devinfo->channel = channel;
+	devinfo->role = role;
+	if (channel == 'B')
+		devinfo->target_offset += 8;
+	devinfo->target_mask = (0x01 << devinfo->target_offset);
+}
+
+static void
+ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		struct scb *scb)
+{
+	role_t	role;
+	int	our_id;
+
+	our_id = SCSIID_OUR_ID(scb->hscb->scsiid);
+	role = ROLE_INITIATOR;
+	if ((scb->hscb->control & TARGET_SCB) != 0)
+		role = ROLE_TARGET;
+	ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb),
+			    SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role);
+}
+
+
+/************************ Message Phase Processing ****************************/
+/*
+ * When an initiator transaction with the MK_MESSAGE flag either reconnects
+ * or enters the initial message out phase, we are interrupted.  Fill our
+ * outgoing message buffer with the appropriate message and beging handing
+ * the message phase(s) manually.
+ */
+static void
+ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+			   struct scb *scb)
+{
+	/*
+	 * To facilitate adding multiple messages together,
+	 * each routine should increment the index and len
+	 * variables instead of setting them explicitly.
+	 */
+	ahc->msgout_index = 0;
+	ahc->msgout_len = 0;
+
+	if ((scb->flags & SCB_DEVICE_RESET) == 0
+	 && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) {
+		u_int identify_msg;
+
+		identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb);
+		if ((scb->hscb->control & DISCENB) != 0)
+			identify_msg |= MSG_IDENTIFY_DISCFLAG;
+		ahc->msgout_buf[ahc->msgout_index++] = identify_msg;
+		ahc->msgout_len++;
+
+		if ((scb->hscb->control & TAG_ENB) != 0) {
+			ahc->msgout_buf[ahc->msgout_index++] =
+			    scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE);
+			ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag;
+			ahc->msgout_len += 2;
+		}
+	}
+
+	if (scb->flags & SCB_DEVICE_RESET) {
+		ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET;
+		ahc->msgout_len++;
+		ahc_print_path(ahc, scb);
+		printf("Bus Device Reset Message Sent\n");
+		/*
+		 * Clear our selection hardware in advance of
+		 * the busfree.  We may have an entry in the waiting
+		 * Q for this target, and we don't want to go about
+		 * selecting while we handle the busfree and blow it
+		 * away.
+		 */
+		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+	} else if ((scb->flags & SCB_ABORT) != 0) {
+		if ((scb->hscb->control & TAG_ENB) != 0)
+			ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG;
+		else
+			ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT;
+		ahc->msgout_len++;
+		ahc_print_path(ahc, scb);
+		printf("Abort%s Message Sent\n",
+		       (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
+		/*
+		 * Clear our selection hardware in advance of
+		 * the busfree.  We may have an entry in the waiting
+		 * Q for this target, and we don't want to go about
+		 * selecting while we handle the busfree and blow it
+		 * away.
+		 */
+		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+	} else if ((ahc->targ_msg_req & devinfo->target_mask) != 0
+		|| (scb->flags & SCB_NEGOTIATE) != 0) {
+		ahc_build_transfer_msg(ahc, devinfo);
+	} else {
+		printf("ahc_intr: AWAITING_MSG for an SCB that "
+		       "does not have a waiting message\n");
+		printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+		       devinfo->target_mask);
+		panic("SCB = %d, SCB Control = %x, MSG_OUT = %x "
+		      "SCB flags = %x", scb->hscb->tag, scb->hscb->control,
+		      ahc_inb(ahc, MSG_OUT), scb->flags);
+	}
+
+	/*
+	 * Clear the MK_MESSAGE flag from the SCB so we aren't
+	 * asked to send this message again.
+	 */
+	ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE);
+	ahc->msgout_index = 0;
+	ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+}
+
+/*
+ * Build an appropriate transfer negotiation message for the
+ * currently active target.
+ */
+static void
+ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	/*
+	 * We need to initiate transfer negotiations.
+	 * If our current and goal settings are identical,
+	 * we want to renegotiate due to a check condition.
+	 */
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	tmode_tstate *tstate;
+	struct	ahc_syncrate *rate;
+	int	dowide;
+	int	dosync;
+	int	doppr;
+	int	use_ppr;
+	u_int	period;
+	u_int	ppr_options;
+	u_int	offset;
+
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	dowide = tinfo->current.width != tinfo->goal.width;
+	dosync = tinfo->current.period != tinfo->goal.period;
+	doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options;
+
+	if (!dowide && !dosync && !doppr) {
+		dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
+		dosync = tinfo->goal.period != 0;
+		doppr = tinfo->goal.ppr_options != 0;
+	}
+
+	if (!dowide && !dosync && !doppr) {
+		panic("ahc_intr: AWAITING_MSG for negotiation, "
+		      "but no negotiation needed\n");	
+	}
+
+	use_ppr = (tinfo->current.transport_version >= 3) || doppr;
+	/* Target initiated PPR is not allowed in the SCSI spec */
+	if (devinfo->role == ROLE_TARGET)
+		use_ppr = 0;
+
+	/*
+	 * Both the PPR message and SDTR message require the
+	 * goal syncrate to be limited to what the target device
+	 * is capable of handling (based on whether an LVD->SE
+	 * expander is on the bus), so combine these two cases.
+	 * Regardless, guarantee that if we are using WDTR and SDTR
+	 * messages that WDTR comes first.
+	 */
+	if (use_ppr || (dosync && !dowide)) {
+
+		period = tinfo->goal.period;
+		ppr_options = tinfo->goal.ppr_options;
+		if (use_ppr == 0)
+			ppr_options = 0;
+		rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+					       &ppr_options, devinfo->role);
+		offset = tinfo->goal.offset;
+		ahc_validate_offset(ahc, tinfo, rate, &offset,
+				    use_ppr ? tinfo->goal.width
+					    : tinfo->current.width,
+				    devinfo->role);
+		if (use_ppr) {
+			ahc_construct_ppr(ahc, devinfo, period, offset,
+					  tinfo->goal.width, ppr_options);
+		} else {
+			ahc_construct_sdtr(ahc, devinfo, period, offset);
+		}
+	} else {
+		ahc_construct_wdtr(ahc, devinfo, tinfo->goal.width);
+	}
+}
+
+/*
+ * Build a synchronous negotiation message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		   u_int period, u_int offset)
+{
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
+	ahc->msgout_buf[ahc->msgout_index++] = period;
+	ahc->msgout_buf[ahc->msgout_index++] = offset;
+	ahc->msgout_len += 5;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+		       ahc_name(ahc), devinfo->channel, devinfo->target,
+		       devinfo->lun, period, offset);
+	}
+}
+
+/*
+ * Build a wide negotiateion message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		   u_int bus_width)
+{
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR;
+	ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+	ahc->msgout_len += 4;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+		       ahc_name(ahc), devinfo->channel, devinfo->target,
+		       devinfo->lun, bus_width);
+	}
+}
+
+/*
+ * Build a parallel protocol request message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		  u_int period, u_int offset, u_int bus_width,
+		  u_int ppr_options)
+{
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
+	ahc->msgout_buf[ahc->msgout_index++] = period;
+	ahc->msgout_buf[ahc->msgout_index++] = 0;
+	ahc->msgout_buf[ahc->msgout_index++] = offset;
+	ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+	ahc->msgout_buf[ahc->msgout_index++] = ppr_options;
+	ahc->msgout_len += 8;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+		       "offset %x, ppr_options %x\n", ahc_name(ahc),
+		       devinfo->channel, devinfo->target, devinfo->lun,
+		       bus_width, period, offset, ppr_options);
+	}
+}
+
+/*
+ * Clear any active message state.
+ */
+static void
+ahc_clear_msg_state(struct ahc_softc *ahc)
+{
+	ahc->msgout_len = 0;
+	ahc->msgin_index = 0;
+	ahc->msg_type = MSG_TYPE_NONE;
+	if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) {
+		/*
+		 * The target didn't care to respond to our
+		 * message request, so clear ATN.
+		 */
+		ahc_outb(ahc, CLRSINT1, CLRATNO);
+	}
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+}
+
+/*
+ * Manual message loop handler.
+ */
+static void
+ahc_handle_message_phase(struct ahc_softc *ahc)
+{ 
+	struct	ahc_devinfo devinfo;
+	u_int	bus_phase;
+	int	end_session;
+
+	ahc_fetch_devinfo(ahc, &devinfo);
+	end_session = FALSE;
+	bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+
+reswitch:
+	switch (ahc->msg_type) {
+	case MSG_TYPE_INITIATOR_MSGOUT:
+	{
+		int lastbyte;
+		int phasemis;
+		int msgdone;
+
+		if (ahc->msgout_len == 0)
+			panic("HOST_MSG_LOOP interrupt with no active message");
+
+		phasemis = bus_phase != P_MESGOUT;
+		if (phasemis) {
+			if (bus_phase == P_MESGIN) {
+				/*
+				 * Change gears and see if
+				 * this messages is of interest to
+				 * us or should be passed back to
+				 * the sequencer.
+				 */
+				ahc_outb(ahc, CLRSINT1, CLRATNO);
+				ahc->send_msg_perror = FALSE;
+				ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+				ahc->msgin_index = 0;
+				goto reswitch;
+			}
+			end_session = TRUE;
+			break;
+		}
+
+		if (ahc->send_msg_perror) {
+			ahc_outb(ahc, CLRSINT1, CLRATNO);
+			ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+			ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR);
+			break;
+		}
+
+		msgdone	= ahc->msgout_index == ahc->msgout_len;
+		if (msgdone) {
+			/*
+			 * The target has requested a retry.
+			 * Re-assert ATN, reset our message index to
+			 * 0, and try again.
+			 */
+			ahc->msgout_index = 0;
+			ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
+		}
+
+		lastbyte = ahc->msgout_index == (ahc->msgout_len - 1);
+		if (lastbyte) {
+			/* Last byte is signified by dropping ATN */
+			ahc_outb(ahc, CLRSINT1, CLRATNO);
+		}
+
+		/*
+		 * Clear our interrupt status and present
+		 * the next byte on the bus.
+		 */
+		ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+		ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
+		break;
+	}
+	case MSG_TYPE_INITIATOR_MSGIN:
+	{
+		int phasemis;
+		int message_done;
+
+		phasemis = bus_phase != P_MESGIN;
+
+		if (phasemis) {
+			ahc->msgin_index = 0;
+			if (bus_phase == P_MESGOUT
+			 && (ahc->send_msg_perror == TRUE
+			  || (ahc->msgout_len != 0
+			   && ahc->msgout_index == 0))) {
+				ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+				goto reswitch;
+			}
+			end_session = TRUE;
+			break;
+		}
+
+		/* Pull the byte in without acking it */
+		ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);
+
+		message_done = ahc_parse_msg(ahc, &devinfo);
+
+		if (message_done) {
+			/*
+			 * Clear our incoming message buffer in case there
+			 * is another message following this one.
+			 */
+			ahc->msgin_index = 0;
+
+			/*
+			 * If this message illicited a response,
+			 * assert ATN so the target takes us to the
+			 * message out phase.
+			 */
+			if (ahc->msgout_len != 0)
+				ahc_outb(ahc, SCSISIGO,
+					 ahc_inb(ahc, SCSISIGO) | ATNO);
+		} else 
+			ahc->msgin_index++;
+
+		/* Ack the byte */
+		ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+		ahc_inb(ahc, SCSIDATL);
+		break;
+	}
+	case MSG_TYPE_TARGET_MSGIN:
+	{
+		int msgdone;
+		int msgout_request;
+
+		if (ahc->msgout_len == 0)
+			panic("Target MSGIN with no active message");
+
+		/*
+		 * If we interrupted a mesgout session, the initiator
+		 * will not know this until our first REQ.  So, we
+		 * only honor mesgout requests after we've sent our
+		 * first byte.
+		 */
+		if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0
+		 && ahc->msgout_index > 0)
+			msgout_request = TRUE;
+		else
+			msgout_request = FALSE;
+
+		if (msgout_request) {
+
+			/*
+			 * Change gears and see if
+			 * this messages is of interest to
+			 * us or should be passed back to
+			 * the sequencer.
+			 */
+			ahc->msg_type = MSG_TYPE_TARGET_MSGOUT;
+			ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO);
+			ahc->msgin_index = 0;
+			/* Dummy read to REQ for first byte */
+			ahc_inb(ahc, SCSIDATL);
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+			break;
+		}
+
+		msgdone = ahc->msgout_index == ahc->msgout_len;
+		if (msgdone) {
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+			end_session = TRUE;
+			break;
+		}
+
+		/*
+		 * Present the next byte on the bus.
+		 */
+		ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+		ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
+		break;
+	}
+	case MSG_TYPE_TARGET_MSGOUT:
+	{
+		int lastbyte;
+		int msgdone;
+
+		/*
+		 * The initiator signals that this is
+		 * the last byte by dropping ATN.
+		 */
+		lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0;
+
+		/*
+		 * Read the latched byte, but turn off SPIOEN first
+		 * so that we don't inadvertantly cause a REQ for the
+		 * next byte.
+		 */
+		ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+		ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL);
+		msgdone = ahc_parse_msg(ahc, &devinfo);
+		if (msgdone == MSGLOOP_TERMINATED) {
+			/*
+			 * The message is *really* done in that it caused
+			 * us to go to bus free.  The sequencer has already
+			 * been reset at this point, so pull the ejection
+			 * handle.
+			 */
+			return;
+		}
+		
+		ahc->msgin_index++;
+
+		/*
+		 * XXX Read spec about initiator dropping ATN too soon
+		 *     and use msgdone to detect it.
+		 */
+		if (msgdone == MSGLOOP_MSGCOMPLETE) {
+			ahc->msgin_index = 0;
+
+			/*
+			 * If this message illicited a response, transition
+			 * to the Message in phase and send it.
+			 */
+			if (ahc->msgout_len != 0) {
+				ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO);
+				ahc_outb(ahc, SXFRCTL0,
+					 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+				ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
+				ahc->msgin_index = 0;
+				break;
+			}
+		}
+
+		if (lastbyte)
+			end_session = TRUE;
+		else {
+			/* Ask for the next byte. */
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+		}
+
+		break;
+	}
+	default:
+		panic("Unknown REQINIT message type");
+	}
+
+	if (end_session) {
+		ahc_clear_msg_state(ahc);
+		ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP);
+	} else
+		ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
+}
+
+/*
+ * See if we sent a particular extended message to the target.
+ * If "full" is true, return true only if the target saw the full
+ * message.  If "full" is false, return true if the target saw at
+ * least the first byte of the message.
+ */
+static int
+ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full)
+{
+	int found;
+	u_int index;
+
+	found = FALSE;
+	index = 0;
+
+	while (index < ahc->msgout_len) {
+		if (ahc->msgout_buf[index] == MSG_EXTENDED) {
+			u_int end_index;
+
+			end_index = index + 1 + ahc->msgout_buf[index + 1];
+			if (ahc->msgout_buf[index+2] == msgval
+			 && type == AHCMSG_EXT) {
+
+				if (full) {
+					if (ahc->msgout_index > end_index)
+						found = TRUE;
+				} else if (ahc->msgout_index > index)
+					found = TRUE;
+			}
+			index = end_index;
+		} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG
+			&& ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
+
+			/* Skip tag type and tag id or residue param*/
+			index += 2;
+		} else {
+			/* Single byte message */
+			if (type == AHCMSG_1B
+			 && ahc->msgout_buf[index] == msgval
+			 && ahc->msgout_index > index)
+				found = TRUE;
+			index++;
+		}
+
+		if (found)
+			break;
+	}
+	return (found);
+}
+
+/*
+ * Wait for a complete incomming message, parse it, and respond accordingly.
+ */
+static int
+ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	tmode_tstate *tstate;
+	int	reject;
+	int	done;
+	int	response;
+	u_int	targ_scsirate;
+
+	done = MSGLOOP_IN_PROG;
+	response = FALSE;
+	reject = FALSE;
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	targ_scsirate = tinfo->scsirate;
+
+	/*
+	 * Parse as much of the message as is availible,
+	 * rejecting it if we don't support it.  When
+	 * the entire message is availible and has been
+	 * handled, return MSGLOOP_MSGCOMPLETE, indicating
+	 * that we have parsed an entire message.
+	 *
+	 * In the case of extended messages, we accept the length
+	 * byte outright and perform more checking once we know the
+	 * extended message type.
+	 */
+	switch (ahc->msgin_buf[0]) {
+	case MSG_MESSAGE_REJECT:
+		response = ahc_handle_msg_reject(ahc, devinfo);
+		/* FALLTHROUGH */
+	case MSG_NOOP:
+		done = MSGLOOP_MSGCOMPLETE;
+		break;
+	case MSG_EXTENDED:
+	{
+		/* Wait for enough of the message to begin validation */
+		if (ahc->msgin_index < 2)
+			break;
+		switch (ahc->msgin_buf[2]) {
+		case MSG_EXT_SDTR:
+		{
+			struct	 ahc_syncrate *syncrate;
+			u_int	 period;
+			u_int	 ppr_options;
+			u_int	 offset;
+			u_int	 saved_offset;
+			
+			if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have both args before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_SDTR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1))
+				break;
+
+			period = ahc->msgin_buf[3];
+			ppr_options = 0;
+			saved_offset = offset = ahc->msgin_buf[4];
+			syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+							   &ppr_options,
+							   devinfo->role);
+			ahc_validate_offset(ahc, tinfo, syncrate, &offset,
+					    targ_scsirate & WIDEXFER,
+					    devinfo->role);
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received "
+				       "SDTR period %x, offset %x\n\t"
+				       "Filtered to period %x, offset %x\n",
+				       ahc_name(ahc), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       ahc->msgin_buf[3], saved_offset,
+				       period, offset);
+			}
+			ahc_set_syncrate(ahc, devinfo, 
+					 syncrate, period,
+					 offset, ppr_options,
+					 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+					 /*paused*/TRUE);
+
+			/*
+			 * See if we initiated Sync Negotiation
+			 * and didn't have to fall down to async
+			 * transfers.
+			 */
+			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) {
+				/* We started it */
+				if (saved_offset != offset) {
+					/* Went too low - force async */
+					reject = TRUE;
+				}
+			} else {
+				/*
+				 * Send our own SDTR in reply
+				 */
+				if (bootverbose) {
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated SDTR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				}
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_construct_sdtr(ahc, devinfo,
+						   period, offset);
+				ahc->msgout_index = 0;
+				response = TRUE;
+			}
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		case MSG_EXT_WDTR:
+		{
+			u_int bus_width;
+			u_int saved_width;
+			u_int sending_reply;
+
+			sending_reply = FALSE;
+			if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have our arg before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_WDTR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1))
+				break;
+
+			bus_width = ahc->msgin_buf[3];
+			saved_width = bus_width;
+			ahc_validate_width(ahc, tinfo, &bus_width,
+					   devinfo->role);
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received WDTR "
+				       "%x filtered to %x\n",
+				       ahc_name(ahc), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       saved_width, bus_width);
+			}
+
+			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) {
+				/*
+				 * Don't send a WDTR back to the
+				 * target, since we asked first.
+				 * If the width went higher than our
+				 * request, reject it.
+				 */
+				if (saved_width > bus_width) {
+					reject = TRUE;
+					printf("(%s:%c:%d:%d): requested %dBit "
+					       "transfers.  Rejecting...\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun,
+					       8 * (0x01 << bus_width));
+					bus_width = 0;
+				}
+			} else {
+				/*
+				 * Send our own WDTR in reply
+				 */
+				if (bootverbose) {
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated WDTR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				}
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_construct_wdtr(ahc, devinfo, bus_width);
+				ahc->msgout_index = 0;
+				response = TRUE;
+				sending_reply = TRUE;
+			}
+			ahc_set_width(ahc, devinfo, bus_width,
+				      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+				      /*paused*/TRUE);
+			/* After a wide message, we are async */
+			ahc_set_syncrate(ahc, devinfo,
+					 /*syncrate*/NULL, /*period*/0,
+					 /*offset*/0, /*ppr_options*/0,
+					 AHC_TRANS_ACTIVE, /*paused*/TRUE);
+			if (sending_reply == FALSE && reject == FALSE) {
+
+				if (tinfo->goal.period) {
+					ahc->msgout_index = 0;
+					ahc->msgout_len = 0;
+					ahc_build_transfer_msg(ahc, devinfo);
+					ahc->msgout_index = 0;
+					response = TRUE;
+				}
+			}
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		case MSG_EXT_PPR:
+		{
+			struct	ahc_syncrate *syncrate;
+			u_int	period;
+			u_int	offset;
+			u_int	bus_width;
+			u_int	ppr_options;
+			u_int	saved_width;
+			u_int	saved_offset;
+			u_int	saved_ppr_options;
+
+			if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have all args before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_PPR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1))
+				break;
+
+			period = ahc->msgin_buf[3];
+			offset = ahc->msgin_buf[5];
+			bus_width = ahc->msgin_buf[6];
+			saved_width = bus_width;
+			ppr_options = ahc->msgin_buf[7];
+			/*
+			 * According to the spec, a DT only
+			 * period factor with no DT option
+			 * set implies async.
+			 */
+			if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+			 && period == 9)
+				offset = 0;
+			saved_ppr_options = ppr_options;
+			saved_offset = offset;
+
+			/*
+			 * Mask out any options we don't support
+			 * on any controller.  Transfer options are
+			 * only available if we are negotiating wide.
+			 */
+			ppr_options &= MSG_EXT_PPR_DT_REQ;
+			if (bus_width == 0)
+				ppr_options = 0;
+
+			ahc_validate_width(ahc, tinfo, &bus_width,
+					   devinfo->role);
+			syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+							   &ppr_options,
+							   devinfo->role);
+			ahc_validate_offset(ahc, tinfo, syncrate,
+					    &offset, bus_width,
+					    devinfo->role);
+
+			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) {
+				/*
+				 * If we are unable to do any of the
+				 * requested options (we went too low),
+				 * then we'll have to reject the message.
+				 */
+				if (saved_width > bus_width
+				 || saved_offset != offset
+				 || saved_ppr_options != ppr_options) {
+					reject = TRUE;
+					period = 0;
+					offset = 0;
+					bus_width = 0;
+					ppr_options = 0;
+					syncrate = NULL;
+				}
+			} else {
+				if (devinfo->role != ROLE_TARGET)
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated PPR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				else
+					printf("(%s:%c:%d:%d): Initiator "
+					       "Initiated PPR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_construct_ppr(ahc, devinfo, period, offset,
+						  bus_width, ppr_options);
+				ahc->msgout_index = 0;
+				response = TRUE;
+			}
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received PPR width %x, "
+				       "period %x, offset %x,options %x\n"
+				       "\tFiltered to width %x, period %x, "
+				       "offset %x, options %x\n",
+				       ahc_name(ahc), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       ahc->msgin_buf[3], saved_width,
+				       saved_offset, saved_ppr_options,
+				       bus_width, period, offset, ppr_options);
+			}
+			ahc_set_width(ahc, devinfo, bus_width,
+				      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+				      /*paused*/TRUE);
+			ahc_set_syncrate(ahc, devinfo,
+					 syncrate, period,
+					 offset, ppr_options,
+					 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+					 /*paused*/TRUE);
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		default:
+			/* Unknown extended message.  Reject it. */
+			reject = TRUE;
+			break;
+		}
+		break;
+	}
+	case MSG_BUS_DEV_RESET:
+		ahc_handle_devreset(ahc, devinfo,
+				    CAM_BDR_SENT,
+				    "Bus Device Reset Received",
+				    /*verbose_level*/0);
+		restart_sequencer(ahc);
+		done = MSGLOOP_TERMINATED;
+		break;
+	case MSG_ABORT_TAG:
+	case MSG_ABORT:
+	case MSG_CLEAR_QUEUE:
+#ifdef AHC_TARGET_MODE
+		/* Target mode messages */
+		if (devinfo->role != ROLE_TARGET) {
+			reject = TRUE;
+			break;
+		}
+		ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
+			       devinfo->lun,
+			       ahc->msgin_buf[0] == MSG_ABORT_TAG
+						  ? SCB_LIST_NULL
+						  : ahc_inb(ahc, INITIATOR_TAG),
+			       ROLE_TARGET, CAM_REQ_ABORTED);
+
+		tstate = ahc->enabled_targets[devinfo->our_scsiid];
+		if (tstate != NULL) {
+			struct tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[devinfo->lun];
+			if (lstate != NULL) {
+				ahc_queue_lstate_event(ahc, lstate,
+						       devinfo->our_scsiid,
+						       ahc->msgin_buf[0],
+						       /*arg*/0);
+				ahc_send_lstate_events(ahc, lstate);
+			}
+		}
+		done = MSGLOOP_MSGCOMPLETE;
+		break;
+#endif
+	case MSG_TERM_IO_PROC:
+	default:
+		reject = TRUE;
+		break;
+	}
+
+	if (reject) {
+		/*
+		 * Setup to reject the message.
+		 */
+		ahc->msgout_index = 0;
+		ahc->msgout_len = 1;
+		ahc->msgout_buf[0] = MSG_MESSAGE_REJECT;
+		done = MSGLOOP_MSGCOMPLETE;
+		response = TRUE;
+	}
+
+	if (done != MSGLOOP_IN_PROG && !response)
+		/* Clear the outgoing message buffer */
+		ahc->msgout_len = 0;
+
+	return (done);
+}
+
+/*
+ * Process a message reject message.
+ */
+static int
+ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	/*
+	 * What we care about here is if we had an
+	 * outstanding SDTR or WDTR message for this
+	 * target.  If we did, this is a signal that
+	 * the target is refusing negotiation.
+	 */
+	struct scb *scb;
+	struct ahc_initiator_tinfo *tinfo;
+	struct tmode_tstate *tstate;
+	u_int scb_index;
+	u_int last_msg;
+	int   response = 0;
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	/* Might be necessary */
+	last_msg = ahc_inb(ahc, LAST_MSG);
+
+	if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) {
+		/*
+		 * Target does not support the PPR message.
+		 * Attempt to negotiate SPI-2 style.
+		 */
+		if (bootverbose) {
+			printf("(%s:%c:%d:%d): PPR Rejected. "
+			       "Trying WDTR/SDTR\n",
+			       ahc_name(ahc), devinfo->channel,
+			       devinfo->target, devinfo->lun);
+		}
+		tinfo->goal.ppr_options = 0;
+		tinfo->current.transport_version = 2;
+		tinfo->goal.transport_version = 2;
+		ahc->msgout_index = 0;
+		ahc->msgout_len = 0;
+		ahc_build_transfer_msg(ahc, devinfo);
+		ahc->msgout_index = 0;
+		response = 1;
+	} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
+
+		/* note 8bit xfers */
+		printf("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
+		       "8bit transfers\n", ahc_name(ahc),
+		       devinfo->channel, devinfo->target, devinfo->lun);
+		ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+			      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+			      /*paused*/TRUE);
+		/*
+		 * No need to clear the sync rate.  If the target
+		 * did not accept the command, our syncrate is
+		 * unaffected.  If the target started the negotiation,
+		 * but rejected our response, we already cleared the
+		 * sync rate before sending our WDTR.
+		 */
+		if (tinfo->goal.period) {
+
+			/* Start the sync negotiation */
+			ahc->msgout_index = 0;
+			ahc->msgout_len = 0;
+			ahc_build_transfer_msg(ahc, devinfo);
+			ahc->msgout_index = 0;
+			response = 1;
+		}
+	} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) {
+		/* note asynch xfers and clear flag */
+		ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0,
+				 /*offset*/0, /*ppr_options*/0,
+				 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+				 /*paused*/TRUE);
+		printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+		       "Using asynchronous transfers\n",
+		       ahc_name(ahc), devinfo->channel,
+		       devinfo->target, devinfo->lun);
+	} else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) {
+
+		printf("(%s:%c:%d:%d): refuses tagged commands.  Performing "
+		       "non-tagged I/O\n", ahc_name(ahc),
+		       devinfo->channel, devinfo->target, devinfo->lun);
+		ahc_set_tags(ahc, devinfo, FALSE);
+
+		/*
+		 * Resend the identify for this CCB as the target
+		 * may believe that the selection is invalid otherwise.
+		 */
+		ahc_outb(ahc, SCB_CONTROL,
+			 ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG);
+	 	scb->hscb->control &= ~MSG_SIMPLE_Q_TAG;
+		ahc_set_transaction_tag(scb, /*enabled*/FALSE,
+					/*type*/MSG_SIMPLE_Q_TAG);
+		ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG);
+		ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
+
+		/*
+		 * This transaction is now at the head of
+		 * the untagged queue for this target.
+		 */
+		if ((ahc->flags & AHC_SCB_BTT) == 0) {
+			struct scb_tailq *untagged_q;
+
+			untagged_q =
+			    &(ahc->untagged_queues[devinfo->target_offset]);
+			TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe);
+			scb->flags |= SCB_UNTAGGEDQ;
+		}
+		ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun),
+			     scb->hscb->tag);
+
+		/*
+		 * Requeue all tagged commands for this target
+		 * currently in our posession so they can be
+		 * converted to untagged commands.
+		 */
+		ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb),
+				   SCB_GET_CHANNEL(ahc, scb),
+				   SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL,
+				   ROLE_INITIATOR, CAM_REQUEUE_REQ,
+				   SEARCH_COMPLETE);
+	} else {
+		/*
+		 * Otherwise, we ignore it.
+		 */
+		printf("%s:%c:%d: Message reject for %x -- ignored\n",
+		       ahc_name(ahc), devinfo->channel, devinfo->target,
+		       last_msg);
+	}
+	return (response);
+}
+
+/*
+ * Process an ingnore wide residue message.
+ */
+static void
+ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	u_int scb_index;
+	struct scb *scb;
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	/*
+	 * XXX Actually check data direction in the sequencer?
+	 * Perhaps add datadir to some spare bits in the hscb?
+	 */
+	if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0
+	 || ahc_get_transfer_dir(scb) != CAM_DIR_IN) {
+		/*
+		 * Ignore the message if we haven't
+		 * seen an appropriate data phase yet.
+		 */
+	} else {
+		/*
+		 * If the residual occurred on the last
+		 * transfer and the transfer request was
+		 * expected to end on an odd count, do
+		 * nothing.  Otherwise, subtract a byte
+		 * and update the residual count accordingly.
+		 */
+		uint32_t sgptr;
+
+		sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR);
+		if ((sgptr & SG_LIST_NULL) != 0
+		 && ahc_inb(ahc, DATA_COUNT_ODD) == 1) {
+			/*
+			 * If the residual occurred on the last
+			 * transfer and the transfer request was
+			 * expected to end on an odd count, do
+			 * nothing.
+			 */
+		} else {
+			struct ahc_dma_seg *sg;
+			uint32_t data_cnt;
+			uint32_t data_addr;
+
+			/* Pull in the rest of the sgptr */
+			sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24)
+			      | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
+			      | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8);
+			sgptr &= SG_PTR_MASK;
+			data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16)
+				 | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8)
+				 | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT));
+
+			data_addr = (ahc_inb(ahc, SHADDR + 3) << 24)
+				  | (ahc_inb(ahc, SHADDR + 2) << 16)
+				  | (ahc_inb(ahc, SHADDR + 1) << 8)
+				  | (ahc_inb(ahc, SHADDR));
+
+			data_cnt += 1;
+			data_addr -= 1;
+
+			sg = ahc_sg_bus_to_virt(scb, sgptr);
+			/*
+			 * The residual sg ptr points to the next S/G
+			 * to load so we must go back one.
+			 */
+			sg--;
+			if (sg != scb->sg_list
+			 && (sg->len & AHC_SG_LEN_MASK) < data_cnt) {
+
+				sg--;
+				data_cnt = 1 | (sg->len & AHC_DMA_LAST_SEG);
+				data_addr = sg->addr
+					  + (sg->len & AHC_SG_LEN_MASK) - 1;
+
+				/*
+				 * Increment sg so it points to the
+				 * "next" sg.
+				 */
+				sg++;
+				sgptr = ahc_sg_virt_to_bus(scb, sg);
+				ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3,
+					 sgptr >> 24);
+				ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2,
+					 sgptr >> 16);
+				ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1,
+					 sgptr >> 8);
+				ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr);
+			}
+
+/* XXX What about high address byte??? */
+			ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24);
+			ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16);
+			ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8);
+			ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt);
+
+/* XXX Perhaps better to just keep the saved address in sram */
+			if ((ahc->features & AHC_ULTRA2) != 0) {
+				ahc_outb(ahc, HADDR + 3, data_addr >> 24);
+				ahc_outb(ahc, HADDR + 2, data_addr >> 16);
+				ahc_outb(ahc, HADDR + 1, data_addr >> 8);
+				ahc_outb(ahc, HADDR, data_addr);
+				ahc_outb(ahc, DFCNTRL, PRELOADEN);
+				ahc_outb(ahc, SXFRCTL0,
+					 ahc_inb(ahc, SXFRCTL0) | CLRCHN);
+			} else {
+				ahc_outb(ahc, HADDR + 3, data_addr >> 24);
+				ahc_outb(ahc, HADDR + 2, data_addr >> 16);
+				ahc_outb(ahc, HADDR + 1, data_addr >> 8);
+				ahc_outb(ahc, HADDR, data_addr);
+			}
+		}
+	}
+}
+
+/*
+ * Handle the effects of issuing a bus device reset message.
+ */
+static void
+ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		    cam_status status, char *message, int verbose_level)
+{
+#ifdef AHC_TARGET_MODE
+	struct tmode_tstate* tstate;
+	u_int lun;
+#endif
+	int found;
+
+	found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
+			       CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role,
+			       status);
+
+#ifdef AHC_TARGET_MODE
+	/*
+	 * Send an immediate notify ccb to all target mord peripheral
+	 * drivers affected by this action.
+	 */
+	tstate = ahc->enabled_targets[devinfo->our_scsiid];
+	if (tstate != NULL) {
+		for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+			struct tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[lun];
+			if (lstate == NULL)
+				continue;
+
+			ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid,
+					       MSG_BUS_DEV_RESET, /*arg*/0);
+			ahc_send_lstate_events(ahc, lstate);
+		}
+	}
+#endif
+
+	/*
+	 * Go back to async/narrow transfers and renegotiate.
+	 */
+	ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+		      AHC_TRANS_CUR, /*paused*/TRUE);
+	ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL,
+			 /*period*/0, /*offset*/0, /*ppr_options*/0,
+			 AHC_TRANS_CUR, /*paused*/TRUE);
+	
+	ahc_send_async(ahc, devinfo->channel, devinfo->target,
+		       CAM_LUN_WILDCARD, AC_SENT_BDR);
+
+	if (message != NULL
+	 && (verbose_level <= bootverbose))
+		printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
+		       message, devinfo->channel, devinfo->target, found);
+}
+
+#ifdef AHC_TARGET_MODE
+void
+ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	/*              
+	 * To facilitate adding multiple messages together,
+	 * each routine should increment the index and len
+	 * variables instead of setting them explicitly.
+	 */             
+	ahc->msgout_index = 0;
+	ahc->msgout_len = 0;
+
+	if ((ahc->targ_msg_req & devinfo->target_mask) != 0)
+		ahc_build_transfer_msg(ahc, devinfo);
+	else
+		panic("ahc_intr: AWAITING target message with no message");
+
+	ahc->msgout_index = 0;
+	ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
+}
+#endif
+/**************************** Initialization **********************************/
+/*
+ * Allocate a controller structure for a new device
+ * and perform initial initializion.
+ */
+struct ahc_softc *
+ahc_alloc(void *platform_arg, char *name)
+{
+	struct  ahc_softc *ahc;
+	int	i;
+
+#ifndef	__FreeBSD__
+	ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT);
+	if (!ahc) {
+		printf("aic7xxx: cannot malloc softc!\n");
+		free(name, M_DEVBUF);
+		return NULL;
+	}
+#else
+	ahc = device_get_softc((device_t)platform_arg);
+#endif
+	memset(ahc, 0, sizeof(*ahc));
+	LIST_INIT(&ahc->pending_scbs);
+	/* We don't know our unit number until the OSM sets it */
+	ahc->name = name;
+	for (i = 0; i < 16; i++)
+		TAILQ_INIT(&ahc->untagged_queues[i]);
+	if (ahc_platform_alloc(ahc, platform_arg) != 0) {
+		ahc_free(ahc);
+		ahc = NULL;
+	}
+	return (ahc);
+}
+
+int
+ahc_softc_init(struct ahc_softc *ahc, struct ahc_probe_config *config)
+{
+
+	ahc->chip = config->chip;
+	ahc->features = config->features;
+	ahc->bugs = config->bugs;
+	ahc->flags = config->flags;
+	ahc->channel = config->channel; 
+	ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN;
+	ahc->description = config->description;
+	/* The IRQMS bit is only valid on VL and EISA chips */
+	if ((ahc->chip & AHC_PCI) != 0)
+		ahc->unpause &= ~IRQMS;
+	ahc->pause = ahc->unpause | PAUSE; 
+	/* XXX The shared scb data stuff should be depricated */
+	if (ahc->scb_data == NULL) {
+		ahc->scb_data = malloc(sizeof(*ahc->scb_data),
+				       M_DEVBUF, M_NOWAIT);
+		if (ahc->scb_data == NULL)
+			return (ENOMEM);
+		memset(ahc->scb_data, 0, sizeof(*ahc->scb_data));
+	}
+
+	return (0);
+}
+
+void
+ahc_softc_insert(struct ahc_softc *ahc)
+{
+	struct ahc_softc *list_ahc;
+
+#ifdef AHC_SUPPORT_PCI
+	/*
+	 * Second Function PCI devices need to inherit some
+	 * settings from function 0.  We assume that function 0
+	 * will always be found prior to function 1.
+	 */
+	if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI
+	 && ahc_get_pci_function(ahc->dev_softc) == 1) {
+		TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
+			ahc_dev_softc_t list_pci;
+			ahc_dev_softc_t pci;
+
+			list_pci = list_ahc->dev_softc;
+			pci = ahc->dev_softc;
+			if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)
+			 && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
+			 && ahc_get_pci_function(list_pci) == 0) {
+				ahc->flags &= ~AHC_BIOS_ENABLED; 
+				ahc->flags |=
+				    list_ahc->flags & AHC_BIOS_ENABLED;
+				ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; 
+				ahc->flags |=
+				    list_ahc->flags & AHC_CHANNEL_B_PRIMARY;
+				break;
+			}
+		}
+	}
+#endif
+
+	/*
+	 * Insertion sort into our list of softcs.
+	 */
+	list_ahc = TAILQ_FIRST(&ahc_tailq);
+	while (list_ahc != NULL
+	    && ahc_softc_comp(list_ahc, ahc) <= 0)
+		list_ahc = TAILQ_NEXT(list_ahc, links);
+	if (list_ahc != NULL)
+		TAILQ_INSERT_BEFORE(list_ahc, ahc, links);
+	else
+		TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links);
+	ahc->init_level++;
+}
+
+void
+ahc_set_unit(struct ahc_softc *ahc, int unit)
+{
+	ahc->unit = unit;
+}
+
+void
+ahc_set_name(struct ahc_softc *ahc, char *name)
+{
+	if (ahc->name != NULL)
+		free(ahc->name, M_DEVBUF);
+	ahc->name = name;
+}
+
+void
+ahc_free(struct ahc_softc *ahc)
+{
+	int i;
+
+	ahc_fini_scbdata(ahc);
+	switch (ahc->init_level) {
+	default:
+	case 5:
+		ahc_shutdown(ahc);
+		TAILQ_REMOVE(&ahc_tailq, ahc, links);
+		/* FALLTHROUGH */
+	case 4:
+		ahc_dmamap_unload(ahc, ahc->shared_data_dmat,
+				  ahc->shared_data_dmamap);
+		/* FALLTHROUGH */
+	case 3:
+		ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo,
+				ahc->shared_data_dmamap);
+		ahc_dmamap_destroy(ahc, ahc->shared_data_dmat,
+				   ahc->shared_data_dmamap);
+		/* FALLTHROUGH */
+	case 2:
+		ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat);
+	case 1:
+#ifndef __linux__
+		ahc_dma_tag_destroy(ahc, ahc->buffer_dmat);
+#endif
+		break;
+	case 0:
+		break;
+	}
+
+#ifndef __linux__
+	ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
+#endif
+	ahc_platform_free(ahc);
+	for (i = 0; i < AHC_NUM_TARGETS; i++) {
+		struct tmode_tstate *tstate;
+
+		tstate = ahc->enabled_targets[i];
+		if (tstate != NULL) {
+#if AHC_TARGET_MODE
+			int j;
+
+			for (j = 0; j < AHC_NUM_LUNS; j++) {
+				struct tmode_lstate *lstate;
+
+				lstate = tstate->enabled_luns[j];
+				if (lstate != NULL) {
+					xpt_free_path(lstate->path);
+					free(lstate, M_DEVBUF);
+				}
+			}
+#endif
+			free(tstate, M_DEVBUF);
+		}
+	}
+#if AHC_TARGET_MODE
+	if (ahc->black_hole != NULL) {
+		xpt_free_path(ahc->black_hole->path);
+		free(ahc->black_hole, M_DEVBUF);
+	}
+#endif
+	if (ahc->name != NULL)
+		free(ahc->name, M_DEVBUF);
+#ifndef __FreeBSD__
+	free(ahc, M_DEVBUF);
+#endif
+	return;
+}
+
+void
+ahc_shutdown(void *arg)
+{
+	struct	ahc_softc *ahc;
+	int	i;
+
+	ahc = (struct ahc_softc *)arg;
+
+	/* This will reset most registers to 0, but not all */
+	ahc_reset(ahc);
+	ahc_outb(ahc, SCSISEQ, 0);
+	ahc_outb(ahc, SXFRCTL0, 0);
+	ahc_outb(ahc, DSPCISTATUS, 0);
+
+	for (i = TARG_SCSIRATE; i < HA_274_BIOSCTRL; i++)
+		ahc_outb(ahc, i, 0);
+}
+
+/*
+ * Reset the controller and record some information about it
+ * that is only availabel just after a reset.
+ */
+int
+ahc_reset(struct ahc_softc *ahc)
+{
+	u_int	sblkctl;
+	u_int	sxfrctl1_a, sxfrctl1_b;
+	int	wait;
+	
+	/*
+	 * Preserve the value of the SXFRCTL1 register for all channels.
+	 * It contains settings that affect termination and we don't want
+	 * to disturb the integrity of the bus.
+	 */
+	pause_sequencer(ahc);
+	sxfrctl1_b = 0;
+	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
+		u_int sblkctl;
+
+		/*
+		 * Save channel B's settings in case this chip
+		 * is setup for TWIN channel operation.
+		 */
+		sblkctl = ahc_inb(ahc, SBLKCTL);
+		ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB);
+		sxfrctl1_b = ahc_inb(ahc, SXFRCTL1);
+		ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB);
+	}
+	sxfrctl1_a = ahc_inb(ahc, SXFRCTL1);
+
+	ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);
+
+	/*
+	 * Ensure that the reset has finished
+	 */
+	wait = 1000;
+	do {
+		ahc_delay(1000);
+	} while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));
+
+	if (wait == 0) {
+		printf("%s: WARNING - Failed chip reset!  "
+		       "Trying to initialize anyway.\n", ahc_name(ahc));
+	}
+	ahc_outb(ahc, HCNTRL, ahc->pause);
+
+	/* Determine channel configuration */
+	sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE);
+	/* No Twin Channel PCI cards */
+	if ((ahc->chip & AHC_PCI) != 0)
+		sblkctl &= ~SELBUSB;
+	switch (sblkctl) {
+	case 0:
+		/* Single Narrow Channel */
+		break;
+	case 2:
+		/* Wide Channel */
+		ahc->features |= AHC_WIDE;
+		break;
+	case 8:
+		/* Twin Channel */
+		ahc->features |= AHC_TWIN;
+		break;
+	default:
+		printf(" Unsupported adapter type.  Ignoring\n");
+		return(-1);
+	}
+
+	/*
+	 * Reload sxfrctl1.
+	 *
+	 * We must always initialize STPWEN to 1 before we
+	 * restore the saved values.  STPWEN is initialized
+	 * to a tri-state condition which can only be cleared
+	 * by turning it on.
+	 */
+	if ((ahc->features & AHC_TWIN) != 0) {
+		u_int sblkctl;
+
+		sblkctl = ahc_inb(ahc, SBLKCTL);
+		ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB);
+		ahc_outb(ahc, SXFRCTL1, sxfrctl1_b);
+		ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB);
+	}
+	ahc_outb(ahc, SXFRCTL1, sxfrctl1_a);
+
+#ifdef AHC_DUMP_SEQ
+	if (ahc->init_level == 0)
+		ahc_dumpseq(ahc);
+#endif
+
+	return (0);
+}
+
+/*
+ * Determine the number of SCBs available on the controller
+ */
+int
+ahc_probe_scbs(struct ahc_softc *ahc) {
+	int i;
+
+	for (i = 0; i < AHC_SCB_MAX; i++) {
+
+		ahc_outb(ahc, SCBPTR, i);
+		ahc_outb(ahc, SCB_BASE, i);
+		if (ahc_inb(ahc, SCB_BASE) != i)
+			break;
+		ahc_outb(ahc, SCBPTR, 0);
+		if (ahc_inb(ahc, SCB_BASE) != 0)
+			break;
+	}
+	return (i);
+}
+
+void
+ahc_init_probe_config(struct ahc_probe_config *probe_config)
+{
+	probe_config->description = NULL;
+	probe_config->channel = 'A';
+	probe_config->channel_b = 'B';
+	probe_config->chip = AHC_NONE;
+	probe_config->features = AHC_FENONE;
+	probe_config->bugs = AHC_BUGNONE;
+	probe_config->flags = AHC_FNONE;
+}
+
+static void
+ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 
+{
+	bus_addr_t *baddr;
+
+	baddr = (bus_addr_t *)arg;
+	*baddr = segs->ds_addr;
+}
+
+static void
+ahc_build_free_scb_list(struct ahc_softc *ahc)
+{
+	int i;
+
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		ahc_outb(ahc, SCBPTR, i);
+
+		/* Clear the control byte. */
+		ahc_outb(ahc, SCB_CONTROL, 0);
+
+		/* Set the next pointer */
+		if ((ahc->flags & AHC_PAGESCBS) != 0)
+			ahc_outb(ahc, SCB_NEXT, i+1);
+		else 
+			ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
+
+		/* Make the tag number invalid */
+		ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+	}
+
+	/* Make sure that the last SCB terminates the free list */
+	ahc_outb(ahc, SCBPTR, i-1);
+	ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
+
+	/* Ensure we clear the 0 SCB's control byte. */
+	ahc_outb(ahc, SCBPTR, 0);
+	ahc_outb(ahc, SCB_CONTROL, 0);
+}
+
+static int
+ahc_init_scbdata(struct ahc_softc *ahc)
+{
+	struct scb_data *scb_data;
+
+	scb_data = ahc->scb_data;
+	SLIST_INIT(&scb_data->free_scbs);
+	SLIST_INIT(&scb_data->sg_maps);
+
+	/* Allocate SCB resources */
+	scb_data->scbarray =
+	    (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX,
+				 M_DEVBUF, M_NOWAIT);
+	if (scb_data->scbarray == NULL)
+		return (ENOMEM);
+	memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX);
+
+	/* Determine the number of hardware SCBs and initialize them */
+
+	scb_data->maxhscbs = ahc_probe_scbs(ahc);
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		/* SCB 0 heads the free list */
+		ahc_outb(ahc, FREE_SCBH, 0);
+	} else {
+		ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
+	}
+
+	if (ahc->scb_data->maxhscbs == 0) {
+		printf("%s: No SCB space found\n", ahc_name(ahc));
+		return (ENXIO);
+	}
+
+	ahc_build_free_scb_list(ahc);
+
+	/*
+	 * Create our DMA tags.  These tags define the kinds of device
+	 * accessible memory allocations and memory mappings we will
+	 * need to perform during normal operation.
+	 *
+	 * Unless we need to further restrict the allocation, we rely
+	 * on the restrictions of the parent dmat, hence the common
+	 * use of MAXADDR and MAXSIZE.
+	 */
+
+	/* DMA tag for our hardware scb structures */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       AHC_SCB_MAX * sizeof(struct hardware_scb),
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->hscb_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Allocation for our ccbs */
+	if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat,
+			     (void **)&scb_data->hscbs,
+			     BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* And permanently map them */
+	ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap,
+			scb_data->hscbs,
+			AHC_SCB_MAX * sizeof(struct hardware_scb),
+			ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0);
+
+	scb_data->init_level++;
+
+	/* DMA tag for our sense buffers */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       AHC_SCB_MAX * sizeof(struct scsi_sense_data),
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->sense_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Allocate them */
+	if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat,
+			     (void **)&scb_data->sense,
+			     BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* And permanently map them */
+	ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap,
+			scb_data->sense,
+			AHC_SCB_MAX * sizeof(struct scsi_sense_data),
+			ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0);
+
+	scb_data->init_level++;
+
+	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       PAGE_SIZE, /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->sg_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Perform initial CCB allocation */
+	memset(scb_data->hscbs, 0, AHC_SCB_MAX * sizeof(struct hardware_scb));
+	ahc_alloc_scbs(ahc);
+
+	if (scb_data->numscbs == 0) {
+		printf("%s: ahc_init_scbdata - "
+		       "Unable to allocate initial scbs\n",
+		       ahc_name(ahc));
+		goto error_exit;
+	}
+
+	/*
+	 * Tell the sequencer which SCB will be the next one it receives.
+	 */
+	ahc->next_queued_scb = ahc_get_scb(ahc);
+	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
+
+	/*
+	 * Note that we were successfull
+	 */
+	return (0); 
+
+error_exit:
+
+	return (ENOMEM);
+}
+
+static void
+ahc_fini_scbdata(struct ahc_softc *ahc)
+{
+	struct scb_data *scb_data;
+
+	scb_data = ahc->scb_data;
+	if (scb_data == NULL)
+		return;
+
+	switch (scb_data->init_level) {
+	default:
+	case 7:
+	{
+		struct sg_map_node *sg_map;
+
+		while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) {
+			SLIST_REMOVE_HEAD(&scb_data->sg_maps, links);
+			ahc_dmamap_unload(ahc, scb_data->sg_dmat,
+					  sg_map->sg_dmamap);
+			ahc_dmamem_free(ahc, scb_data->sg_dmat,
+					sg_map->sg_vaddr,
+					sg_map->sg_dmamap);
+			free(sg_map, M_DEVBUF);
+		}
+		ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
+	}
+	case 6:
+		ahc_dmamap_unload(ahc, scb_data->sense_dmat,
+				  scb_data->sense_dmamap);
+	case 5:
+		ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense,
+				scb_data->sense_dmamap);
+		ahc_dmamap_destroy(ahc, scb_data->sense_dmat,
+				   scb_data->sense_dmamap);
+	case 4:
+		ahc_dma_tag_destroy(ahc, scb_data->sense_dmat);
+	case 3:
+		ahc_dmamap_unload(ahc, scb_data->hscb_dmat,
+				  scb_data->hscb_dmamap);
+	case 2:
+		ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs,
+				scb_data->hscb_dmamap);
+		ahc_dmamap_destroy(ahc, scb_data->hscb_dmat,
+				   scb_data->hscb_dmamap);
+	case 1:
+		ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat);
+		break;
+	case 0:
+		break;
+	}
+	if (scb_data->scbarray != NULL)
+		free(scb_data->scbarray, M_DEVBUF);
+}
+
+void
+ahc_alloc_scbs(struct ahc_softc *ahc)
+{
+	struct scb_data *scb_data;
+	struct scb *next_scb;
+	struct sg_map_node *sg_map;
+	bus_addr_t physaddr;
+	struct ahc_dma_seg *segs;
+	int newcount;
+	int i;
+
+	scb_data = ahc->scb_data;
+	if (scb_data->numscbs >= AHC_SCB_MAX)
+		/* Can't allocate any more */
+		return;
+
+	next_scb = &scb_data->scbarray[scb_data->numscbs];
+
+	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+
+	if (sg_map == NULL)
+		return;
+
+	/* Allocate S/G space for the next batch of SCBS */
+	if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat,
+			     (void **)&sg_map->sg_vaddr,
+			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
+		free(sg_map, M_DEVBUF);
+		return;
+	}
+
+	SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);
+
+	ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap,
+			sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb,
+			&sg_map->sg_physaddr, /*flags*/0);
+
+	segs = sg_map->sg_vaddr;
+	physaddr = sg_map->sg_physaddr;
+
+	newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
+	for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) {
+		struct scb_platform_data *pdata;
+#ifndef __linux__
+		int error;
+#endif
+		pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
+							   M_DEVBUF, M_NOWAIT);
+		if (pdata == NULL)
+			break;
+		next_scb->platform_data = pdata;
+		next_scb->sg_list = segs;
+		/*
+		 * The sequencer always starts with the second entry.
+		 * The first entry is embedded in the scb.
+		 */
+		next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg);
+		next_scb->ahc_softc = ahc;
+		next_scb->flags = SCB_FREE;
+#ifndef __linux__
+		error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0,
+					  &next_scb->dmamap);
+		if (error != 0)
+			break;
+#endif
+		next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
+		next_scb->hscb->tag = ahc->scb_data->numscbs;
+		SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
+				  next_scb, links.sle);
+		segs += AHC_NSEG;
+		physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg));
+		next_scb++;
+		ahc->scb_data->numscbs++;
+	}
+}
+
+void
+ahc_controller_info(struct ahc_softc *ahc, char *buf)
+{
+	int len;
+
+	len = sprintf(buf, "%s: ", ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]);
+	buf += len;
+	if ((ahc->features & AHC_TWIN) != 0)
+ 		len = sprintf(buf, "Twin Channel, A SCSI Id=%d, "
+			      "B SCSI Id=%d, primary %c, ",
+			      ahc->our_id, ahc->our_id_b,
+			      ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A');
+	else {
+		const char *type;
+
+		if ((ahc->features & AHC_WIDE) != 0) {
+			type = "Wide";
+		} else {
+			type = "Single";
+		}
+		len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ",
+			      type, ahc->channel, ahc->our_id);
+	}
+	buf += len;
+
+	if ((ahc->flags & AHC_PAGESCBS) != 0)
+		sprintf(buf, "%d/%d SCBs",
+			ahc->scb_data->maxhscbs, AHC_SCB_MAX);
+	else
+		sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+ahc_init(struct ahc_softc *ahc)
+{
+	int	 max_targ;
+	int	 i;
+	int	 term;
+	u_int	 scsi_conf;
+	u_int	 scsiseq_template;
+	u_int	 ultraenb;
+	u_int	 discenable;
+	u_int	 tagenable;
+	size_t	 driver_data_size;
+	uint32_t physaddr;
+
+#ifdef AHC_DEBUG_SEQUENCER
+	ahc->flags |= AHC_SEQUENCER_DEBUG;
+#endif
+
+#ifdef AHC_PRINT_SRAM
+	printf("Scratch Ram:");
+	for (i = 0x20; i < 0x5f; i++) {
+		if (((i % 8) == 0) && (i != 0)) {
+			printf ("\n              ");
+		}
+		printf (" 0x%x", ahc_inb(ahc, i));
+	}
+	if ((ahc->features & AHC_MORE_SRAM) != 0) {
+		for (i = 0x70; i < 0x7f; i++) {
+			if (((i % 8) == 0) && (i != 0)) {
+				printf ("\n              ");
+			}
+			printf (" 0x%x", ahc_inb(ahc, i));
+		}
+	}
+	printf ("\n");
+#endif
+	max_targ = 15;
+
+	/*
+	 * Assume we have a board at this stage and it has been reset.
+	 */
+	if ((ahc->flags & AHC_USEDEFAULTS) != 0)
+		ahc->our_id = ahc->our_id_b = 7;
+	
+	/*
+	 * Default to allowing initiator operations.
+	 */
+	ahc->flags |= AHC_INITIATORROLE;
+
+	/*
+	 * Only allow target mode features if this unit has them enabled.
+	 */
+	if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0)
+		ahc->features &= ~AHC_TARGETMODE;
+
+#ifndef __linux__
+	/* DMA tag for mapping buffers into device visible space. */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG,
+			       /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
+			       /*flags*/BUS_DMA_ALLOCNOW,
+			       &ahc->buffer_dmat) != 0) {
+		return (ENOMEM);
+	}
+#endif
+
+	ahc->init_level++;
+
+	/*
+	 * DMA tag for our command fifos and other data in system memory
+	 * the card's sequencer must be able to access.  For initiator
+	 * roles, we need to allocate space for the the qinfifo and qoutfifo.
+	 * The qinfifo and qoutfifo are composed of 256 1 byte elements. 
+	 * When providing for the target mode role, we must additionally
+	 * provide space for the incoming target command fifo and an extra
+	 * byte to deal with a dma bug in some chip versions.
+	 */
+	driver_data_size = 2 * 256 * sizeof(uint8_t);
+	if ((ahc->features & AHC_TARGETMODE) != 0)
+		driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd)
+				 + /*DMA WideOdd Bug Buffer*/1;
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       driver_data_size,
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &ahc->shared_data_dmat) != 0) {
+		return (ENOMEM);
+	}
+
+	ahc->init_level++;
+
+	/* Allocation of driver data */
+	if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat,
+			     (void **)&ahc->qoutfifo,
+			     BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) {
+		return (ENOMEM);
+	}
+
+	ahc->init_level++;
+
+	/* And permanently map it in */
+	ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+			ahc->qoutfifo, driver_data_size, ahc_dmamap_cb,
+			&ahc->shared_data_busaddr, /*flags*/0);
+
+	if ((ahc->features & AHC_TARGETMODE) != 0) {
+		ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo;
+		ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS];
+		ahc->dma_bug_buf = ahc->shared_data_busaddr
+				 + driver_data_size - 1;
+		/* All target command blocks start out invalid. */
+		for (i = 0; i < AHC_TMODE_CMDS; i++)
+			ahc->targetcmds[i].cmd_valid = 0;
+		ahc->tqinfifonext = 1;
+		ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
+		ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+		ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
+	}
+	ahc->qinfifo = &ahc->qoutfifo[256];
+
+	ahc->init_level++;
+
+	/* Allocate SCB data now that buffer_dmat is initialized */
+	if (ahc->scb_data->maxhscbs == 0)
+		if (ahc_init_scbdata(ahc) != 0)
+			return (ENOMEM);
+
+	/*
+	 * Allocate a tstate to house information for our
+	 * initiator presence on the bus as well as the user
+	 * data for any target mode initiator.
+	 */
+	if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) {
+		printf("%s: unable to allocate tmode_tstate.  "
+		       "Failing attach\n", ahc_name(ahc));
+		return (-1);
+	}
+
+	if ((ahc->features & AHC_TWIN) != 0) {
+		if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) {
+			printf("%s: unable to allocate tmode_tstate.  "
+			       "Failing attach\n", ahc_name(ahc));
+			return (-1);
+		}
+	}
+
+	ahc_outb(ahc, SEQ_FLAGS, 0);
+	ahc_outb(ahc, SEQ_FLAGS2, 0);
+
+	if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) {
+		ahc->flags |= AHC_PAGESCBS;
+	} else {
+		ahc->flags &= ~AHC_PAGESCBS;
+	}
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOWMISC) {
+		printf("%s: hardware scb %d bytes; kernel scb %d bytes; "
+		       "ahc_dma %d bytes\n",
+			ahc_name(ahc),
+			sizeof(struct hardware_scb),
+			sizeof(struct scb),
+			sizeof(struct ahc_dma_seg));
+	}
+#endif /* AHC_DEBUG */
+
+	/* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
+	if (ahc->features & AHC_TWIN) {
+
+		/*
+		 * The device is gated to channel B after a chip reset,
+		 * so set those values first
+		 */
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
+		term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
+		ahc_outb(ahc, SCSIID, ahc->our_id_b);
+		scsi_conf = ahc_inb(ahc, SCSICONF + 1);
+		ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+					|term|ahc->seltime_b|ENSTIMER|ACTNEGEN);
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+		ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+		ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+		if ((scsi_conf & RESET_SCSI) != 0
+		 && (ahc->flags & AHC_INITIATORROLE) != 0)
+			ahc->flags |= AHC_RESET_BUS_B;
+
+		/* Select Channel A */
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
+	}
+	term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
+	else
+		ahc_outb(ahc, SCSIID, ahc->our_id);
+	scsi_conf = ahc_inb(ahc, SCSICONF);
+	ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+				|term|ahc->seltime
+				|ENSTIMER|ACTNEGEN);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+	ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+	ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+	if ((scsi_conf & RESET_SCSI) != 0
+	 && (ahc->flags & AHC_INITIATORROLE) != 0)
+		ahc->flags |= AHC_RESET_BUS_A;
+
+	/*
+	 * Look at the information that board initialization or
+	 * the board bios has left us.
+	 */
+	ultraenb = 0;	
+	tagenable = ALL_TARGETS_MASK;
+
+	/* Grab the disconnection disable table and invert it for our needs */
+	if (ahc->flags & AHC_USEDEFAULTS) {
+		printf("%s: Host Adapter Bios disabled.  Using default SCSI "
+			"device parameters\n", ahc_name(ahc));
+		ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B|
+			      AHC_TERM_ENB_A|AHC_TERM_ENB_B;
+		discenable = ALL_TARGETS_MASK;
+		if ((ahc->features & AHC_ULTRA) != 0)
+			ultraenb = ALL_TARGETS_MASK;
+	} else {
+		discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8)
+			   | ahc_inb(ahc, DISC_DSB));
+		if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0)
+			ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8)
+				      | ahc_inb(ahc, ULTRA_ENB);
+	}
+	if ((ahc->flags & AHC_ULTRA_DISABLED) != 0)
+		ultraenb = 0;
+
+	if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
+		max_targ = 7;
+
+	for (i = 0; i <= max_targ; i++) {
+		struct ahc_initiator_tinfo *tinfo;
+		struct tmode_tstate *tstate;
+		u_int our_id;
+		u_int target_id;
+		char channel;
+
+		channel = 'A';
+		our_id = ahc->our_id;
+		target_id = i;
+		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 'B';
+			our_id = ahc->our_id_b;
+			target_id = i % 8;
+		}
+		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+					    target_id, &tstate);
+		/* Default to async narrow across the board */
+		memset(tinfo, 0, sizeof(*tinfo));
+		if (ahc->flags & AHC_USEDEFAULTS) {
+			if ((ahc->features & AHC_WIDE) != 0)
+				tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+
+			/*
+			 * These will be truncated when we determine the
+			 * connection type we have with the target.
+			 */
+			tinfo->user.period = ahc_syncrates->period;
+			tinfo->user.offset = ~0;
+		} else {
+			u_int scsirate;
+			uint16_t mask;
+
+			/* Take the settings leftover in scratch RAM. */
+			scsirate = ahc_inb(ahc, TARG_SCSIRATE + i);
+			mask = (0x01 << i);
+			if ((ahc->features & AHC_ULTRA2) != 0) {
+				u_int offset;
+				u_int maxsync;
+
+				if ((scsirate & SOFS) == 0x0F) {
+					/*
+					 * Haven't negotiated yet,
+					 * so the format is different.
+					 */
+					scsirate = (scsirate & SXFR) >> 4
+						 | (ultraenb & mask)
+						  ? 0x08 : 0x0
+						 | (scsirate & WIDEXFER);
+					offset = MAX_OFFSET_ULTRA2;
+				} else
+					offset = ahc_inb(ahc, TARG_OFFSET + i);
+				if ((scsirate & ~WIDEXFER) == 0 && offset != 0)
+					/* Set to the lowest sync rate, 5MHz */
+					scsirate |= 0x1c;
+				maxsync = AHC_SYNCRATE_ULTRA2;
+				if ((ahc->features & AHC_DT) != 0)
+					maxsync = AHC_SYNCRATE_DT;
+				tinfo->user.period =
+				    ahc_find_period(ahc, scsirate, maxsync);
+				if (offset == 0)
+					tinfo->user.period = 0;
+				else
+					tinfo->user.offset = ~0;
+				if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/
+				 && (ahc->features & AHC_DT) != 0)
+					tinfo->user.ppr_options =
+					    MSG_EXT_PPR_DT_REQ;
+			} else if ((scsirate & SOFS) != 0) {
+				if ((scsirate & SXFR) == 0x40
+				 && (ultraenb & mask) != 0) {
+					/* Treat 10MHz as a non-ultra speed */
+					scsirate &= ~SXFR;
+				 	ultraenb &= ~mask;
+				}
+				tinfo->user.period = 
+				    ahc_find_period(ahc, scsirate,
+						    (ultraenb & mask)
+						   ? AHC_SYNCRATE_ULTRA
+						   : AHC_SYNCRATE_FAST);
+				if (tinfo->user.period != 0)
+					tinfo->user.offset = ~0;
+			}
+			if (tinfo->user.period == 0)
+				tinfo->user.offset = 0;
+			if ((scsirate & WIDEXFER) != 0
+			 && (ahc->features & AHC_WIDE) != 0)
+				tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+			tinfo->user.protocol_version = 4;
+			if ((ahc->features & AHC_DT) != 0)
+				tinfo->user.transport_version = 3;
+			else
+				tinfo->user.transport_version = 2;
+			tinfo->goal.protocol_version = 2;
+			tinfo->goal.transport_version = 2;
+			tinfo->current.protocol_version = 2;
+			tinfo->current.transport_version = 2;
+		}
+		tstate->ultraenb = ultraenb;
+		tstate->discenable = discenable;
+		tstate->tagenable = 0; /* Wait until the XPT says its okay */
+	}
+	ahc->user_discenable = discenable;
+	ahc->user_tagenable = tagenable;
+
+	/* There are no untagged SCBs active yet. */
+	for (i = 0; i < 16; i++) {
+		ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			int lun;
+
+			/*
+			 * The SCB based BTT allows an entry per
+			 * target and lun pair.
+			 */
+			for (lun = 1; lun < AHC_NUM_LUNS; lun++)
+				ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
+		}
+	}
+
+	/* All of our queues are empty */
+	for (i = 0; i < 256; i++)
+		ahc->qoutfifo[i] = SCB_LIST_NULL;
+
+	for (i = 0; i < 256; i++)
+		ahc->qinfifo[i] = SCB_LIST_NULL;
+
+	if ((ahc->features & AHC_MULTI_TID) != 0) {
+		ahc_outb(ahc, TARGID, 0);
+		ahc_outb(ahc, TARGID + 1, 0);
+	}
+
+	/*
+	 * Tell the sequencer where it can find our arrays in memory.
+	 */
+	physaddr = ahc->scb_data->hscb_busaddr;
+	ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+	physaddr = ahc->shared_data_busaddr;
+	ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+	/*
+	 * Initialize the group code to command length table.
+	 * This overrides the values in TARG_SCSIRATE, so only
+	 * setup the table after we have processed that information.
+	 */
+	ahc_outb(ahc, CMDSIZE_TABLE, 5);
+	ahc_outb(ahc, CMDSIZE_TABLE + 1, 9);
+	ahc_outb(ahc, CMDSIZE_TABLE + 2, 9);
+	ahc_outb(ahc, CMDSIZE_TABLE + 3, 0);
+	ahc_outb(ahc, CMDSIZE_TABLE + 4, 15);
+	ahc_outb(ahc, CMDSIZE_TABLE + 5, 11);
+	ahc_outb(ahc, CMDSIZE_TABLE + 6, 0);
+	ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);
+		
+	/* Tell the sequencer of our initial queue positions */
+	ahc_outb(ahc, KERNEL_QINPOS, 0);
+	ahc_outb(ahc, QINPOS, 0);
+	ahc_outb(ahc, QOUTPOS, 0);
+
+	/* Don't have any special messages to send to targets */
+	ahc_outb(ahc, TARGET_MSG_REQUEST, 0);
+	ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0);
+
+	/*
+	 * Use the built in queue management registers
+	 * if they are available.
+	 */
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256);
+		ahc_outb(ahc, SDSCB_QOFF, 0);
+		ahc_outb(ahc, SNSCB_QOFF, 0);
+		ahc_outb(ahc, HNSCB_QOFF, 0);
+	}
+
+
+	/* We don't have any waiting selections */
+	ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
+
+	/* Our disconnection list is empty too */
+	ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
+
+	/* Message out buffer starts empty */
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+
+	/*
+	 * Setup the allowed SCSI Sequences based on operational mode.
+	 * If we are a target, we'll enalbe select in operations once
+	 * we've had a lun enabled.
+	 */
+	scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP;
+	if ((ahc->flags & AHC_INITIATORROLE) != 0)
+		scsiseq_template |= ENRSELI;
+	ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
+
+	/*
+	 * Load the Sequencer program and Enable the adapter
+	 * in "fast" mode.
+	 */
+	if (bootverbose)
+		printf("%s: Downloading Sequencer Program...",
+		       ahc_name(ahc));
+
+	ahc_loadseq(ahc);
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		int wait;
+
+		/*
+		 * Wait for up to 500ms for our transceivers
+		 * to settle.  If the adapter does not have
+		 * a cable attached, the tranceivers may
+		 * never settle, so don't complain if we
+		 * fail here.
+		 */
+		pause_sequencer(ahc);
+		for (wait = 5000;
+		     (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
+		     wait--)
+			ahc_delay(100);
+		unpause_sequencer(ahc);
+	}
+	return (0);
+}
+
+/*
+ * Ensure that the card is paused in a location
+ * outside of all critical sections and that all
+ * pending work is completed prior to returning.
+ * This routine should only be called from outside
+ * an interrupt context.
+ */
+void
+ahc_pause_and_flushwork(struct ahc_softc *ahc)
+{
+	int intstat;
+	int maxloops;
+
+	maxloops = 1000;
+	ahc->flags |= AHC_ALL_INTERRUPTS;
+	intstat = 0;
+	do {
+		ahc_intr(ahc);
+		pause_sequencer(ahc);
+		ahc_clear_critical_section(ahc);
+		if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
+			break;
+		maxloops--;
+	} while (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) && --maxloops);
+	if (maxloops == 0) {
+		printf("Infinite interrupt loop, INTSTAT = %x",
+		      ahc_inb(ahc, INTSTAT));
+	}
+	ahc_platform_flushwork(ahc);
+	ahc->flags &= ~AHC_ALL_INTERRUPTS;
+}
+
+int
+ahc_suspend(struct ahc_softc *ahc)
+{
+	uint8_t *ptr;
+	int	 i;
+
+	ahc_pause_and_flushwork(ahc);
+
+	if (LIST_FIRST(&ahc->pending_scbs) != NULL)
+		return (EBUSY);
+
+#if AHC_TARGET_MODE
+	/*
+	 * XXX What about ATIOs that have not yet been serviced?
+	 * Perhaps we should just refuse to be suspended if we
+	 * are acting in a target role.
+	 */
+	if (ahc->pending_device != NULL)
+		return (EBUSY);
+#endif
+
+	/* Save volatile registers */
+	if ((ahc->features & AHC_TWIN) != 0) {
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
+		ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ);
+		ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
+		ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
+		ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0);
+		ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1);
+		ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER);
+		ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL);
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
+	}
+	ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ);
+	ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
+	ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1);
+	ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0);
+	ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1);
+	ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER);
+	ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL);
+
+	if ((ahc->chip & AHC_PCI) != 0) {
+		ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+		ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
+	}
+
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE);
+		ahc_outb(ahc, SFUNCT, sfunct);
+		ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1);
+	}
+
+	if ((ahc->features & AHC_MULTI_FUNC) != 0)
+		ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR);
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
+
+	ptr = ahc->suspend_state.scratch_ram;
+	for (i = 0; i < 64; i++)
+		*ptr++ = ahc_inb(ahc, SRAM_BASE + i);
+
+	if ((ahc->features & AHC_MORE_SRAM) != 0) {
+		for (i = 0; i < 16; i++)
+			*ptr++ = ahc_inb(ahc, TARG_OFFSET + i);
+	}
+
+	ptr = ahc->suspend_state.btt;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		for (i = 0;i < AHC_NUM_TARGETS; i++) {
+			int j;
+
+			for (j = 0;j < AHC_NUM_LUNS; j++) {
+				u_int tcl;
+
+				tcl = BUILD_TCL(i << 4, j);
+				*ptr = ahc_index_busy_tcl(ahc, tcl);
+			}
+		}
+	}
+	ahc_shutdown(ahc);
+	return (0);
+}
+
+int
+ahc_resume(struct ahc_softc *ahc)
+{
+	uint8_t *ptr;
+	int	 i;
+
+	ahc_reset(ahc);
+
+	ahc_build_free_scb_list(ahc);
+
+	/* Restore volatile registers */
+	if ((ahc->features & AHC_TWIN) != 0) {
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
+		ahc_outb(ahc, SCSIID, ahc->our_id);
+		ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq);
+		ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0);
+		ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1);
+		ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0);
+		ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1);
+		ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer);
+		ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl);
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
+	}
+	ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq);
+	ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0);
+	ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1);
+	ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0);
+	ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1);
+	ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer);
+	ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
+	else
+		ahc_outb(ahc, SCSIID, ahc->our_id);
+
+	if ((ahc->chip & AHC_PCI) != 0) {
+		ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0);
+		ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus);
+	}
+
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode);
+		ahc_outb(ahc, SFUNCT, sfunct);
+		ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1);
+	}
+
+	if ((ahc->features & AHC_MULTI_FUNC) != 0)
+		ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr);
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh);
+
+	ptr = ahc->suspend_state.scratch_ram;
+	for (i = 0; i < 64; i++)
+		ahc_outb(ahc, SRAM_BASE + i, *ptr++);
+
+	if ((ahc->features & AHC_MORE_SRAM) != 0) {
+		for (i = 0; i < 16; i++)
+			ahc_outb(ahc, TARG_OFFSET + i, *ptr++);
+	}
+
+	ptr = ahc->suspend_state.btt;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		for (i = 0;i < AHC_NUM_TARGETS; i++) {
+			int j;
+
+			for (j = 0;j < AHC_NUM_LUNS; j++) {
+				u_int tcl;
+
+				tcl = BUILD_TCL(i << 4, j);
+				ahc_busy_tcl(ahc, tcl, *ptr);
+			}
+		}
+	}
+	return (0);
+}
+
+/************************** Busy Target Table *********************************/
+/*
+ * Return the untagged transaction id for a given target/channel lun.
+ * Optionally, clear the entry.
+ */
+u_int
+ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
+{
+	u_int scbid;
+	u_int target_offset;
+
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		u_int saved_scbptr;
+		
+		saved_scbptr = ahc_inb(ahc, SCBPTR);
+		ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
+		scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl));
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+	} else {
+		target_offset = TCL_TARGET_OFFSET(tcl);
+		scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset);
+	}
+
+	return (scbid);
+}
+
+void
+ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
+{
+	u_int target_offset;
+
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		u_int saved_scbptr;
+		
+		saved_scbptr = ahc_inb(ahc, SCBPTR);
+		ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
+		ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL);
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+	} else {
+		target_offset = TCL_TARGET_OFFSET(tcl);
+		ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL);
+	}
+}
+
+void
+ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid)
+{
+	u_int target_offset;
+
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		u_int saved_scbptr;
+		
+		saved_scbptr = ahc_inb(ahc, SCBPTR);
+		ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
+		ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl), scbid);
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+	} else {
+		target_offset = TCL_TARGET_OFFSET(tcl);
+		ahc_outb(ahc, BUSY_TARGETS + target_offset, scbid);
+	}
+}
+
+/************************** SCB and SCB queue management **********************/
+int
+ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
+	      char channel, int lun, u_int tag, role_t role)
+{
+	int targ = SCB_GET_TARGET(ahc, scb);
+	char chan = SCB_GET_CHANNEL(ahc, scb);
+	int slun = SCB_GET_LUN(scb);
+	int match;
+
+	match = ((chan == channel) || (channel == ALL_CHANNELS));
+	if (match != 0)
+		match = ((targ == target) || (target == CAM_TARGET_WILDCARD));
+	if (match != 0)
+		match = ((lun == slun) || (lun == CAM_LUN_WILDCARD));
+	if (match != 0) {
+#if AHC_TARGET_MODE
+		int group;
+
+		group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code);
+		if (role == ROLE_INITIATOR) {
+			match = (group != XPT_FC_GROUP_TMODE)
+			      && ((tag == scb->hscb->tag)
+			       || (tag == SCB_LIST_NULL));
+		} else if (role == ROLE_TARGET) {
+			match = (group == XPT_FC_GROUP_TMODE)
+			      && ((tag == scb->io_ctx->csio.tag_id)
+			       || (tag == SCB_LIST_NULL));
+		}
+#else /* !AHC_TARGET_MODE */
+		match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+#endif /* AHC_TARGET_MODE */
+	}
+
+	return match;
+}
+
+void
+ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
+{
+	int	target;
+	char	channel;
+	int	lun;
+
+	target = SCB_GET_TARGET(ahc, scb);
+	lun = SCB_GET_LUN(scb);
+	channel = SCB_GET_CHANNEL(ahc, scb);
+	
+	ahc_search_qinfifo(ahc, target, channel, lun,
+			   /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN,
+			   CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+
+	ahc_platform_freeze_devq(ahc, scb);
+}
+
+void
+ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb)
+{
+	struct scb *prev_scb;
+
+	prev_scb = NULL;
+	if (ahc_qinfifo_count(ahc) != 0) {
+		u_int prev_tag;
+		uint8_t prev_pos;
+
+		prev_pos = ahc->qinfifonext - 1;
+		prev_tag = ahc->qinfifo[prev_pos];
+		prev_scb = ahc_lookup_scb(ahc, prev_tag);
+	}
+	ahc_qinfifo_requeue(ahc, prev_scb, scb);
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+	} else {
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+	}
+}
+
+static void
+ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb,
+		    struct scb *scb)
+{
+	if (prev_scb == NULL)
+		ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag);
+	else
+		prev_scb->hscb->next = scb->hscb->tag;
+	ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+	scb->hscb->next = ahc->next_queued_scb->hscb->tag;
+}
+
+static int
+ahc_qinfifo_count(struct ahc_softc *ahc)
+{
+	u_int8_t qinpos;
+	u_int8_t diff;
+
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		qinpos = ahc_inb(ahc, SNSCB_QOFF);
+		ahc_outb(ahc, SNSCB_QOFF, qinpos);
+	} else
+		qinpos = ahc_inb(ahc, QINPOS);
+	diff = ahc->qinfifonext - qinpos;
+	return (diff);
+}
+
+int
+ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
+		   int lun, u_int tag, role_t role, uint32_t status,
+		   ahc_search_action action)
+{
+	struct	scb *scb;
+	struct	scb *prev_scb;
+	uint8_t qinstart;
+	uint8_t qinpos;
+	uint8_t qintail;
+	uint8_t next, prev;
+	uint8_t curscbptr;
+	int	found;
+	int	maxtarget;
+	int	i;
+	int	have_qregs;
+
+	qintail = ahc->qinfifonext;
+	have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0;
+	if (have_qregs) {
+		qinstart = ahc_inb(ahc, SNSCB_QOFF);
+		ahc_outb(ahc, SNSCB_QOFF, qinstart);
+	} else
+		qinstart = ahc_inb(ahc, QINPOS);
+	qinpos = qinstart;
+	next = ahc_inb(ahc, NEXT_QUEUED_SCB);
+	found = 0;
+	prev_scb = NULL;
+
+	if (action == SEARCH_COMPLETE) {
+		/*
+		 * Don't attempt to run any queued untagged transactions
+		 * until we are done with the abort process.
+		 */
+		ahc_freeze_untagged_queues(ahc);
+	}
+
+	/*
+	 * Start with an empty queue.  Entries that are not chosen
+	 * for removal will be re-added to the queue as we go.
+	 */
+	ahc->qinfifonext = qinpos;
+	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
+
+	while (qinpos != qintail) {
+		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]);
+		if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) {
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahc_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahc_set_transaction_status(scb,
+								   status);
+				cstat = ahc_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahc_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in qinfifo\n");
+				ahc_done(ahc, scb);
+
+				/* FALLTHROUGH */
+			case SEARCH_REMOVE:
+				break;
+			}
+			case SEARCH_COUNT:
+				ahc_qinfifo_requeue(ahc, prev_scb, scb);
+				prev_scb = scb;
+				break;
+			}
+		} else {
+			ahc_qinfifo_requeue(ahc, prev_scb, scb);
+			prev_scb = scb;
+		}
+		qinpos++;
+	}
+
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+	} else {
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+	}
+
+	if (action != SEARCH_COUNT
+	 && (found != 0)
+	 && (qinstart != ahc->qinfifonext)) {
+		/*
+		 * The sequencer may be in the process of dmaing
+		 * down the SCB at the beginning of the queue.
+		 * This could be problematic if either the first,
+		 * or the second SCB is removed from the queue
+		 * (the first SCB includes a pointer to the "next"
+		 * SCB to dma). If we have removed any entries, swap
+		 * the first element in the queue with the next HSCB
+		 * so the sequencer will notice that NEXT_QUEUED_SCB
+		 * has changed during its dma attempt and will retry
+		 * the DMA.
+		 */
+		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);
+
+		/*
+		 * ahc_swap_with_next_hscb forces our next pointer to
+		 * point to the reserved SCB for future commands.  Save
+		 * and restore our original next pointer to maintain
+		 * queue integrity.
+		 */
+		next = scb->hscb->next;
+		ahc->scb_data->scbindex[scb->hscb->tag] = NULL;
+		ahc_swap_with_next_hscb(ahc, scb);
+		scb->hscb->next = next;
+		ahc->qinfifo[qinstart] = scb->hscb->tag;
+
+		/* Tell the card about the new head of the qinfifo. */
+		ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag);
+
+		/* Fixup the tail "next" pointer. */
+		qintail = ahc->qinfifonext - 1;
+		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]);
+		scb->hscb->next = ahc->next_queued_scb->hscb->tag;
+	}
+
+	/*
+	 * Search waiting for selection list.
+	 */
+	curscbptr = ahc_inb(ahc, SCBPTR);
+	next = ahc_inb(ahc, WAITING_SCBH);  /* Start at head of list. */
+	prev = SCB_LIST_NULL;
+
+	while (next != SCB_LIST_NULL) {
+		uint8_t scb_index;
+
+		ahc_outb(ahc, SCBPTR, next);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+		if (scb_index >= ahc->scb_data->numscbs) {
+			printf("Waiting List inconsistency. "
+			       "SCB index == %d, yet numscbs == %d.",
+			       scb_index, ahc->scb_data->numscbs);
+			ahc_dump_card_state(ahc);
+			panic("for safety");
+		}
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (ahc_match_scb(ahc, scb, target, channel,
+				  lun, SCB_LIST_NULL, role)) {
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahc_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahc_set_transaction_status(scb,
+								   status);
+				cstat = ahc_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahc_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in Waiting List\n");
+				ahc_done(ahc, scb);
+				/* FALLTHROUGH */
+			}
+			case SEARCH_REMOVE:
+				next = ahc_rem_wscb(ahc, next, prev);
+				break;
+			case SEARCH_COUNT:
+				prev = next;
+				next = ahc_inb(ahc, SCB_NEXT);
+				break;
+			}
+		} else {
+			
+			prev = next;
+			next = ahc_inb(ahc, SCB_NEXT);
+		}
+	}
+	ahc_outb(ahc, SCBPTR, curscbptr);
+
+	/*
+	 * And lastly, the untagged holding queues.
+	 */
+	i = 0;
+	if ((ahc->flags & AHC_SCB_BTT) == 0) {
+
+		maxtarget = 16;
+		if (target != CAM_TARGET_WILDCARD) {
+
+			i = target;
+			if (channel == 'B')
+				i += 8;
+			maxtarget = i + 1;
+		}
+	} else {
+		maxtarget = 0;
+	}
+
+	for (; i < maxtarget; i++) {
+		struct scb_tailq *untagged_q;
+		struct scb *next_scb;
+
+		untagged_q = &(ahc->untagged_queues[i]);
+		next_scb = TAILQ_FIRST(untagged_q);
+		while (next_scb != NULL) {
+
+			scb = next_scb;
+			next_scb = TAILQ_NEXT(scb, links.tqe);
+
+			/*
+			 * The head of the list may be the currently
+			 * active untagged command for a device.
+			 * We're only searching for commands that
+			 * have not been started.  A transaction
+			 * marked active but still in the qinfifo
+			 * is removed by the qinfifo scanning code
+			 * above.
+			 */
+			if ((scb->flags & SCB_ACTIVE) != 0)
+				continue;
+
+			if (ahc_match_scb(ahc, scb, target, channel,
+					  lun, SCB_LIST_NULL, role)) {
+				/*
+				 * We found an scb that needs to be acted on.
+				 */
+				found++;
+				switch (action) {
+				case SEARCH_COMPLETE:
+				{
+					cam_status ostat;
+					cam_status cstat;
+
+					ostat = ahc_get_transaction_status(scb);
+					if (ostat == CAM_REQ_INPROG)
+						ahc_set_transaction_status(scb,
+								   status);
+					cstat = ahc_get_transaction_status(scb);
+					if (cstat != CAM_REQ_CMP)
+						ahc_freeze_scb(scb);
+					if ((scb->flags & SCB_ACTIVE) == 0)
+						printf("Inactive SCB in untaggedQ\n");
+					ahc_done(ahc, scb);
+					break;
+				}
+				case SEARCH_REMOVE:
+					TAILQ_REMOVE(untagged_q, scb,
+						     links.tqe);
+					break;
+				case SEARCH_COUNT:
+					break;
+				}
+			}
+		}
+	}
+
+	if (action == SEARCH_COMPLETE)
+		ahc_release_untagged_queues(ahc);
+	return (found);
+}
+
+int
+ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel,
+		     int lun, u_int tag, int stop_on_first, int remove,
+		     int save_state)
+{
+	struct	scb *scbp;
+	u_int	next;
+	u_int	prev;
+	u_int	count;
+	u_int	active_scb;
+
+	count = 0;
+	next = ahc_inb(ahc, DISCONNECTED_SCBH);
+	prev = SCB_LIST_NULL;
+
+	if (save_state) {
+		/* restore this when we're done */
+		active_scb = ahc_inb(ahc, SCBPTR);
+	} else
+		/* Silence compiler */
+		active_scb = SCB_LIST_NULL;
+
+	while (next != SCB_LIST_NULL) {
+		u_int scb_index;
+
+		ahc_outb(ahc, SCBPTR, next);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+		if (scb_index >= ahc->scb_data->numscbs) {
+			printf("Disconnected List inconsistency. "
+			       "SCB index == %d, yet numscbs == %d.",
+			       scb_index, ahc->scb_data->numscbs);
+			ahc_dump_card_state(ahc);
+			panic("for safety");
+		}
+
+		if (next == prev) {
+			panic("Disconnected List Loop. "
+			      "cur SCBPTR == %x, prev SCBPTR == %x.",
+			      next, prev);
+		}
+		scbp = ahc_lookup_scb(ahc, scb_index);
+		if (ahc_match_scb(ahc, scbp, target, channel, lun,
+				  tag, ROLE_INITIATOR)) {
+			count++;
+			if (remove) {
+				next =
+				    ahc_rem_scb_from_disc_list(ahc, prev, next);
+			} else {
+				prev = next;
+				next = ahc_inb(ahc, SCB_NEXT);
+			}
+			if (stop_on_first)
+				break;
+		} else {
+			prev = next;
+			next = ahc_inb(ahc, SCB_NEXT);
+		}
+	}
+	if (save_state)
+		ahc_outb(ahc, SCBPTR, active_scb);
+	return (count);
+}
+
+/*
+ * Remove an SCB from the on chip list of disconnected transactions.
+ * This is empty/unused if we are not performing SCB paging.
+ */
+static u_int
+ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr)
+{
+	u_int next;
+
+	ahc_outb(ahc, SCBPTR, scbptr);
+	next = ahc_inb(ahc, SCB_NEXT);
+
+	ahc_outb(ahc, SCB_CONTROL, 0);
+
+	ahc_add_curscb_to_free_list(ahc);
+
+	if (prev != SCB_LIST_NULL) {
+		ahc_outb(ahc, SCBPTR, prev);
+		ahc_outb(ahc, SCB_NEXT, next);
+	} else
+		ahc_outb(ahc, DISCONNECTED_SCBH, next);
+
+	return (next);
+}
+
+/*
+ * Add the SCB as selected by SCBPTR onto the on chip list of
+ * free hardware SCBs.  This list is empty/unused if we are not
+ * performing SCB paging.
+ */
+static void
+ahc_add_curscb_to_free_list(struct ahc_softc *ahc)
+{
+	/*
+	 * Invalidate the tag so that our abort
+	 * routines don't think it's active.
+	 */
+	ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH));
+		ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR));
+	}
+}
+
+/*
+ * Manipulate the waiting for selection list and return the
+ * scb that follows the one that we remove.
+ */
+static u_int
+ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
+{       
+	u_int curscb, next;
+
+	/*
+	 * Select the SCB we want to abort and
+	 * pull the next pointer out of it.
+	 */
+	curscb = ahc_inb(ahc, SCBPTR);
+	ahc_outb(ahc, SCBPTR, scbpos);
+	next = ahc_inb(ahc, SCB_NEXT);
+
+	/* Clear the necessary fields */
+	ahc_outb(ahc, SCB_CONTROL, 0);
+
+	ahc_add_curscb_to_free_list(ahc);
+
+	/* update the waiting list */
+	if (prev == SCB_LIST_NULL) {
+		/* First in the list */
+		ahc_outb(ahc, WAITING_SCBH, next); 
+
+		/*
+		 * Ensure we aren't attempting to perform
+		 * selection for this entry.
+		 */
+		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+	} else {
+		/*
+		 * Select the scb that pointed to us 
+		 * and update its next pointer.
+		 */
+		ahc_outb(ahc, SCBPTR, prev);
+		ahc_outb(ahc, SCB_NEXT, next);
+	}
+
+	/*
+	 * Point us back at the original scb position.
+	 */
+	ahc_outb(ahc, SCBPTR, curscb);
+	return next;
+}
+
+/******************************** Error Handling ******************************/
+/*
+ * Abort all SCBs that match the given description (target/channel/lun/tag),
+ * setting their status to the passed in status if the status has not already
+ * been modified from CAM_REQ_INPROG.  This routine assumes that the sequencer
+ * is paused before it is called.
+ */
+int
+ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
+	       int lun, u_int tag, role_t role, uint32_t status)
+{
+	struct	scb *scbp;
+	struct	scb *scbp_next;
+	u_int	active_scb;
+	int	i, j;
+	int	maxtarget;
+	int	minlun;
+	int	maxlun;
+
+	int	found;
+
+	/*
+	 * Don't attempt to run any queued untagged transactions
+	 * until we are done with the abort process.
+	 */
+	ahc_freeze_untagged_queues(ahc);
+
+	/* restore this when we're done */
+	active_scb = ahc_inb(ahc, SCBPTR);
+
+	found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL,
+				   role, CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+
+	/*
+	 * Clean out the busy target table for any untagged commands.
+	 */
+	i = 0;
+	maxtarget = 16;
+	if (target != CAM_TARGET_WILDCARD) {
+		i = target;
+		if (channel == 'B')
+			i += 8;
+		maxtarget = i + 1;
+	}
+
+	if (lun == CAM_LUN_WILDCARD) {
+
+		/*
+		 * Unless we are using an SCB based
+		 * busy targets table, there is only
+		 * one table entry for all luns of
+		 * a target.
+		 */
+		minlun = 0;
+		maxlun = 1;
+		if ((ahc->flags & AHC_SCB_BTT) != 0)
+			maxlun = AHC_NUM_LUNS;
+	} else {
+		minlun = lun;
+		maxlun = lun + 1;
+	}
+
+	for (;i < maxtarget; i++) {
+		for (j = minlun;j < maxlun; j++)
+			ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j));
+	}
+
+	/*
+	 * Go through the disconnected list and remove any entries we
+	 * have queued for completion, 0'ing their control byte too.
+	 * We save the active SCB and restore it ourselves, so there
+	 * is no reason for this search to restore it too.
+	 */
+	ahc_search_disc_list(ahc, target, channel, lun, tag,
+			     /*stop_on_first*/FALSE, /*remove*/TRUE,
+			     /*save_state*/FALSE);
+
+	/*
+	 * Go through the hardware SCB array looking for commands that
+	 * were active but not on any list.
+	 */
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		u_int scbid;
+
+		ahc_outb(ahc, SCBPTR, i);
+		scbid = ahc_inb(ahc, SCB_TAG);
+		scbp = ahc_lookup_scb(ahc, scbid);
+		if (scbp != NULL
+		 && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))
+			ahc_add_curscb_to_free_list(ahc);
+	}
+
+	/*
+	 * Go through the pending CCB list and look for
+	 * commands for this target that are still active.
+	 * These are other tagged commands that were
+	 * disconnected when the reset occured.
+	 */
+	scbp_next = LIST_FIRST(&ahc->pending_scbs);
+	while (scbp_next != NULL) {
+		scbp = scbp_next;
+		scbp_next = LIST_NEXT(scbp, pending_links);
+		if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) {
+			cam_status ostat;
+
+			ostat = ahc_get_transaction_status(scbp);
+			if (ostat == CAM_REQ_INPROG)
+				ahc_set_transaction_status(scbp, status);
+			if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP)
+				ahc_freeze_scb(scbp);
+			if ((scbp->flags & SCB_ACTIVE) == 0)
+				printf("Inactive SCB on pending list\n");
+			ahc_done(ahc, scbp);
+			found++;
+		}
+	}
+	ahc_outb(ahc, SCBPTR, active_scb);
+	ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status);
+	ahc_release_untagged_queues(ahc);
+	return found;
+}
+
+static void
+ahc_reset_current_bus(struct ahc_softc *ahc)
+{
+	uint8_t scsiseq;
+
+	ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST);
+	scsiseq = ahc_inb(ahc, SCSISEQ);
+	ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO);
+	ahc_delay(AHC_BUSRESET_DELAY);
+	/* Turn off the bus reset */
+	ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO);
+
+	ahc_clear_intstat(ahc);
+
+	/* Re-enable reset interrupts */
+	ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST);
+}
+
+int
+ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
+{
+	struct	ahc_devinfo devinfo;
+	u_int	initiator, target, max_scsiid;
+	u_int	sblkctl;
+	int	found;
+	int	restart_needed;
+	char	cur_channel;
+
+	ahc->pending_device = NULL;
+
+	ahc_compile_devinfo(&devinfo,
+			    CAM_TARGET_WILDCARD,
+			    CAM_TARGET_WILDCARD,
+			    CAM_LUN_WILDCARD,
+			    channel, ROLE_UNKNOWN);
+	pause_sequencer(ahc);
+
+	/* Make sure the sequencer is in a safe location. */
+	ahc_clear_critical_section(ahc);
+
+	/*
+	 * Run our command complete fifos to ensure that we perform
+	 * completion processing on any commands that 'completed'
+	 * before the reset occurred.
+	 */
+	ahc_run_qoutfifo(ahc);
+#if AHC_TARGET_MODE
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		ahc_run_tqinfifo(ahc, /*paused*/TRUE);
+	}
+#endif
+
+	/*
+	 * Reset the bus if we are initiating this reset
+	 */
+	sblkctl = ahc_inb(ahc, SBLKCTL);
+	cur_channel = 'A';
+	if ((ahc->features & AHC_TWIN) != 0
+	 && ((sblkctl & SELBUSB) != 0))
+	    cur_channel = 'B';
+	if (cur_channel != channel) {
+		/* Case 1: Command for another bus is active
+		 * Stealthily reset the other bus without
+		 * upsetting the current bus.
+		 */
+		ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
+		ahc_outb(ahc, SIMODE1,
+			 ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+		if (initiate_reset)
+			ahc_reset_current_bus(ahc);
+		ahc_clear_intstat(ahc);
+		ahc_outb(ahc, SBLKCTL, sblkctl);
+		restart_needed = FALSE;
+	} else {
+		/* Case 2: A command from this bus is active or we're idle */
+		ahc_clear_msg_state(ahc);
+		ahc_outb(ahc, SIMODE1,
+			 ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+		if (initiate_reset)
+			ahc_reset_current_bus(ahc);
+		ahc_clear_intstat(ahc);
+		restart_needed = TRUE;
+	}
+
+	/*
+	 * Clean up all the state information for the
+	 * pending transactions on this bus.
+	 */
+	found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel,
+			       CAM_LUN_WILDCARD, SCB_LIST_NULL,
+			       ROLE_UNKNOWN, CAM_SCSI_BUS_RESET);
+
+	max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7;
+
+#ifdef AHC_TARGET_MODE
+	/*
+	 * Send an immediate notify ccb to all target more peripheral
+	 * drivers affected by this action.
+	 */
+	for (target = 0; target <= max_scsiid; target++) {
+		struct tmode_tstate* tstate;
+		u_int lun;
+
+		tstate = ahc->enabled_targets[target];
+		if (tstate == NULL)
+			continue;
+		for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+			struct tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[lun];
+			if (lstate == NULL)
+				continue;
+
+			ahc_queue_lstate_event(ahc, lstate, CAM_TARGET_WILDCARD,
+					       EVENT_TYPE_BUS_RESET, /*arg*/0);
+			ahc_send_lstate_events(ahc, lstate);
+		}
+	}
+#endif
+	/* Notify the XPT that a bus reset occurred */
+	ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
+		       CAM_LUN_WILDCARD, AC_BUS_RESET);
+
+	/*
+	 * Revert to async/narrow transfers until we renegotiate.
+	 */
+	for (target = 0; target <= max_scsiid; target++) {
+
+		if (ahc->enabled_targets[target] == NULL)
+			continue;
+		for (initiator = 0; initiator <= max_scsiid; initiator++) {
+			struct ahc_devinfo devinfo;
+
+			ahc_compile_devinfo(&devinfo, target, initiator,
+					    CAM_LUN_WILDCARD,
+					    channel, ROLE_UNKNOWN);
+			ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHC_TRANS_CUR, /*paused*/TRUE);
+			ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL,
+					 /*period*/0, /*offset*/0,
+					 /*ppr_options*/0, AHC_TRANS_CUR,
+					 /*paused*/TRUE);
+		}
+	}
+
+	if (restart_needed)
+		restart_sequencer(ahc);
+	else
+		unpause_sequencer(ahc);
+	return found;
+}
+
+
+/***************************** Residual Processing ****************************/
+/*
+ * Calculate the residual for a just completed SCB.
+ */
+static void
+ahc_calc_residual(struct scb *scb)
+{
+	struct hardware_scb *hscb;
+	struct status_pkt *spkt;
+	uint32_t sgptr;
+	uint32_t resid_sgptr;
+	uint32_t resid;
+
+	/*
+	 * 5 cases.
+	 * 1) No residual.
+	 *    SG_RESID_VALID clear in sgptr.
+	 * 2) Transferless command
+	 * 3) Never performed any transfers.
+	 *    sgptr has SG_FULL_RESID set.
+	 * 4) No residual but target did not
+	 *    save data pointers after the
+	 *    last transfer, so sgptr was
+	 *    never updated.
+	 * 5) We have a partial residual.
+	 *    Use residual_sgptr to determine
+	 *    where we are.
+	 */
+
+	hscb = scb->hscb;
+	sgptr = ahc_le32toh(hscb->sgptr);
+	if ((sgptr & SG_RESID_VALID) == 0)
+		/* Case 1 */
+		return;
+	sgptr &= ~SG_RESID_VALID;
+
+	if ((sgptr & SG_LIST_NULL) != 0)
+		/* Case 2 */
+		return;
+
+	spkt = &hscb->shared_data.status;
+	resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr);
+	if ((sgptr & SG_FULL_RESID) != 0) {
+		/* Case 3 */
+		resid = ahc_get_transfer_length(scb);
+	} else if ((resid_sgptr & SG_LIST_NULL) != 0) {
+		/* Case 4 */
+		return;
+	} else if ((resid_sgptr & ~SG_PTR_MASK) != 0) {
+		panic("Bogus resid sgptr value 0x%x\n", resid_sgptr);
+	} else {
+		struct ahc_dma_seg *sg;
+
+		/*
+		 * Remainder of the SG where the transfer
+		 * stopped.  
+		 */
+		resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK;
+		sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK);
+
+		/* The residual sg_ptr always points to the next sg */
+		sg--;
+
+		/*
+		 * Add up the contents of all residual
+		 * SG segments that are after the SG where
+		 * the transfer stopped.
+		 */
+		while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) {
+			sg++;
+			resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK;
+		}
+	}
+	if ((scb->flags & SCB_SENSE) == 0)
+		ahc_set_residual(scb, resid);
+	else
+		ahc_set_sense_residual(scb, resid);
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOWMISC) {
+		ahc_print_path(ahc, scb);
+		printf("Handled Residual of %d bytes\n", resid);
+	}
+#endif
+}
+
+/******************************* Target Mode **********************************/
+#ifdef AHC_TARGET_MODE
+/*
+ * Add a target mode event to this lun's queue
+ */
+static void
+ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate,
+		       u_int initiator_id, u_int event_type, u_int event_arg)
+{
+	struct ahc_tmode_event *event;
+	int pending;
+
+	xpt_freeze_devq(lstate->path, /*count*/1);
+	if (lstate->event_w_idx >= lstate->event_r_idx)
+		pending = lstate->event_w_idx - lstate->event_r_idx;
+	else
+		pending = AHC_TMODE_EVENT_BUFFER_SIZE + 1
+			- (lstate->event_r_idx - lstate->event_w_idx);
+
+	if (event_type == EVENT_TYPE_BUS_RESET
+	 || event_type == MSG_BUS_DEV_RESET) {
+		/*
+		 * Any earlier events are irrelevant, so reset our buffer.
+		 * This has the effect of allowing us to deal with reset
+		 * floods (an external device holding down the reset line)
+		 * without losing the event that is really interesting.
+		 */
+		lstate->event_r_idx = 0;
+		lstate->event_w_idx = 0;
+		xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE);
+	}
+
+	if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) {
+		xpt_print_path(lstate->path);
+		printf("immediate event %x:%x lost\n",
+		       lstate->event_buffer[lstate->event_r_idx].event_type,
+		       lstate->event_buffer[lstate->event_r_idx].event_arg);
+		lstate->event_r_idx++;
+		if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE)
+			lstate->event_r_idx = 0;
+		xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE);
+	}
+
+	event = &lstate->event_buffer[lstate->event_w_idx];
+	event->initiator_id = initiator_id;
+	event->event_type = event_type;
+	event->event_arg = event_arg;
+	lstate->event_w_idx++;
+	if (lstate->event_w_idx == AHC_TMODE_EVENT_BUFFER_SIZE)
+		lstate->event_w_idx = 0;
+}
+
+/*
+ * Send any target mode events queued up waiting
+ * for immediate notify resources.
+ */
+void
+ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate)
+{
+	struct ccb_hdr *ccbh;
+	struct ccb_immed_notify *inot;
+
+	while (lstate->event_r_idx != lstate->event_w_idx
+	    && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) {
+		struct ahc_tmode_event *event;
+
+		event = &lstate->event_buffer[lstate->event_r_idx];
+		SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle);
+		inot = (struct ccb_immed_notify *)ccbh;
+		switch (event->event_type) {
+		case EVENT_TYPE_BUS_RESET:
+			ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN;
+			break;
+		default:
+			ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN;
+			inot->message_args[0] = event->event_type;
+			inot->message_args[1] = event->event_arg;
+			break;
+		}
+		inot->initiator_id = event->initiator_id;
+		inot->sense_len = 0;
+		xpt_done((union ccb *)inot);
+		lstate->event_r_idx++;
+		if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE)
+			lstate->event_r_idx = 0;
+	}
+}
+#endif
+
+/******************** Sequencer Program Patching/Download *********************/
+
+#ifdef AHC_DUMP_SEQ
+void
+ahc_dumpseq(struct ahc_softc* ahc)
+{
+	int i;
+	int max_prog;
+
+	if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI)
+		max_prog = 448;
+	else if ((ahc->features & AHC_ULTRA2) != 0)
+		max_prog = 768;
+	else
+		max_prog = 512;
+
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+	ahc_outb(ahc, SEQADDR0, 0);
+	ahc_outb(ahc, SEQADDR1, 0);
+	for (i = 0; i < max_prog; i++) {
+		uint8_t ins_bytes[4];
+
+		ahc_insb(ahc, SEQRAM, ins_bytes, 4);
+		printf("0x%08x\n", ins_bytes[0] << 24
+				 | ins_bytes[1] << 16
+				 | ins_bytes[2] << 8
+				 | ins_bytes[3]);
+	}
+}
+#endif
+
+static void
+ahc_loadseq(struct ahc_softc *ahc)
+{
+	struct	cs cs_table[num_critical_sections];
+	u_int	begin_set[num_critical_sections];
+	u_int	end_set[num_critical_sections];
+	struct	patch *cur_patch;
+	u_int	cs_count;
+	u_int	cur_cs;
+	u_int	i;
+	int	downloaded;
+	u_int	skip_addr;
+	u_int	sg_prefetch_cnt;
+	uint8_t	download_consts[7];
+
+	/*
+	 * Start out with 0 critical sections
+	 * that apply to this firmware load.
+	 */
+	cs_count = 0;
+	cur_cs = 0;
+	memset(begin_set, 0, sizeof(begin_set));
+	memset(end_set, 0, sizeof(end_set));
+
+	/* Setup downloadable constant table */
+	download_consts[QOUTFIFO_OFFSET] = 0;
+	if (ahc->targetcmds != NULL)
+		download_consts[QOUTFIFO_OFFSET] += 32;
+	download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1;
+	download_consts[CACHESIZE_MASK] = ahc->pci_cachesize - 1;
+	download_consts[INVERTED_CACHESIZE_MASK] = ~(ahc->pci_cachesize - 1);
+	sg_prefetch_cnt = ahc->pci_cachesize;
+	if (sg_prefetch_cnt < (2 * sizeof(struct ahc_dma_seg)))
+		sg_prefetch_cnt = 2 * sizeof(struct ahc_dma_seg);
+	download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt;
+	download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_cnt - 1);
+	download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_cnt - 1);
+
+	cur_patch = patches;
+	downloaded = 0;
+	skip_addr = 0;
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+	ahc_outb(ahc, SEQADDR0, 0);
+	ahc_outb(ahc, SEQADDR1, 0);
+
+	for (i = 0; i < sizeof(seqprog)/4; i++) {
+		if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) {
+			/*
+			 * Don't download this instruction as it
+			 * is in a patch that was removed.
+			 */
+			continue;
+		}
+		/*
+		 * Move through the CS table until we find a CS
+		 * that might apply to this instruction.
+		 */
+		for (; cur_cs < num_critical_sections; cur_cs++) {
+			if (critical_sections[cur_cs].end <= i) {
+				if (begin_set[cs_count] == TRUE
+				 && end_set[cs_count] == FALSE) {
+					cs_table[cs_count].end = downloaded;
+				 	end_set[cs_count] = TRUE;
+					cs_count++;
+				}
+				continue;
+			}
+			if (critical_sections[cur_cs].begin <= i
+			 && begin_set[cs_count] == FALSE) {
+				cs_table[cs_count].begin = downloaded;
+				begin_set[cs_count] = TRUE;
+			}
+			break;
+		}
+		ahc_download_instr(ahc, i, download_consts);
+		downloaded++;
+	}
+
+	ahc->num_critical_sections = cs_count;
+	if (cs_count != 0) {
+
+		cs_count *= sizeof(struct cs);
+		ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+		if (ahc->critical_sections == NULL)
+			panic("ahc_loadseq: Could not malloc");
+		memcpy(ahc->critical_sections, cs_table, cs_count);
+	}
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
+	restart_sequencer(ahc);
+
+	if (bootverbose)
+		printf(" %d instructions downloaded\n", downloaded);
+}
+
+static int
+ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch,
+		u_int start_instr, u_int *skip_addr)
+{
+	struct	patch *cur_patch;
+	struct	patch *last_patch;
+	u_int	num_patches;
+
+	num_patches = sizeof(patches)/sizeof(struct patch);
+	last_patch = &patches[num_patches];
+	cur_patch = *start_patch;
+
+	while (cur_patch < last_patch && start_instr == cur_patch->begin) {
+
+		if (cur_patch->patch_func(ahc) == 0) {
+
+			/* Start rejecting code */
+			*skip_addr = start_instr + cur_patch->skip_instr;
+			cur_patch += cur_patch->skip_patch;
+		} else {
+			/* Accepted this patch.  Advance to the next
+			 * one and wait for our intruction pointer to
+			 * hit this point.
+			 */
+			cur_patch++;
+		}
+	}
+
+	*start_patch = cur_patch;
+	if (start_instr < *skip_addr)
+		/* Still skipping */
+		return (0);
+
+	return (1);
+}
+
+static void
+ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
+{
+	union	ins_formats instr;
+	struct	ins_format1 *fmt1_ins;
+	struct	ins_format3 *fmt3_ins;
+	u_int	opcode;
+
+	/*
+	 * The firmware is always compiled into a little endian format.
+	 */
+	instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]);
+
+	fmt1_ins = &instr.format1;
+	fmt3_ins = NULL;
+
+	/* Pull the opcode */
+	opcode = instr.format1.opcode;
+	switch (opcode) {
+	case AIC_OP_JMP:
+	case AIC_OP_JC:
+	case AIC_OP_JNC:
+	case AIC_OP_CALL:
+	case AIC_OP_JNE:
+	case AIC_OP_JNZ:
+	case AIC_OP_JE:
+	case AIC_OP_JZ:
+	{
+		struct patch *cur_patch;
+		int address_offset;
+		u_int address;
+		u_int skip_addr;
+		u_int i;
+
+		fmt3_ins = &instr.format3;
+		address_offset = 0;
+		address = fmt3_ins->address;
+		cur_patch = patches;
+		skip_addr = 0;
+
+		for (i = 0; i < address;) {
+
+			ahc_check_patch(ahc, &cur_patch, i, &skip_addr);
+
+			if (skip_addr > i) {
+				int end_addr;
+
+				end_addr = MIN(address, skip_addr);
+				address_offset += end_addr - i;
+				i = skip_addr;
+			} else {
+				i++;
+			}
+		}
+		address -= address_offset;
+		fmt3_ins->address = address;
+		/* FALLTHROUGH */
+	}
+	case AIC_OP_OR:
+	case AIC_OP_AND:
+	case AIC_OP_XOR:
+	case AIC_OP_ADD:
+	case AIC_OP_ADC:
+	case AIC_OP_BMOV:
+		if (fmt1_ins->parity != 0) {
+			fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
+		}
+		fmt1_ins->parity = 0;
+		if ((ahc->features & AHC_CMD_CHAN) == 0
+		 && opcode == AIC_OP_BMOV) {
+			/*
+			 * Block move was added at the same time
+			 * as the command channel.  Verify that
+			 * this is only a move of a single element
+			 * and convert the BMOV to a MOV
+			 * (AND with an immediate of FF).
+			 */
+			if (fmt1_ins->immediate != 1)
+				panic("%s: BMOV not supported\n",
+				      ahc_name(ahc));
+			fmt1_ins->opcode = AIC_OP_AND;
+			fmt1_ins->immediate = 0xff;
+		}
+		/* FALLTHROUGH */
+	case AIC_OP_ROL:
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			int i, count;
+
+			/* Calculate odd parity for the instruction */
+			for (i = 0, count = 0; i < 31; i++) {
+				uint32_t mask;
+
+				mask = 0x01 << i;
+				if ((instr.integer & mask) != 0)
+					count++;
+			}
+			if ((count & 0x01) == 0)
+				instr.format1.parity = 1;
+		} else {
+			/* Compress the instruction for older sequencers */
+			if (fmt3_ins != NULL) {
+				instr.integer =
+					fmt3_ins->immediate
+				      | (fmt3_ins->source << 8)
+				      | (fmt3_ins->address << 16)
+				      |	(fmt3_ins->opcode << 25);
+			} else {
+				instr.integer =
+					fmt1_ins->immediate
+				      | (fmt1_ins->source << 8)
+				      | (fmt1_ins->destination << 16)
+				      |	(fmt1_ins->ret << 24)
+				      |	(fmt1_ins->opcode << 25);
+			}
+		}
+		/* The sequencer is a little endian cpu */
+		instr.integer = ahc_htole32(instr.integer);
+		ahc_outsb(ahc, SEQRAM, instr.bytes, 4);
+		break;
+	default:
+		panic("Unknown opcode encountered in seq program");
+		break;
+	}
+}
+
+void
+ahc_dump_card_state(struct ahc_softc *ahc)
+{
+	struct scb *scb;
+	struct scb_tailq *untagged_q;
+	int target;
+	int maxtarget;
+	int i;
+	uint8_t qinpos;
+	uint8_t qintail;
+	uint8_t qoutpos;
+	uint8_t scb_index;
+	uint8_t saved_scbptr;
+
+	saved_scbptr = ahc_inb(ahc, SCBPTR);
+
+	printf("%s: Dumping Card State at SEQADDR 0x%x\n",
+	       ahc_name(ahc),
+	       ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+
+	printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n",
+	       ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL),
+	       ahc_inb(ahc, SSTAT0));
+	printf("SCB count = %d\n", ahc->scb_data->numscbs);
+	printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
+	printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
+	/* QINFIFO */
+	printf("QINFIFO entries: ");
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		qinpos = ahc_inb(ahc, SNSCB_QOFF);
+		ahc_outb(ahc, SNSCB_QOFF, qinpos);
+	} else
+		qinpos = ahc_inb(ahc, QINPOS);
+	qintail = ahc->qinfifonext;
+	while (qinpos != qintail) {
+		printf("%d ", ahc->qinfifo[qinpos]);
+		qinpos++;
+	}
+	printf("\n");
+
+	printf("Waiting Queue entries: ");
+	scb_index = ahc_inb(ahc, WAITING_SCBH);
+	i = 0;
+	while (scb_index != SCB_LIST_NULL && i++ < 256) {
+		ahc_outb(ahc, SCBPTR, scb_index);
+		printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+		scb_index = ahc_inb(ahc, SCB_NEXT);
+	}
+	printf("\n");
+
+	printf("Disconnected Queue entries: ");
+	scb_index = ahc_inb(ahc, DISCONNECTED_SCBH);
+	i = 0;
+	while (scb_index != SCB_LIST_NULL && i++ < 256) {
+		ahc_outb(ahc, SCBPTR, scb_index);
+		printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+		scb_index = ahc_inb(ahc, SCB_NEXT);
+	}
+	printf("\n");
+		
+	printf("QOUTFIFO entries: ");
+	qoutpos = ahc->qoutfifonext;
+	i = 0;
+	while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) {
+		printf("%d ", ahc->qoutfifo[qoutpos]);
+		qoutpos++;
+	}
+	printf("\n");
+
+	printf("Sequencer Free SCB List: ");
+	scb_index = ahc_inb(ahc, FREE_SCBH);
+	i = 0;
+	while (scb_index != SCB_LIST_NULL && i++ < 256) {
+		ahc_outb(ahc, SCBPTR, scb_index);
+		printf("%d ", scb_index);
+		scb_index = ahc_inb(ahc, SCB_NEXT);
+	}
+	printf("\n");
+
+	printf("Pending list: ");
+	i = 0;
+	LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
+		if (i++ > 256)
+			break;
+		printf("%d ", scb->hscb->tag);
+	}
+	printf("\n");
+
+	printf("Kernel Free SCB list: ");
+	i = 0;
+	SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) {
+		if (i++ > 256)
+			break;
+		printf("%d ", scb->hscb->tag);
+	}
+	printf("\n");
+
+	maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7;
+	for (target = 0; target <= maxtarget; target++) {
+		untagged_q = &ahc->untagged_queues[target];
+		if (TAILQ_FIRST(untagged_q) == NULL)
+			continue;
+		printf("Untagged Q(%d): ", target);
+		i = 0;
+		TAILQ_FOREACH(scb, untagged_q, links.tqe) {
+			if (i++ > 256)
+				break;
+			printf("%d ", scb->hscb->tag);
+		}
+		printf("\n");
+	}
+
+	ahc_platform_dump_card_state(ahc);
+	ahc_outb(ahc, SCBPTR, saved_scbptr);
+}
+
+/************************* Target Mode ****************************************/
+#ifdef AHC_TARGET_MODE
+cam_status
+ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb,
+		    struct tmode_tstate **tstate, struct tmode_lstate **lstate,
+		    int notfound_failure)
+{
+
+	if ((ahc->features & AHC_TARGETMODE) == 0)
+		return (CAM_REQ_INVALID);
+
+	/*
+	 * Handle the 'black hole' device that sucks up
+	 * requests to unattached luns on enabled targets.
+	 */
+	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD
+	 && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
+		*tstate = NULL;
+		*lstate = ahc->black_hole;
+	} else {
+		u_int max_id;
+
+		max_id = (ahc->features & AHC_WIDE) ? 15 : 7;
+		if (ccb->ccb_h.target_id > max_id)
+			return (CAM_TID_INVALID);
+
+		if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS)
+			return (CAM_LUN_INVALID);
+
+		*tstate = ahc->enabled_targets[ccb->ccb_h.target_id];
+		*lstate = NULL;
+		if (*tstate != NULL)
+			*lstate =
+			    (*tstate)->enabled_luns[ccb->ccb_h.target_lun];
+	}
+
+	if (notfound_failure != 0 && *lstate == NULL)
+		return (CAM_PATH_INVALID);
+
+	return (CAM_REQ_CMP);
+}
+
+void
+ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
+{
+	struct	   tmode_tstate *tstate;
+	struct	   tmode_lstate *lstate;
+	struct	   ccb_en_lun *cel;
+	cam_status status;
+	u_int	   target;
+	u_int	   lun;
+	u_int	   target_mask;
+	u_long	   s;
+	char	   channel;
+
+	status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate,
+				     /*notfound_failure*/FALSE);
+
+	if (status != CAM_REQ_CMP) {
+		ccb->ccb_h.status = status;
+		return;
+	}
+
+	if ((ahc->features & AHC_MULTIROLE) != 0) {
+		u_int	   our_id;
+
+		if (cam_sim_bus(sim) == 0)
+			our_id = ahc->our_id;
+		else
+			our_id = ahc->our_id_b;
+
+		if (ccb->ccb_h.target_id != our_id) {
+			if ((ahc->features & AHC_MULTI_TID) != 0
+		   	 && (ahc->flags & AHC_INITIATORROLE) != 0) {
+				/*
+				 * Only allow additional targets if
+				 * the initiator role is disabled.
+				 * The hardware cannot handle a re-select-in
+				 * on the initiator id during a re-select-out
+				 * on a different target id.
+				 */
+				status = CAM_TID_INVALID;
+			} else if ((ahc->flags & AHC_INITIATORROLE) != 0
+				|| ahc->enabled_luns > 0) {
+				/*
+				 * Only allow our target id to change
+				 * if the initiator role is not configured
+				 * and there are no enabled luns which
+				 * are attached to the currently registered
+				 * scsi id.
+				 */
+				status = CAM_TID_INVALID;
+			}
+		}
+	}
+
+	if (status != CAM_REQ_CMP) {
+		ccb->ccb_h.status = status;
+		return;
+	}
+
+	/*
+	 * We now have an id that is valid.
+	 * If we aren't in target mode, switch modes.
+	 */
+	if ((ahc->flags & AHC_TARGETROLE) == 0
+	 && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
+		u_long	s;
+
+		printf("Configuring Target Mode\n");
+		ahc_lock(ahc, &s);
+		if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+			ccb->ccb_h.status = CAM_BUSY;
+			ahc_unlock(ahc, &s);
+			return;
+		}
+		ahc->flags |= AHC_TARGETROLE;
+		if ((ahc->features & AHC_MULTIROLE) == 0)
+			ahc->flags &= ~AHC_INITIATORROLE;
+		pause_sequencer(ahc);
+		ahc_loadseq(ahc);
+		ahc_unlock(ahc, &s);
+	}
+	cel = &ccb->cel;
+	target = ccb->ccb_h.target_id;
+	lun = ccb->ccb_h.target_lun;
+	channel = SIM_CHANNEL(ahc, sim);
+	target_mask = 0x01 << target;
+	if (channel == 'B')
+		target_mask <<= 8;
+
+	if (cel->enable != 0) {
+		u_int scsiseq;
+
+		/* Are we already enabled?? */
+		if (lstate != NULL) {
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Lun already enabled\n");
+			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
+			return;
+		}
+
+		if (cel->grp6_len != 0
+		 || cel->grp7_len != 0) {
+			/*
+			 * Don't (yet?) support vendor
+			 * specific commands.
+			 */
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+			printf("Non-zero Group Codes\n");
+			return;
+		}
+
+		/*
+		 * Seems to be okay.
+		 * Setup our data structures.
+		 */
+		if (target != CAM_TARGET_WILDCARD && tstate == NULL) {
+			tstate = ahc_alloc_tstate(ahc, target, channel);
+			if (tstate == NULL) {
+				xpt_print_path(ccb->ccb_h.path);
+				printf("Couldn't allocate tstate\n");
+				ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+				return;
+			}
+		}
+		lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+		if (lstate == NULL) {
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Couldn't allocate lstate\n");
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			return;
+		}
+		memset(lstate, 0, sizeof(*lstate));
+		status = xpt_create_path(&lstate->path, /*periph*/NULL,
+					 xpt_path_path_id(ccb->ccb_h.path),
+					 xpt_path_target_id(ccb->ccb_h.path),
+					 xpt_path_lun_id(ccb->ccb_h.path));
+		if (status != CAM_REQ_CMP) {
+			free(lstate, M_DEVBUF);
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Couldn't allocate path\n");
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			return;
+		}
+		SLIST_INIT(&lstate->accept_tios);
+		SLIST_INIT(&lstate->immed_notifies);
+		ahc_lock(ahc, &s);
+		pause_sequencer(ahc);
+		if (target != CAM_TARGET_WILDCARD) {
+			tstate->enabled_luns[lun] = lstate;
+			ahc->enabled_luns++;
+
+			if ((ahc->features & AHC_MULTI_TID) != 0) {
+				u_int targid_mask;
+
+				targid_mask = ahc_inb(ahc, TARGID)
+					    | (ahc_inb(ahc, TARGID + 1) << 8);
+
+				targid_mask |= target_mask;
+				ahc_outb(ahc, TARGID, targid_mask);
+				ahc_outb(ahc, TARGID+1, (targid_mask >> 8));
+				
+				ahc_update_scsiid(ahc, targid_mask);
+			} else {
+				u_int our_id;
+				char  channel;
+
+				channel = SIM_CHANNEL(ahc, sim);
+				our_id = SIM_SCSI_ID(ahc, sim);
+
+				/*
+				 * This can only happen if selections
+				 * are not enabled
+				 */
+				if (target != our_id) {
+					u_int sblkctl;
+					char  cur_channel;
+					int   swap;
+
+					sblkctl = ahc_inb(ahc, SBLKCTL);
+					cur_channel = (sblkctl & SELBUSB)
+						    ? 'B' : 'A';
+					if ((ahc->features & AHC_TWIN) == 0)
+						cur_channel = 'A';
+					swap = cur_channel != channel;
+					if (channel == 'A')
+						ahc->our_id = target;
+					else
+						ahc->our_id_b = target;
+
+					if (swap)
+						ahc_outb(ahc, SBLKCTL,
+							 sblkctl ^ SELBUSB);
+
+					ahc_outb(ahc, SCSIID, target);
+
+					if (swap)
+						ahc_outb(ahc, SBLKCTL, sblkctl);
+				}
+			}
+		} else
+			ahc->black_hole = lstate;
+		/* Allow select-in operations */
+		if (ahc->black_hole != NULL && ahc->enabled_luns > 0) {
+			scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
+			scsiseq |= ENSELI;
+			ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq);
+			scsiseq = ahc_inb(ahc, SCSISEQ);
+			scsiseq |= ENSELI;
+			ahc_outb(ahc, SCSISEQ, scsiseq);
+		}
+		unpause_sequencer(ahc);
+		ahc_unlock(ahc, &s);
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		xpt_print_path(ccb->ccb_h.path);
+		printf("Lun now enabled for target mode\n");
+	} else {
+		struct scb *scb;
+		int i, empty;
+
+		if (lstate == NULL) {
+			ccb->ccb_h.status = CAM_LUN_INVALID;
+			return;
+		}
+
+		ahc_lock(ahc, &s);
+		
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
+			struct ccb_hdr *ccbh;
+
+			ccbh = &scb->io_ctx->ccb_h;
+			if (ccbh->func_code == XPT_CONT_TARGET_IO
+			 && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
+				printf("CTIO pending\n");
+				ccb->ccb_h.status = CAM_REQ_INVALID;
+				ahc_unlock(ahc, &s);
+				return;
+			}
+		}
+
+		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
+			printf("ATIOs pending\n");
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+		}
+
+		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
+			printf("INOTs pending\n");
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+		}
+
+		if (ccb->ccb_h.status != CAM_REQ_CMP) {
+			ahc_unlock(ahc, &s);
+			return;
+		}
+
+		xpt_print_path(ccb->ccb_h.path);
+		printf("Target mode disabled\n");
+		xpt_free_path(lstate->path);
+		free(lstate, M_DEVBUF);
+
+		pause_sequencer(ahc);
+		/* Can we clean up the target too? */
+		if (target != CAM_TARGET_WILDCARD) {
+			tstate->enabled_luns[lun] = NULL;
+			ahc->enabled_luns--;
+			for (empty = 1, i = 0; i < 8; i++)
+				if (tstate->enabled_luns[i] != NULL) {
+					empty = 0;
+					break;
+				}
+
+			if (empty) {
+				ahc_free_tstate(ahc, target, channel,
+						/*force*/FALSE);
+				if (ahc->features & AHC_MULTI_TID) {
+					u_int targid_mask;
+
+					targid_mask = ahc_inb(ahc, TARGID)
+						    | (ahc_inb(ahc, TARGID + 1)
+						       << 8);
+
+					targid_mask &= ~target_mask;
+					ahc_outb(ahc, TARGID, targid_mask);
+					ahc_outb(ahc, TARGID+1,
+					 	 (targid_mask >> 8));
+					ahc_update_scsiid(ahc, targid_mask);
+				}
+			}
+		} else {
+
+			ahc->black_hole = NULL;
+
+			/*
+			 * We can't allow selections without
+			 * our black hole device.
+			 */
+			empty = TRUE;
+		}
+		if (ahc->enabled_luns == 0) {
+			/* Disallow select-in */
+			u_int scsiseq;
+
+			scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
+			scsiseq &= ~ENSELI;
+			ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq);
+			scsiseq = ahc_inb(ahc, SCSISEQ);
+			scsiseq &= ~ENSELI;
+			ahc_outb(ahc, SCSISEQ, scsiseq);
+
+			if ((ahc->features & AHC_MULTIROLE) == 0) {
+				printf("Configuring Initiator Mode\n");
+				ahc->flags &= ~AHC_TARGETROLE;
+				ahc->flags |= AHC_INITIATORROLE;
+				pause_sequencer(ahc);
+				ahc_loadseq(ahc);
+			}
+		}
+		unpause_sequencer(ahc);
+		ahc_unlock(ahc, &s);
+	}
+}
+
+static void
+ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask)
+{
+	u_int scsiid_mask;
+	u_int scsiid;
+
+	if ((ahc->features & AHC_MULTI_TID) == 0)
+		panic("ahc_update_scsiid called on non-multitid unit\n");
+
+	/*
+	 * Since we will rely on the the TARGID mask
+	 * for selection enables, ensure that OID
+	 * in SCSIID is not set to some other ID
+	 * that we don't want to allow selections on.
+	 */
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		scsiid = ahc_inb(ahc, SCSIID_ULTRA2);
+	else
+		scsiid = ahc_inb(ahc, SCSIID);
+	scsiid_mask = 0x1 << (scsiid & OID);
+	if ((targid_mask & scsiid_mask) == 0) {
+		u_int our_id;
+
+		/* ffs counts from 1 */
+		our_id = ffs(targid_mask);
+		if (our_id == 0)
+			our_id = ahc->our_id;
+		else
+			our_id--;
+		scsiid &= TID;
+		scsiid |= our_id;
+	}
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SCSIID_ULTRA2, scsiid);
+	else
+		ahc_outb(ahc, SCSIID, scsiid);
+}
+
+void
+ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
+{
+	struct target_cmd *cmd;
+
+	/*
+	 * If the card supports auto-access pause,
+	 * we can access the card directly regardless
+	 * of whether it is paused or not.
+	 */
+	if ((ahc->features & AHC_AUTOPAUSE) != 0)
+		paused = TRUE;
+
+	while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) {
+
+		/*
+		 * Only advance through the queue if we
+		 * have the resources to process the command.
+		 */
+		if (ahc_handle_target_cmd(ahc, cmd) != 0)
+			break;
+
+		ahc->tqinfifonext++;
+		cmd->cmd_valid = 0;
+
+		/*
+		 * Lazily update our position in the target mode incomming
+		 * command queue as seen by the sequencer.
+		 */
+		if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
+			if ((ahc->features & AHC_HS_MAILBOX) != 0) {
+				u_int hs_mailbox;
+
+				hs_mailbox = ahc_inb(ahc, HS_MAILBOX);
+				hs_mailbox &= ~HOST_TQINPOS;
+				hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS;
+				ahc_outb(ahc, HS_MAILBOX, hs_mailbox);
+			} else {
+				if (!paused)
+					pause_sequencer(ahc);	
+				ahc_outb(ahc, KERNEL_TQINPOS,
+					 ahc->tqinfifonext & HOST_TQINPOS);
+				if (!paused)
+					unpause_sequencer(ahc);
+			}
+		}
+	}
+}
+
+static int
+ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
+{
+	struct	  tmode_tstate *tstate;
+	struct	  tmode_lstate *lstate;
+	struct	  ccb_accept_tio *atio;
+	uint8_t *byte;
+	int	  initiator;
+	int	  target;
+	int	  lun;
+
+	initiator = SCSIID_TARGET(ahc, cmd->scsiid);
+	target = SCSIID_OUR_ID(cmd->scsiid);
+	lun    = (cmd->identify & MSG_IDENTIFY_LUNMASK);
+
+	byte = cmd->bytes;
+	tstate = ahc->enabled_targets[target];
+	lstate = NULL;
+	if (tstate != NULL)
+		lstate = tstate->enabled_luns[lun];
+
+	/*
+	 * Commands for disabled luns go to the black hole driver.
+	 */
+	if (lstate == NULL)
+		lstate = ahc->black_hole;
+
+	atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios);
+	if (atio == NULL) {
+		ahc->flags |= AHC_TQINFIFO_BLOCKED;
+		/*
+		 * Wait for more ATIOs from the peripheral driver for this lun.
+		 */
+		return (1);
+	} else
+		ahc->flags &= ~AHC_TQINFIFO_BLOCKED;
+#if 0
+	printf("Incoming command from %d for %d:%d%s\n",
+	       initiator, target, lun,
+	       lstate == ahc->black_hole ? "(Black Holed)" : "");
+#endif
+	SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
+
+	if (lstate == ahc->black_hole) {
+		/* Fill in the wildcards */
+		atio->ccb_h.target_id = target;
+		atio->ccb_h.target_lun = lun;
+	}
+
+	/*
+	 * Package it up and send it off to
+	 * whomever has this lun enabled.
+	 */
+	atio->sense_len = 0;
+	atio->init_id = initiator;
+	if (byte[0] != 0xFF) {
+		/* Tag was included */
+		atio->tag_action = *byte++;
+		atio->tag_id = *byte++;
+		atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
+	} else {
+		atio->ccb_h.flags = 0;
+	}
+	byte++;
+
+	/* Okay.  Now determine the cdb size based on the command code */
+	switch (*byte >> CMD_GROUP_CODE_SHIFT) {
+	case 0:
+		atio->cdb_len = 6;
+		break;
+	case 1:
+	case 2:
+		atio->cdb_len = 10;
+		break;
+	case 4:
+		atio->cdb_len = 16;
+		break;
+	case 5:
+		atio->cdb_len = 12;
+		break;
+	case 3:
+	default:
+		/* Only copy the opcode. */
+		atio->cdb_len = 1;
+		printf("Reserved or VU command code type encountered\n");
+		break;
+	}
+	
+	memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len);
+
+	atio->ccb_h.status |= CAM_CDB_RECVD;
+
+	if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) {
+		/*
+		 * We weren't allowed to disconnect.
+		 * We're hanging on the bus until a
+		 * continue target I/O comes in response
+		 * to this accept tio.
+		 */
+#if 0
+		printf("Received Immediate Command %d:%d:%d - %p\n",
+		       initiator, target, lun, ahc->pending_device);
+#endif
+		ahc->pending_device = lstate;
+		ahc_freeze_ccb((union ccb *)atio);
+		atio->ccb_h.flags |= CAM_DIS_DISCONNECT;
+	}
+	xpt_done((union ccb*)atio);
+	return (0);
+}
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,1202 @@
+/*
+ * Core definitions and data structures shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $
+ */
+
+#ifndef _AIC7XXX_H_
+#define _AIC7XXX_H_
+
+/* Register Definitions */
+#include "aic7xxx_reg.h"
+
+/************************* Forward Declarations *******************************/
+struct ahc_platform_data;
+struct scb_platform_data;
+
+/****************************** Useful Macros *********************************/
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array))
+
+#define ALL_CHANNELS '\0'
+#define ALL_TARGETS_MASK 0xFFFF
+#define INITIATOR_WILDCARD	(~0)
+
+#define SCSIID_TARGET(ahc, scsiid) \
+	(((scsiid) & ((((ahc)->features & AHC_TWIN) != 0) ? TWIN_TID : TID)) \
+	>> TID_SHIFT)
+#define SCSIID_OUR_ID(scsiid) \
+	((scsiid) & OID)
+#define SCSIID_CHANNEL(ahc, scsiid) \
+	((((ahc)->features & AHC_TWIN) != 0) \
+        ? ((((scsiid) & TWIN_CHNLB) != 0) ? 'B' : 'A') \
+       : 'A')
+#define	SCB_IS_SCSIBUS_B(ahc, scb) \
+	(SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) == 'B')
+#define	SCB_GET_OUR_ID(scb) \
+	SCSIID_OUR_ID((scb)->hscb->scsiid)
+#define	SCB_GET_TARGET(ahc, scb) \
+	SCSIID_TARGET((ahc), (scb)->hscb->scsiid)
+#define	SCB_GET_CHANNEL(ahc, scb) \
+	SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid)
+#define	SCB_GET_LUN(scb) \
+	((scb)->hscb->lun)
+#define SCB_GET_TARGET_OFFSET(ahc, scb)	\
+	(SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0))
+#define SCB_GET_TARGET_MASK(ahc, scb) \
+	(0x01 << (SCB_GET_TARGET_OFFSET(ahc, scb)))
+#define TCL_TARGET_OFFSET(tcl) \
+	((((tcl) >> 4) & TID) >> 4)
+#define TCL_LUN(tcl) \
+	(tcl & (AHC_NUM_LUNS - 1))
+#define BUILD_TCL(scsiid, lun) \
+	((lun) | (((scsiid) & TID) << 4))
+
+#ifndef	AHC_TARGET_MODE
+#undef	AHC_TMODE_ENABLE
+#define	AHC_TMODE_ENABLE 0
+#endif
+
+/**************************** Driver Constants ********************************/
+/*
+ * The maximum number of supported targets.
+ */
+#define AHC_NUM_TARGETS 16
+
+/*
+ * The maximum number of supported luns.
+ * The identify message only supports 64 luns in SPI3.
+ * You can have 2^64 luns when information unit transfers are enabled,
+ * but it is doubtful this driver will ever support IUTs.
+ */
+#define AHC_NUM_LUNS 64
+
+/*
+ * The maximum transfer per S/G segment.
+ */
+#define AHC_MAXTRANSFER_SIZE	 0x00ffffff	/* limited by 24bit counter */
+
+/*
+ * The maximum amount of SCB storage in hardware on a controller.
+ * This value represents an upper bound.  Controllers vary in the number
+ * they actually support.
+ */
+#define AHC_SCB_MAX	255
+
+/*
+ * The maximum number of concurrent transactions supported per driver instance.
+ * Sequencer Control Blocks (SCBs) store per-transaction information.  Although
+ * the space for SCBs on the host adapter varies by model, the driver will
+ * page the SCBs between host and controller memory as needed.  We are limited
+ * to 253 because:
+ * 	1) The 8bit nature of the RISC engine holds us to an 8bit value.
+ * 	2) We reserve one value, 255, to represent the invalid element.
+ *	3) Our input queue scheme requires one SCB to always be reserved
+ *	   in advance of queuing any SCBs.  This takes us down to 254.
+ *	4) To handle our output queue correctly on machines that only
+ * 	   support 32bit stores, we must clear the array 4 bytes at a
+ *	   time.  To avoid colliding with a DMA write from the sequencer,
+ *	   we must be sure that 4 slots are empty when we write to clear
+ *	   the queue.  This reduces us to 253 SCBs: 1 that just completed
+ *	   and the known three additional empty slots in the queue that
+ *	   preceed it.
+ */
+#define AHC_MAX_QUEUE	253
+
+/*
+ * Ring Buffer of incoming target commands.
+ * We allocate 256 to simplify the logic in the sequencer
+ * by using the natural wrap point of an 8bit counter.
+ */
+#define AHC_TMODE_CMDS	256
+
+/* Reset line assertion time in us */
+#define AHC_BUSRESET_DELAY	250
+
+/******************* Chip Characteristics/Operating Settings  *****************/
+/*
+ * Chip Type
+ * The chip order is from least sophisticated to most sophisticated.
+ */
+typedef enum {
+	AHC_NONE	= 0x0000,
+	AHC_CHIPID_MASK	= 0x00FF,
+	AHC_AIC7770	= 0x0001,
+	AHC_AIC7850	= 0x0002,
+	AHC_AIC7855	= 0x0003,
+	AHC_AIC7859	= 0x0004,
+	AHC_AIC7860	= 0x0005,
+	AHC_AIC7870	= 0x0006,
+	AHC_AIC7880	= 0x0007,
+	AHC_AIC7895	= 0x0008,
+	AHC_AIC7895C	= 0x0009,
+	AHC_AIC7890	= 0x000a,
+	AHC_AIC7896	= 0x000b,
+	AHC_AIC7892	= 0x000c,
+	AHC_AIC7899	= 0x000d,
+	AHC_VL		= 0x0100,	/* Bus type VL */
+	AHC_EISA	= 0x0200,	/* Bus type EISA */
+	AHC_PCI		= 0x0400,	/* Bus type PCI */
+	AHC_BUS_MASK	= 0x0F00
+} ahc_chip;
+
+/*
+ * Features available in each chip type.
+ */
+typedef enum {
+	AHC_FENONE	= 0x00000,
+	AHC_ULTRA	= 0x00001,	/* Supports 20MHz Transfers */
+	AHC_ULTRA2	= 0x00002,	/* Supports 40MHz Transfers */
+	AHC_WIDE  	= 0x00004,	/* Wide Channel */
+	AHC_TWIN	= 0x00008,	/* Twin Channel */
+	AHC_MORE_SRAM	= 0x00010,	/* 80 bytes instead of 64 */
+	AHC_CMD_CHAN	= 0x00020,	/* Has a Command DMA Channel */
+	AHC_QUEUE_REGS	= 0x00040,	/* Has Queue management registers */
+	AHC_SG_PRELOAD	= 0x00080,	/* Can perform auto-SG preload */
+	AHC_SPIOCAP	= 0x00100,	/* Has a Serial Port I/O Cap Register */
+	AHC_MULTI_TID	= 0x00200,	/* Has bitmask of TIDs for select-in */
+	AHC_HS_MAILBOX	= 0x00400,	/* Has HS_MAILBOX register */
+	AHC_DT		= 0x00800,	/* Double Transition transfers */
+	AHC_NEW_TERMCTL	= 0x01000,	/* Newer termination scheme */
+	AHC_MULTI_FUNC	= 0x02000,	/* Multi-Function Twin Channel Device */
+	AHC_LARGE_SCBS	= 0x04000,	/* 64byte SCBs */
+	AHC_AUTORATE	= 0x08000,	/* Automatic update of SCSIRATE/OFFSET*/
+	AHC_AUTOPAUSE	= 0x10000,	/* Automatic pause on register access */
+	AHC_TARGETMODE	= 0x20000,	/* Has tested target mode support */
+	AHC_MULTIROLE	= 0x40000,	/* Space for two roles at a time */
+	AHC_REMOVABLE	= 0x80000,	/* Hot-Swap supported */
+	AHC_AIC7770_FE	= AHC_FENONE,
+	AHC_AIC7850_FE	= AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE,
+	AHC_AIC7855_FE	= AHC_AIC7850_FE,
+	AHC_AIC7860_FE	= AHC_AIC7850_FE|AHC_ULTRA,
+	AHC_AIC7870_FE	= AHC_TARGETMODE,
+	AHC_AIC7880_FE	= AHC_AIC7870_FE|AHC_ULTRA,
+	/*
+	 * Although we have space for both the initiator and
+	 * target roles on ULTRA2 chips, we currently disable
+	 * the initiator role to allow multi-scsi-id target mode
+	 * configurations.  We can only respond on the same SCSI
+	 * ID as our initiator role if we allow initiator operation.
+	 * At some point, we should add a configuration knob to
+	 * allow both roles to be loaded.
+	 */
+	AHC_AIC7890_FE	= AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2
+			  |AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID
+			  |AHC_HS_MAILBOX|AHC_NEW_TERMCTL|AHC_LARGE_SCBS
+			  |AHC_TARGETMODE,
+	AHC_AIC7892_FE	= AHC_AIC7890_FE|AHC_DT|AHC_AUTORATE|AHC_AUTOPAUSE,
+	AHC_AIC7895_FE	= AHC_AIC7880_FE|AHC_MORE_SRAM|AHC_AUTOPAUSE
+			  |AHC_CMD_CHAN|AHC_MULTI_FUNC|AHC_LARGE_SCBS,
+	AHC_AIC7895C_FE	= AHC_AIC7895_FE|AHC_MULTI_TID,
+	AHC_AIC7896_FE	= AHC_AIC7890_FE|AHC_MULTI_FUNC,
+	AHC_AIC7899_FE	= AHC_AIC7892_FE|AHC_MULTI_FUNC
+} ahc_feature;
+
+/*
+ * Bugs in the silicon that we work around in software.
+ */
+typedef enum {
+	AHC_BUGNONE		= 0x00,
+	/*
+	 * On all chips prior to the U2 product line,
+	 * the WIDEODD S/G segment feature does not
+	 * work during scsi->HostBus transfers.
+	 */
+	AHC_TMODE_WIDEODD_BUG	= 0x01,
+	/*
+	 * On the aic7890/91 Rev 0 chips, the autoflush
+	 * feature does not work.  A manual flush of
+	 * the DMA FIFO is required.
+	 */
+	AHC_AUTOFLUSH_BUG	= 0x02,
+	/*
+	 * On many chips, cacheline streaming does not work.
+	 */
+	AHC_CACHETHEN_BUG	= 0x04,
+	/*
+	 * On the aic7896/97 chips, cacheline
+	 * streaming must be enabled.
+	 */
+	AHC_CACHETHEN_DIS_BUG	= 0x08,
+	/*
+	 * PCI 2.1 Retry failure on non-empty data fifo.
+	 */
+	AHC_PCI_2_1_RETRY_BUG	= 0x10,
+	/*
+	 * Controller does not handle cacheline residuals
+	 * properly on S/G segments if PCI MWI instructions
+	 * are allowed.
+	 */
+	AHC_PCI_MWI_BUG		= 0x20,
+	/*
+	 * An SCB upload using the SCB channel's
+	 * auto array entry copy feature may 
+	 * corrupt data.  This appears to only
+	 * occur on 66MHz systems.
+	 */
+	AHC_SCBCHAN_UPLOAD_BUG	= 0x40
+} ahc_bug;
+
+/*
+ * Configuration specific settings.
+ * The driver determines these settings by probing the
+ * chip/controller's configuration.
+ */
+typedef enum {
+	AHC_FNONE		= 0x000,
+	AHC_PAGESCBS		= 0x001,/* Enable SCB paging */
+	AHC_CHANNEL_B_PRIMARY	= 0x002,/*
+					 * On twin channel adapters, probe
+					 * channel B first since it is the
+					 * primary bus.
+					 */
+	AHC_USEDEFAULTS		= 0x004,/*
+					 * For cards without an seeprom
+					 * or a BIOS to initialize the chip's
+					 * SRAM, we use the default target
+					 * settings.
+					 */
+	AHC_SEQUENCER_DEBUG	= 0x008,
+	AHC_SHARED_SRAM		= 0x010,
+	AHC_LARGE_SEEPROM	= 0x020,/* Uses C56_66 not C46 */
+	AHC_RESET_BUS_A		= 0x040,
+	AHC_RESET_BUS_B		= 0x080,
+	AHC_EXTENDED_TRANS_A	= 0x100,
+	AHC_EXTENDED_TRANS_B	= 0x200,
+	AHC_TERM_ENB_A		= 0x400,
+	AHC_TERM_ENB_B		= 0x800,
+	AHC_INITIATORROLE	= 0x1000,/*
+					  * Allow initiator operations on
+					  * this controller.
+					  */
+	AHC_TARGETROLE		= 0x2000,/*
+					  * Allow target operations on this
+					  * controller.
+					  */
+	AHC_NEWEEPROM_FMT	= 0x4000,
+	AHC_RESOURCE_SHORTAGE	= 0x8000,
+	AHC_TQINFIFO_BLOCKED	= 0x10000,/* Blocked waiting for ATIOs */
+	AHC_INT50_SPEEDFLEX	= 0x20000,/*
+					   * Internal 50pin connector
+					   * sits behind an aic3860
+					   */
+	AHC_SCB_BTT		= 0x40000,/*
+					   * The busy targets table is
+					   * stored in SCB space rather
+					   * than SRAM.
+					   */
+	AHC_BIOS_ENABLED	= 0x80000,
+	AHC_ALL_INTERRUPTS	= 0x100000,
+	AHC_ULTRA_DISABLED	= 0x200000/*
+					   * The precision resistor for
+					   * ultra transmission speeds is
+					   * missing, so we must limit
+					   * ourselves to fast SCSI.
+					   */
+} ahc_flag;
+
+/*
+ * Controller  Information composed at probe time.
+ */
+struct ahc_probe_config {
+	const char	*description;
+	char		 channel;
+	char		 channel_b;
+	ahc_chip	 chip;
+	ahc_feature	 features;
+	ahc_bug		 bugs;
+	ahc_flag	 flags;
+};
+
+/************************* Hardware  SCB Definition ***************************/
+
+/*
+ * The driver keeps up to MAX_SCB scb structures per card in memory.  The SCB
+ * consists of a "hardware SCB" mirroring the fields availible on the card
+ * and additional information the kernel stores for each transaction.
+ *
+ * To minimize space utilization, a portion of the hardware scb stores
+ * different data during different portions of a SCSI transaction.
+ * As initialized by the host driver for the initiator role, this area
+ * contains the SCSI cdb (or a pointer to the  cdb) to be executed.  After
+ * the cdb has been presented to the target, this area serves to store
+ * residual transfer information and the SCSI status byte.
+ * For the target role, the contents of this area do not change, but
+ * still serve a different purpose than for the initiator role.  See
+ * struct target_data for details.
+ */
+
+/*
+ * Status information embedded in the shared poriton of
+ * an SCB after passing the cdb to the target.  The kernel
+ * driver will only read this data for transactions that
+ * complete abnormally (non-zero status byte).
+ */
+struct status_pkt {
+	uint32_t residual_datacnt;	/* Residual in the current S/G seg */
+	uint32_t residual_sg_ptr;	/* The next S/G for this transfer */
+	uint8_t	 scsi_status;		/* Standard SCSI status byte */
+};
+
+/*
+ * Target mode version of the shared data SCB segment.
+ */
+struct target_data {
+	uint8_t	target_phases;		/* Bitmap of phases to execute */
+	uint8_t	data_phase;		/* Data-In or Data-Out */
+	uint8_t	scsi_status;		/* SCSI status to give to initiator */
+	uint8_t	initiator_tag;		/* Initiator's transaction tag */
+};
+
+struct hardware_scb {
+/*0*/	union {
+		/*
+		 * If the cdb is 12 bytes or less, we embed it directly
+		 * in the SCB.  For longer cdbs, we embed the address
+		 * of the cdb payload as seen by the chip and a DMA
+		 * is used to pull it in.
+		 */
+		uint8_t	cdb[12];
+		uint32_t	cdb_ptr;
+		struct		status_pkt status;
+		struct		target_data tdata;
+	} shared_data;
+/*
+ * A word about residuals.
+ * The scb is presented to the sequencer with the dataptr and datacnt
+ * fields initialized to the contents of the first S/G element to
+ * transfer.  The sgptr field is initialized to the bus address for
+ * the S/G element that follows the first in the in core S/G array
+ * or'ed with the SG_FULL_RESID flag.  Sgptr may point to an invalid
+ * S/G entry for this transfer (single S/G element transfer with the
+ * first elements address and length preloaded in the dataptr/datacnt
+ * fields).  If no transfer is to occur, sgptr is set to SG_LIST_NULL.
+ * The SG_FULL_RESID flag ensures that the residual will be correctly
+ * noted even if no data transfers occur.  Once the data phase is entered,
+ * the residual sgptr and datacnt are loaded from the sgptr and the
+ * datacnt fields.  After each S/G element's dataptr and length are
+ * loaded into the hardware, the residual sgptr is advanced.  After
+ * each S/G element is expired, its datacnt field is checked to see
+ * if the LAST_SEG flag is set.  If so, SG_LIST_NULL is set in the
+ * residual sg ptr and the transfer is considered complete.  If the
+ * sequencer determines that there is a residual in the tranfer, it
+ * will set the SG_RESID_VALID flag in sgptr and dma the scb back into
+ * host memory.  To sumarize:
+ *
+ * Sequencer:
+ *	o A residual has occurred if SG_FULL_RESID is set in sgptr,
+ *	  or residual_sgptr does not have SG_LIST_NULL set.
+ *
+ *	o We are transfering the last segment if residual_datacnt has
+ *	  the SG_LAST_SEG flag set.
+ *
+ * Host:
+ *	o A residual has occurred if a completed scb has the
+ *	  SG_RESID_VALID flag set.
+ *
+ *	o residual_sgptr and sgptr refer to the "next" sg entry
+ *	  and so may point beyond the last valid sg entry for the
+ *	  transfer.
+ */ 
+/*12*/	uint32_t dataptr;
+/*16*/	uint32_t datacnt;		/*
+					 * Byte 3 (numbered from 0) of
+					 * the datacnt is really the
+					 * 4th byte in that data address.
+					 */
+/*20*/	uint32_t sgptr;
+#define SG_PTR_MASK	0xFFFFFFF8
+/*24*/	uint8_t  control;	/* See SCB_CONTROL in aic7xxx.reg for details */
+/*25*/	uint8_t  scsiid;	/* what to load in the SCSIID register */
+/*26*/	uint8_t  lun;
+/*27*/	uint8_t  tag;			/*
+					 * Index into our kernel SCB array.
+					 * Also used as the tag for tagged I/O
+					 */
+/*28*/	uint8_t  cdb_len;
+/*29*/	uint8_t  scsirate;		/* Value for SCSIRATE register */
+/*30*/	uint8_t  scsioffset;		/* Value for SCSIOFFSET register */
+/*31*/	uint8_t  next;			/*
+					 * Used for threading SCBs in the
+					 * "Waiting for Selection" and
+					 * "Disconnected SCB" lists down
+					 * in the sequencer.
+					 */
+/*32*/	uint8_t  cdb32[32];		/*
+					 * CDB storage for cdbs of size
+					 * 13->32.  We store them here
+					 * because hardware scbs are
+					 * allocated from DMA safe
+					 * memory so we are guaranteed
+					 * the controller can access
+					 * this data.
+					 */
+};
+
+/************************ Kernel SCB Definitions ******************************/
+/*
+ * Some fields of the SCB are OS dependent.  Here we collect the
+ * definitions for elements that all OS platforms need to include
+ * in there SCB definition.
+ */
+
+/*
+ * Definition of a scatter/gather element as transfered to the controller.
+ * The aic7xxx chips only support a 24bit length.  We use the top byte of
+ * the length to store additional address bits and a flag to indicate
+ * that a given segment terminates the transfer.  This gives us an
+ * addressable range of 512GB on machines with 64bit PCI or with chips
+ * that can support dual address cycles on 32bit PCI busses.
+ */
+struct ahc_dma_seg {
+	uint32_t	addr;
+	uint32_t	len;
+#define	AHC_DMA_LAST_SEG	0x80000000
+#define	AHC_SG_HIGH_ADDR_MASK	0x7F000000
+#define	AHC_SG_LEN_MASK		0x00FFFFFF
+};
+
+/*
+ * The current state of this SCB.
+ */
+typedef enum {
+	SCB_FREE		= 0x0000,
+	SCB_OTHERTCL_TIMEOUT	= 0x0002,/*
+					  * Another device was active
+					  * during the first timeout for
+					  * this SCB so we gave ourselves
+					  * an additional timeout period
+					  * in case it was hogging the
+					  * bus.
+				          */
+	SCB_DEVICE_RESET	= 0x0004,
+	SCB_SENSE		= 0x0008,
+	SCB_CDB32_PTR		= 0x0010,
+	SCB_RECOVERY_SCB	= 0x0040,
+	SCB_NEGOTIATE		= 0x0080,
+	SCB_ABORT		= 0x1000,
+	SCB_UNTAGGEDQ		= 0x2000,
+	SCB_ACTIVE		= 0x4000,
+	SCB_TARGET_IMMEDIATE	= 0x8000
+} scb_flag;
+
+struct scb {
+	struct	hardware_scb	 *hscb;
+	union {
+		SLIST_ENTRY(scb)  sle;
+		TAILQ_ENTRY(scb)  tqe;
+	} links;
+	LIST_ENTRY(scb)		  pending_links;
+	ahc_io_ctx_t		  io_ctx;
+	struct ahc_softc	 *ahc_softc;
+	scb_flag		  flags;
+#ifndef __linux__
+	bus_dmamap_t		  dmamap;
+#endif
+	struct scb_platform_data *platform_data;
+	struct	ahc_dma_seg 	 *sg_list;
+	bus_addr_t		  sg_list_phys;
+	u_int			  sg_count;/* How full ahc_dma_seg is */
+};
+
+struct sg_map_node {
+	bus_dmamap_t		 sg_dmamap;
+	bus_addr_t		 sg_physaddr;
+	struct ahc_dma_seg*	 sg_vaddr;
+	SLIST_ENTRY(sg_map_node) links;
+};
+
+struct scb_data {
+	SLIST_HEAD(, scb) free_scbs;	/*
+					 * Pool of SCBs ready to be assigned
+					 * commands to execute.
+					 */
+	struct	scb *scbindex[AHC_SCB_MAX + 1];/* Mapping from tag to SCB */
+	struct	hardware_scb	*hscbs;	/* Array of hardware SCBs */
+	struct	scb *scbarray;		/* Array of kernel SCBs */
+	struct	scsi_sense_data *sense; /* Per SCB sense data */
+
+	/*
+	 * "Bus" addresses of our data structures.
+	 */
+	bus_dma_tag_t	 hscb_dmat;	/* dmat for our hardware SCB array */
+	bus_dmamap_t	 hscb_dmamap;
+	bus_addr_t	 hscb_busaddr;
+	bus_dma_tag_t	 sense_dmat;
+	bus_dmamap_t	 sense_dmamap;
+	bus_addr_t	 sense_busaddr;
+	bus_dma_tag_t	 sg_dmat;	/* dmat for our sg segments */
+	SLIST_HEAD(, sg_map_node) sg_maps;
+	uint8_t	numscbs;
+	uint8_t	maxhscbs;		/* Number of SCBs on the card */
+	uint8_t	init_level;		/*
+					 * How far we've initialized
+					 * this structure.
+					 */
+};
+
+/************************ Target Mode Definitions *****************************/
+
+/*
+ * Connection desciptor for select-in requests in target mode.
+ */
+struct target_cmd {
+	uint8_t scsiid;		/* Our ID and the initiator's ID */
+	uint8_t identify;	/* Identify message */
+	uint8_t bytes[22];	/* 
+				 * Bytes contains any additional message
+				 * bytes terminated by 0xFF.  The remainder
+				 * is the cdb to execute.
+				 */
+	uint8_t cmd_valid;	/*
+				 * When a command is complete, the firmware
+				 * will set cmd_valid to all bits set.
+				 * After the host has seen the command,
+				 * the bits are cleared.  This allows us
+				 * to just peek at host memory to determine
+				 * if more work is complete. cmd_valid is on
+				 * an 8 byte boundary to simplify setting
+				 * it on aic7880 hardware which only has
+				 * limited direct access to the DMA FIFO.
+				 */
+	uint8_t pad[7];
+};
+
+/*
+ * Number of events we can buffer up if we run out
+ * of immediate notify ccbs.
+ */
+#define AHC_TMODE_EVENT_BUFFER_SIZE 8
+struct ahc_tmode_event {
+	uint8_t initiator_id;
+	uint8_t event_type;	/* MSG type or EVENT_TYPE_BUS_RESET */
+#define	EVENT_TYPE_BUS_RESET 0xFF
+	uint8_t event_arg;
+};
+
+/*
+ * Per enabled lun target mode state.
+ * As this state is directly influenced by the host OS'es target mode
+ * environment, we let the OS module define it.  Forward declare the
+ * structure here so we can store arrays of them, etc. in OS neutral
+ * data structures.
+ */
+#ifdef AHC_TARGET_MODE 
+struct tmode_lstate {
+	struct cam_path *path;
+	struct ccb_hdr_slist accept_tios;
+	struct ccb_hdr_slist immed_notifies;
+	struct ahc_tmode_event event_buffer[AHC_TMODE_EVENT_BUFFER_SIZE];
+	uint8_t event_r_idx;
+	uint8_t event_w_idx;
+};
+#else
+struct tmode_lstate;
+#endif
+
+/******************** Transfer Negotiation Datastructures *********************/
+#define AHC_TRANS_CUR		0x01	/* Modify current neogtiation status */
+#define AHC_TRANS_ACTIVE	0x03	/* Assume this target is on the bus */
+#define AHC_TRANS_GOAL		0x04	/* Modify negotiation goal */
+#define AHC_TRANS_USER		0x08	/* Modify user negotiation settings */
+
+/*
+ * Transfer Negotiation Information.
+ */
+struct ahc_transinfo {
+	uint8_t protocol_version;	/* SCSI Revision level */
+	uint8_t transport_version;	/* SPI Revision level */
+	uint8_t width;			/* Bus width */
+	uint8_t period;			/* Sync rate factor */
+	uint8_t offset;			/* Sync offset */
+	uint8_t ppr_options;		/* Parallel Protocol Request options */
+};
+
+/*
+ * Per-initiator current, goal and user transfer negotiation information. */
+struct ahc_initiator_tinfo {
+	uint8_t scsirate;		/* Computed value for SCSIRATE reg */
+	struct ahc_transinfo current;
+	struct ahc_transinfo goal;
+	struct ahc_transinfo user;
+};
+
+/*
+ * Per enabled target ID state.
+ * Pointers to lun target state as well as sync/wide negotiation information
+ * for each initiator<->target mapping.  For the initiator role we pretend
+ * that we are the target and the targets are the initiators since the
+ * negotiation is the same regardless of role.
+ */
+struct tmode_tstate {
+	struct tmode_lstate*		enabled_luns[AHC_NUM_LUNS];
+	struct ahc_initiator_tinfo	transinfo[AHC_NUM_TARGETS];
+
+	/*
+	 * Per initiator state bitmasks.
+	 */
+	uint16_t		 ultraenb;	/* Using ultra sync rate  */
+	uint16_t	 	 discenable;	/* Disconnection allowed  */
+	uint16_t		 tagenable;	/* Tagged Queuing allowed */
+};
+
+/*
+ * Data structure for our table of allowed synchronous transfer rates.
+ */
+struct ahc_syncrate {
+	u_int sxfr_u2;	/* Value of the SXFR parameter for Ultra2+ Chips */
+	u_int sxfr;	/* Value of the SXFR parameter for <= Ultra Chips */
+#define		ULTRA_SXFR 0x100	/* Rate Requires Ultra Mode set */
+#define		ST_SXFR	   0x010	/* Rate Single Transition Only */
+#define		DT_SXFR	   0x040	/* Rate Double Transition Only */
+	uint8_t period; /* Period to send to SCSI target */
+	char *rate;
+};
+
+/*
+ * The synchronouse transfer rate table.
+ */
+extern struct ahc_syncrate ahc_syncrates[];
+
+/*
+ * Indexes into our table of syncronous transfer rates.
+ */
+#define AHC_SYNCRATE_DT		0
+#define AHC_SYNCRATE_ULTRA2	1
+#define AHC_SYNCRATE_ULTRA	3
+#define AHC_SYNCRATE_FAST	6
+
+/***************************** Lookup Tables **********************************/
+/*
+ * Textual descriptions of the different chips indexed by chip type.
+ */
+extern char *ahc_chip_names[];
+extern const u_int num_chip_names;
+
+/*
+ * Hardware error codes.
+ */
+struct hard_error_entry {
+        uint8_t errno;
+	char *errmesg;
+};
+extern struct hard_error_entry hard_error[];
+extern const u_int num_errors;
+
+/*
+ * Phase -> name and message out response
+ * to parity errors in each phase table. 
+ */
+struct phase_table_entry {
+        uint8_t phase;
+        uint8_t mesg_out; /* Message response to parity errors */
+	char *phasemsg;
+};
+extern struct phase_table_entry phase_table[];
+extern const u_int num_phases;
+
+/************************** Serial EEPROM Format ******************************/
+
+struct seeprom_config {
+/*
+ * Per SCSI ID Configuration Flags
+ */
+	uint16_t device_flags[16];	/* words 0-15 */
+#define		CFXFER		0x0007	/* synchronous transfer rate */
+#define		CFSYNCH		0x0008	/* enable synchronous transfer */
+#define		CFDISC		0x0010	/* enable disconnection */
+#define		CFWIDEB		0x0020	/* wide bus device */
+#define		CFSYNCHISULTRA	0x0040	/* CFSYNCH is an ultra offset (2940AU)*/
+#define		CFSYNCSINGLE	0x0080	/* Single-Transition signalling */
+#define		CFSTART		0x0100	/* send start unit SCSI command */
+#define		CFINCBIOS	0x0200	/* include in BIOS scan */
+#define		CFRNFOUND	0x0400	/* report even if not found */
+#define		CFMULTILUNDEV	0x0800	/* Probe multiple luns in BIOS scan */
+#define		CFWBCACHEENB	0x4000	/* Enable W-Behind Cache on disks */
+#define		CFWBCACHENOP	0xc000	/* Don't touch W-Behind Cache */
+
+/*
+ * BIOS Control Bits
+ */
+	uint16_t bios_control;		/* word 16 */
+#define		CFSUPREM	0x0001	/* support all removeable drives */
+#define		CFSUPREMB	0x0002	/* support removeable boot drives */
+#define		CFBIOSEN	0x0004	/* BIOS enabled */
+/*		UNUSED		0x0008	*/
+#define		CFSM2DRV	0x0010	/* support more than two drives */
+#define		CF284XEXTEND	0x0020	/* extended translation (284x cards) */	
+#define		CFSTPWLEVEL	0x0010	/* Termination level control */
+#define		CFEXTEND	0x0080	/* extended translation enabled */
+#define		CFSCAMEN	0x0100	/* SCAM enable */
+/*		UNUSED		0xff00	*/
+
+/*
+ * Host Adapter Control Bits
+ */
+	uint16_t adapter_control;	/* word 17 */	
+#define		CFAUTOTERM	0x0001	/* Perform Auto termination */
+#define		CFULTRAEN	0x0002	/* Ultra SCSI speed enable */
+#define		CF284XSELTO     0x0003	/* Selection timeout (284x cards) */
+#define		CF284XFIFO      0x000C	/* FIFO Threshold (284x cards) */
+#define		CFSTERM		0x0004	/* SCSI low byte termination */
+#define		CFWSTERM	0x0008	/* SCSI high byte termination */
+#define		CFSPARITY	0x0010	/* SCSI parity */
+#define		CF284XSTERM     0x0020	/* SCSI low byte term (284x cards) */	
+#define		CFMULTILUN	0x0020	/* SCSI low byte term (284x cards) */	
+#define		CFRESETB	0x0040	/* reset SCSI bus at boot */
+#define		CFCLUSTERENB	0x0080	/* Cluster Enable */
+#define		CFCHNLBPRIMARY	0x0100	/* aic7895 probe B channel first */
+#define		CFSEAUTOTERM	0x0400	/* Ultra2 Perform secondary Auto Term*/
+#define		CFSELOWTERM	0x0800	/* Ultra2 secondary low term */
+#define		CFSEHIGHTERM	0x1000	/* Ultra2 secondary high term */
+#define		CFDOMAINVAL	0x4000	/* Perform Domain Validation*/
+
+/*
+ * Bus Release Time, Host Adapter ID
+ */
+	uint16_t brtime_id;		/* word 18 */
+#define		CFSCSIID	0x000f	/* host adapter SCSI ID */
+/*		UNUSED		0x00f0	*/
+#define		CFBRTIME	0xff00	/* bus release time */
+
+/*
+ * Maximum targets
+ */
+	uint16_t max_targets;		/* word 19 */	
+#define		CFMAXTARG	0x00ff	/* maximum targets */
+#define		CFBOOTLUN	0x0f00	/* Lun to boot from */
+#define		CFBOOTID	0xf000	/* Target to boot from */
+	uint16_t res_1[10];		/* words 20-29 */
+	uint16_t signature;		/* Signature == 0x250 */
+#define		CFSIGNATURE	0x250
+	uint16_t checksum;		/* word 31 */
+};
+
+/****************************  Message Buffer *********************************/
+typedef enum {
+	MSG_TYPE_NONE			= 0x00,
+	MSG_TYPE_INITIATOR_MSGOUT	= 0x01,
+	MSG_TYPE_INITIATOR_MSGIN	= 0x02,
+	MSG_TYPE_TARGET_MSGOUT		= 0x03,
+	MSG_TYPE_TARGET_MSGIN		= 0x04
+} ahc_msg_type;
+
+typedef enum {
+	MSGLOOP_IN_PROG,
+	MSGLOOP_MSGCOMPLETE,
+	MSGLOOP_TERMINATED
+} msg_loop_stat;
+
+/*********************** Software Configuration Structure *********************/
+TAILQ_HEAD(scb_tailq, scb);
+
+struct ahc_suspend_channel_state {
+	uint8_t	scsiseq;
+	uint8_t	sxfrctl0;
+	uint8_t	sxfrctl1;
+	uint8_t	simode0;
+	uint8_t	simode1;
+	uint8_t	seltimer;
+	uint8_t	seqctl;
+};
+
+struct ahc_suspend_state {
+	struct	ahc_suspend_channel_state channel[2];
+	uint8_t	optionmode;
+	uint8_t	dscommand0;
+	uint8_t	dspcistatus;
+	/* hsmailbox */
+	uint8_t	crccontrol1;
+	uint8_t	scbbaddr;
+	/* Host and sequencer SCB counts */
+	uint8_t	dff_thrsh;
+	uint8_t	*scratch_ram;
+	uint8_t	*btt;
+};
+
+struct ahc_softc {
+	bus_space_tag_t           tag;
+	bus_space_handle_t        bsh;
+#ifndef __linux__
+	bus_dma_tag_t		  buffer_dmat;   /* dmat for buffer I/O */
+#endif
+	struct scb_data		 *scb_data;
+
+	struct scb		 *next_queued_scb;
+
+	/*
+	 * SCBs that have been sent to the controller
+	 */
+	LIST_HEAD(, scb)	 pending_scbs;
+
+	/*
+	 * Counting lock for deferring the release of additional
+	 * untagged transactions from the untagged_queues.  When
+	 * the lock is decremented to 0, all queues in the
+	 * untagged_queues array are run.
+	 */
+	u_int			  untagged_queue_lock;
+
+	/*
+	 * Per-target queue of untagged-transactions.  The
+	 * transaction at the head of the queue is the
+	 * currently pending untagged transaction for the
+	 * target.  The driver only allows a single untagged
+	 * transaction per target.
+	 */
+	struct scb_tailq	  untagged_queues[AHC_NUM_TARGETS];
+
+	/*
+	 * Platform specific data.
+	 */
+	struct ahc_platform_data *platform_data;
+
+	/*
+	 * Platform specific device information.
+	 */
+	ahc_dev_softc_t		  dev_softc;
+
+	/*
+	 * Target mode related state kept on a per enabled lun basis.
+	 * Targets that are not enabled will have null entries.
+	 * As an initiator, we keep one target entry for our initiator
+	 * ID to store our sync/wide transfer settings.
+	 */
+	struct tmode_tstate*	  enabled_targets[AHC_NUM_TARGETS];
+
+	/*
+	 * The black hole device responsible for handling requests for
+	 * disabled luns on enabled targets.
+	 */
+	struct tmode_lstate*	  black_hole;
+
+	/*
+	 * Device instance currently on the bus awaiting a continue TIO
+	 * for a command that was not given the disconnect priveledge.
+	 */
+	struct tmode_lstate*	  pending_device;
+
+	/*
+	 * Card characteristics
+	 */
+	ahc_chip		  chip;
+	ahc_feature		  features;
+	ahc_bug			  bugs;
+	ahc_flag		  flags;
+
+	/* Values to store in the SEQCTL register for pause and unpause */
+	uint8_t			  unpause;
+	uint8_t			  pause;
+
+	/* Command Queues */
+	uint8_t			  qoutfifonext;
+	uint8_t			  qinfifonext;
+	uint8_t			 *qoutfifo;
+	uint8_t			 *qinfifo;
+
+	/* Critical Section Data */
+	struct cs		 *critical_sections;
+	u_int			  num_critical_sections;
+
+	/* Links for chaining softcs */
+	TAILQ_ENTRY(ahc_softc)	  links;
+
+	/* Channel Names ('A', 'B', etc.) */
+	char			  channel;
+	char			  channel_b;
+
+	/* Initiator Bus ID */
+	uint8_t			  our_id;
+	uint8_t			  our_id_b;
+
+	/* Targets that need negotiation messages */
+	uint16_t		  targ_msg_req;
+
+	/*
+	 * PCI error detection.
+	 */
+	int			  unsolicited_ints;
+
+	/*
+	 * Target incoming command FIFO.
+	 */
+	struct target_cmd	 *targetcmds;
+	uint8_t			  tqinfifonext;
+
+	/*
+	 * Incoming and outgoing message handling.
+	 */
+	uint8_t			  send_msg_perror;
+	ahc_msg_type		  msg_type;
+	uint8_t			  msgout_buf[12];/* Message we are sending */
+	uint8_t			  msgin_buf[12];/* Message we are receiving */
+	u_int			  msgout_len;	/* Length of message to send */
+	u_int			  msgout_index;	/* Current index in msgout */
+	u_int			  msgin_index;	/* Current index in msgin */
+
+	/*
+	 * Mapping information for data structures shared
+	 * between the sequencer and kernel.
+	 */
+	bus_dma_tag_t		  parent_dmat;
+	bus_dma_tag_t		  shared_data_dmat;
+	bus_dmamap_t		  shared_data_dmamap;
+	bus_addr_t		  shared_data_busaddr;
+
+	/*
+	 * Bus address of the one byte buffer used to
+	 * work-around a DMA bug for chips <= aic7880
+	 * in target mode.
+	 */
+	bus_addr_t		  dma_bug_buf;
+
+	/* Information saved through suspend/resume cycles */
+	struct ahc_suspend_state  suspend_state;
+
+	/* Number of enabled target mode device on this card */
+	u_int			  enabled_luns;
+
+	/* Initialization level of this data structure */
+	u_int			  init_level;
+
+	/* PCI cacheline size. */
+	u_int			  pci_cachesize;
+
+	/* Per-Unit descriptive information */
+	const char		 *description;
+	char			 *name;
+	int			  unit;
+
+	/* Selection Timer settings */
+	int			  seltime;
+	int			  seltime_b;
+
+	uint16_t	 	  user_discenable;/* Disconnection allowed  */
+	uint16_t		  user_tagenable;/* Tagged Queuing allowed */
+};
+
+TAILQ_HEAD(ahc_softc_tailq, ahc_softc);
+extern struct ahc_softc_tailq ahc_tailq;
+
+/************************ Active Device Information ***************************/
+typedef enum {
+	ROLE_UNKNOWN,
+	ROLE_INITIATOR,
+	ROLE_TARGET
+} role_t;
+
+struct ahc_devinfo {
+	int	 our_scsiid;
+	int	 target_offset;
+	uint16_t target_mask;
+	u_int	 target;
+	u_int	 lun;
+	char	 channel;
+	role_t	 role;		/*
+				 * Only guaranteed to be correct if not
+				 * in the busfree state.
+				 */
+};
+
+/****************************** PCI Structures ********************************/
+typedef int (ahc_device_setup_t)(ahc_dev_softc_t,
+				 struct ahc_probe_config *);
+
+struct ahc_pci_identity {
+	uint64_t		 full_id;
+	uint64_t		 id_mask;
+	char			*name;
+	ahc_device_setup_t	*setup;
+};
+extern struct ahc_pci_identity ahc_pci_ident_table [];
+extern const u_int ahc_num_pci_devs;
+
+/***************************** VL/EISA Declarations ***************************/
+struct aic7770_identity {
+	uint32_t		 full_id;
+	uint32_t		 id_mask;
+	char			*name;
+	ahc_device_setup_t	*setup;
+};
+extern struct aic7770_identity aic7770_ident_table [];
+extern const int ahc_num_aic7770_devs;
+
+#define AHC_EISA_SLOT_OFFSET	0xc00
+#define AHC_EISA_IOSIZE		0x100
+
+/*************************** Function Declarations ****************************/
+/******************************************************************************/
+u_int			ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
+void			ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
+void			ahc_busy_tcl(struct ahc_softc *ahc,
+				     u_int tcl, u_int busyid);
+
+/***************************** PCI Front End *********************************/
+struct ahc_pci_identity	*ahc_find_pci_device(ahc_dev_softc_t);
+int			 ahc_pci_config(struct ahc_softc *,
+					struct ahc_pci_identity *);
+
+/*************************** EISA/VL Front End ********************************/
+struct aic7770_identity *aic7770_find_device(uint32_t);
+int			 aic7770_config(struct ahc_softc *ahc,
+					struct aic7770_identity *);
+
+/************************** SCB and SCB queue management **********************/
+int		ahc_probe_scbs(struct ahc_softc *);
+void		ahc_run_untagged_queues(struct ahc_softc *ahc);
+void		ahc_run_untagged_queue(struct ahc_softc *ahc,
+				       struct scb_tailq *queue);
+void		ahc_qinfifo_requeue_tail(struct ahc_softc *ahc,
+					 struct scb *scb);
+int		ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
+			      int target, char channel, int lun,
+			      u_int tag, role_t role);
+
+/****************************** Initialization ********************************/
+void			 ahc_init_probe_config(struct ahc_probe_config *);
+struct ahc_softc	*ahc_alloc(void *platform_arg, char *name);
+int			 ahc_softc_init(struct ahc_softc *,
+					struct ahc_probe_config*);
+void			 ahc_controller_info(struct ahc_softc *ahc, char *buf);
+int			 ahc_init(struct ahc_softc *ahc);
+void			 ahc_pause_and_flushwork(struct ahc_softc *ahc);
+int			 ahc_suspend(struct ahc_softc *ahc); 
+int			 ahc_resume(struct ahc_softc *ahc);
+void			 ahc_softc_insert(struct ahc_softc *);
+void			 ahc_set_unit(struct ahc_softc *, int);
+void			 ahc_set_name(struct ahc_softc *, char *);
+void			 ahc_alloc_scbs(struct ahc_softc *ahc);
+void			 ahc_free(struct ahc_softc *ahc);
+int			 ahc_reset(struct ahc_softc *ahc);
+void			 ahc_shutdown(void *arg);
+
+/*************************** Interrupt Services *******************************/
+void			ahc_pci_intr(struct ahc_softc *ahc);
+void			ahc_clear_intstat(struct ahc_softc *ahc);
+void			ahc_run_qoutfifo(struct ahc_softc *ahc);
+#ifdef AHC_TARGET_MODE
+void			ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
+#endif
+void			ahc_handle_brkadrint(struct ahc_softc *ahc);
+void			ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
+void			ahc_handle_scsiint(struct ahc_softc *ahc,
+					   u_int intstat);
+void			ahc_clear_critical_section(struct ahc_softc *ahc);
+
+/***************************** Error Recovery *********************************/
+typedef enum {
+	SEARCH_COMPLETE,
+	SEARCH_COUNT,
+	SEARCH_REMOVE
+} ahc_search_action;
+int			ahc_search_qinfifo(struct ahc_softc *ahc, int target,
+					   char channel, int lun, u_int tag,
+					   role_t role, uint32_t status,
+					   ahc_search_action action);
+int			ahc_search_disc_list(struct ahc_softc *ahc, int target,
+					     char channel, int lun, u_int tag,
+					     int stop_on_first, int remove,
+					     int save_state);
+void			ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
+int			ahc_reset_channel(struct ahc_softc *ahc, char channel,
+					  int initiate_reset);
+void			restart_sequencer(struct ahc_softc *ahc);
+/*************************** Utility Functions ********************************/
+void			ahc_compile_devinfo(struct ahc_devinfo *devinfo,
+					    u_int our_id, u_int target,
+					    u_int lun, char channel,
+					    role_t role);
+/************************** Transfer Negotiation ******************************/
+struct ahc_syncrate*	ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
+					  u_int *ppr_options, u_int maxsync);
+u_int			ahc_find_period(struct ahc_softc *ahc,
+					u_int scsirate, u_int maxsync);
+void			ahc_validate_offset(struct ahc_softc *ahc,
+					    struct ahc_initiator_tinfo *tinfo,
+					    struct ahc_syncrate *syncrate,
+					    u_int *offset, int wide,
+					    role_t role);
+void			ahc_validate_width(struct ahc_softc *ahc,
+					   struct ahc_initiator_tinfo *tinfo,
+					   u_int *bus_width,
+					   role_t role);
+void			ahc_update_target_msg_request(struct ahc_softc *ahc,
+					struct ahc_devinfo *dinfo,
+					struct ahc_initiator_tinfo *tinfo,
+					int force, int paused);
+void			ahc_set_width(struct ahc_softc *ahc,
+				      struct ahc_devinfo *devinfo,
+				      u_int width, u_int type, int paused);
+void			ahc_set_syncrate(struct ahc_softc *ahc,
+					 struct ahc_devinfo *devinfo,
+					 struct ahc_syncrate *syncrate,
+					 u_int period, u_int offset,
+					 u_int ppr_options,
+					 u_int type, int paused);
+void			ahc_set_tags(struct ahc_softc *ahc,
+				     struct ahc_devinfo *devinfo, int enable);
+
+/**************************** Target Mode *************************************/
+#ifdef AHC_TARGET_MODE
+void		ahc_send_lstate_events(struct ahc_softc *,
+				       struct tmode_lstate *);
+void		ahc_handle_en_lun(struct ahc_softc *ahc,
+				  struct cam_sim *sim, union ccb *ccb);
+cam_status	ahc_find_tmode_devs(struct ahc_softc *ahc,
+				    struct cam_sim *sim, union ccb *ccb,
+				    struct tmode_tstate **tstate,
+				    struct tmode_lstate **lstate,
+				    int notfound_failure);
+void		ahc_setup_target_msgin(struct ahc_softc *ahc,
+				       struct ahc_devinfo *devinfo);
+#ifndef AHC_TMODE_ENABLE
+#define AHC_TMODE_ENABLE 0
+#endif
+#endif
+/******************************* Debug ***************************************/
+void			ahc_print_scb(struct scb *scb);
+void			ahc_dump_card_state(struct ahc_softc *ahc);
+#endif /* _AIC7XXX_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.reg	Thu Feb 10 19:00:35 2000
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Sun Mar  4 14:30:18 2001
@@ -1,7 +1,7 @@
 /*
  * Aic7xxx register and scratch ram definitions.
  *
- * Copyright (c) 1994-1998 Justin Gibbs.
+ * Copyright (c) 1994-2001 Justin Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -9,16 +9,12 @@
  * 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.
+ *    without modification.
  * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -32,7 +28,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
+ * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $
  */
 
 /*
@@ -114,6 +112,8 @@
 	mask	PHASE_MASK	CDI|IOI|MSGI
 	mask	P_DATAOUT	0x00
 	mask	P_DATAIN	IOI
+	mask	P_DATAOUT_DT	P_DATAOUT|MSGI
+	mask	P_DATAIN_DT	P_DATAIN|MSGI
 	mask	P_COMMAND	CDI
 	mask	P_MESGOUT	CDI|MSGI
 	mask	P_STATUS	CDI|IOI
@@ -160,8 +160,10 @@
 	address			0x004
 	access_mode RW
 	bit	WIDEXFER	0x80		/* Wide transfer control */
+	bit	ENABLE_CRC	0x40		/* CRC for D-Phases */
+	bit	SINGLE_EDGE	0x10		/* Disable DT Transfers */
 	mask	SXFR		0x70		/* Sync transfer rate */
-	mask	SXFR_ULTRA2	0x7f		/* Sync transfer rate */
+	mask	SXFR_ULTRA2	0x0f		/* Sync transfer rate */
 	mask	SOFS		0x0f		/* Sync offset */
 }
 
@@ -174,6 +176,8 @@
 	address			0x005
 	access_mode RW
 	mask	TID		0xf0		/* Target ID mask */
+	mask	TWIN_TID	0x70
+	bit	TWIN_CHNLB	0x80
 	mask	OID		0x0f		/* Our ID mask */
 	/*
 	 * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
@@ -213,24 +217,27 @@
 	access_mode RW
 }
 
-/*
- * Option Mode Register (Alternate Mode) (p. 5-198)
- * This register is used to set certain options on Ultra3 based chips.
- * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set)
- */
+/* ALT_MODE register on Ultra160 chips */
 register OPTIONMODE {
 	address			0x008
 	access_mode RW
-	bit	AUTORATEEN	0x80
-	bit	AUTOACKEN	0x40
-	bit	ATNMGMNTEN	0x20
-	bit	BUSFREEREV	0x10
-	bit	EXPPHASEDIS	0x08
-	bit	SCSIDATL_IMGEN	0x04
-	bit	AUTO_MSGOUT_DE	0x02
+	bit	AUTORATEEN		0x80
+	bit	AUTOACKEN		0x40
+	bit	ATNMGMNTEN		0x20
+	bit	BUSFREEREV		0x10
+	bit	EXPPHASEDIS		0x08
+	bit	SCSIDATL_IMGEN		0x04
+	bit	AUTO_MSGOUT_DE		0x02
 	bit	DIS_MSGIN_DUALEDGE	0x01
+	mask	OPTIONMODE_DEFAULTS	AUTO_MSGOUT_DE|DIS_MSGIN_DUALEDGE
 }
 
+/* ALT_MODE register on Ultra160 chips */
+register TARGCRCCNT {
+	address			0x00a
+	size	2
+	access_mode RW
+}
 
 /*
  * Clear SCSI Interrupt 0 (p. 3-20)
@@ -243,6 +250,7 @@
 	bit	CLRSELDI	0x20
 	bit	CLRSELINGO	0x10
 	bit	CLRSWRAP	0x08
+	bit	CLRIOERR	0x08	/* Ultra2 Only */
 	bit	CLRSPIORDY	0x02
 }
 
@@ -304,13 +312,12 @@
 	address			0x00d
 	access_mode RO
 	bit	OVERRUN		0x80
-	bit	SHVALID		0x40
-	bit	WIDE_RES	0x20
+	bit	SHVALID		0x40	/* Shaddow Layer non-zero */
 	bit	EXP_ACTIVE	0x10	/* SCSI Expander Active */
-	bit	CRCVALERR	0x08	/* CRC Value Error */
-	bit	CRCENDERR	0x04	/* CRC End Error */
-	bit	CRCREQERR	0x02	/* CRC REQ Error */
-	bit	DUAL_EDGE_ERROR	0x01	/* Invalid pins for Dual Edge phase */
+	bit	CRCVALERR	0x08	/* CRC doesn't match (U3 only) */
+	bit	CRCENDERR	0x04	/* No terminal CRC packet (U3 only) */
+	bit	CRCREQERR	0x02	/* Illegal CRC packet req (U3 only) */
+	bit	DUAL_EDGE_ERR	0x01	/* Incorrect data phase (U3 only) */
 	mask	SFCNT		0x1f
 }
 
@@ -376,12 +383,12 @@
  */
 register SCSIBUSL {
 	address			0x012
-	access_mode RO
+	access_mode RW
 }
 
 register SCSIBUSH {
 	address			0x013
-	access_mode RO
+	access_mode RW
 }
 
 /*
@@ -410,6 +417,7 @@
 	bit	STAGE3		0x04
 	bit	STAGE2		0x02
 	bit	STAGE1		0x01
+	alias	TARGIDIN
 }
 
 /*
@@ -424,6 +432,25 @@
 	bit	ONEBIT		0x08
 }
 
+register SCAMCTL {
+	address			0x01a
+	access_mode RW
+	bit	ENSCAMSELO	0x80
+	bit	CLRSCAMSELID	0x40
+	bit	ALTSTIM		0x20
+	bit	DFLTTID		0x10
+	mask	SCAMLVL		0x03
+}
+
+/*
+ * Target Mode Selecting in ID bitmask (aic7890/91/96/97)
+ */
+register TARGID {
+	address			0x01b
+	size			2
+	access_mode RW
+}
+
 /*
  * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
  * Indicates if external logic has been attached to the chip to
@@ -445,6 +472,59 @@
 	bit	SSPIOCPS	0x01	/* Termination and cable detection */
 }
 
+register BRDCTL	{
+	address			0x01d
+	bit	BRDDAT7		0x80
+	bit	BRDDAT6		0x40
+	bit	BRDDAT5		0x20
+	bit	BRDSTB		0x10
+	bit	BRDCS		0x08
+	bit	BRDRW		0x04
+	bit	BRDCTL1		0x02
+	bit	BRDCTL0		0x01
+	/* 7890 Definitions */
+	bit	BRDDAT4		0x10
+	bit	BRDDAT3		0x08
+	bit	BRDDAT2		0x04
+	bit	BRDRW_ULTRA2	0x02
+	bit	BRDSTB_ULTRA2	0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+register SEECTL {
+	address			0x01e
+	bit	EXTARBACK	0x80
+	bit	EXTARBREQ	0x40
+	bit	SEEMS		0x20
+	bit	SEERDY		0x10
+	bit	SEECS		0x08
+	bit	SEECK		0x04
+	bit	SEEDO		0x02
+	bit	SEEDI		0x01
+}
 /*
  * SCSI Block Control (p. 3-32)
  * Controls Bus type and channel selection.  In a twin channel configuration
@@ -585,30 +665,22 @@
 	bit	ENABLE		0x01
 }
 
-register DSCOMMAND0 {
-	address			0x084
-	access_mode RW
-	bit	CACHETHEN	0x80
-	bit	DPARCKEN	0x40
-	bit	MPARCKEN	0x20
-	bit	EXTREQLCK	0x10
-	bit	INTSCBRAMSEL	0x08
-	bit	RAMPS		0x04
-	bit	USCBSIZE32	0x02
-	bit	CIOPARCKEN	0x01
-}
-
 /*
  * On the aic78X0 chips, Board Control is replaced by the DSCommand
  * register (p. 4-64)
  */
-register DSCOMMAND {
+register DSCOMMAND0 {
 	address			0x084
 	access_mode RW
 	bit	CACHETHEN	0x80	/* Cache Threshold enable */
 	bit	DPARCKEN	0x40	/* Data Parity Check Enable */
 	bit	MPARCKEN	0x20	/* Memory Parity Check Enable */
 	bit	EXTREQLCK	0x10	/* External Request Lock */
+	/* aic7890/91/96/97 only */
+	bit	INTSCBRAMSEL	0x08	/* Internal SCB RAM Select */
+	bit	RAMPS		0x04	/* External SCB RAM Present */
+	bit	USCBSIZE32	0x02	/* Use 32byte SCB Page Size */
+	bit	CIOPARCKEN	0x01	/* Internal bus parity error enable */
 }
 
 /*
@@ -622,7 +694,7 @@
 }
 
 /*
- * Bus Speed (p. 3-45)
+ * Bus Speed (p. 3-45) aic7770 only
  */
 register BUSSPD {
 	address			0x086
@@ -631,8 +703,26 @@
 	mask	STBOFF		0x38
 	mask	STBON		0x07
 	mask	DFTHRSH_100	0xc0
+	mask	DFTHRSH_75	0x80
+}
+
+/* aic7850/55/60/70/80/95 only */
+register DSPCISTATUS {
+	address			0x086
+	mask	DFTHRSH_100	0xc0
+}
+
+/* aic7890/91/96/97 only */
+register HS_MAILBOX {
+	address			0x086
+	mask	HOST_MAILBOX	0xF0
+	mask	SEQ_MAILBOX	0x0F
+	mask	HOST_TQINPOS	0x80	/* Boundary at either 0 or 128 */
 }
 
+const	HOST_MAILBOX_SHIFT	4
+const	SEQ_MAILBOX_SHIFT	0
+
 /*
  * Host Control (p. 3-47) R/W
  * Overall host control of the device.
@@ -668,7 +758,7 @@
 
 /*
  * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
+ * Gate one of the SCBs into the SCBARRAY window.
  */
 register SCBPTR {
 	address			0x090
@@ -690,31 +780,48 @@
 	mask	SEND_REJECT	0x10|SEQINT	/* sending a message reject */
 	mask	NO_IDENT	0x20|SEQINT	/* no IDENTIFY after reconnect*/
 	mask	NO_MATCH	0x30|SEQINT	/* no cmd match for reconnect */
-	mask	EXTENDED_MSG	0x40|SEQINT	/* Extended message received */
-	mask	WIDE_RESIDUE	0x50|SEQINT	/* need kernel to back up */
-						/* the SG array for us */
-	mask	REJECT_MSG	0x60|SEQINT	/* Reject message received */
-	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
-	mask	RESIDUAL	0x80|SEQINT	/* Residual byte count != 0 */
-	mask	AWAITING_MSG	0xa0|SEQINT	/*
-						 * Kernel requested to specify
-						 * a message to this target
-						 * (command was null), so tell
-						 * it that it can fill the
-						 * message buffer.
+	mask	IGN_WIDE_RES	0x40|SEQINT	/* Complex IGN Wide Res Msg */
+	mask	RESIDUAL	0x50|SEQINT	/* Residual byte count != 0 */
+	mask	HOST_MSG_LOOP	0x60|SEQINT	/*
+						 * The bus is ready for the
+						 * host to perform another
+						 * message transaction.  This
+						 * mechanism is used for things
+						 * like sync/wide negotiation
+						 * that require a kernel based
+						 * message state engine.
 						 */
-	mask	TRACEPOINT	0xb0|SEQINT
-	mask	TRACEPOINT2	0xc0|SEQINT
-	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
-						 * Target changed phase on us
-						 * when we were expecting
-						 * another msgin byte.
+	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
+	mask	PERR_DETECTED	0x80|SEQINT	/*
+						 * Either the phase_lock
+						 * or inb_next routine has
+						 * noticed a parity error.
 						 */
-	mask	DATA_OVERRUN	0xe0|SEQINT	/*
+	mask	DATA_OVERRUN	0x90|SEQINT	/*
 						 * Target attempted to write
 						 * beyond the bounds of its
 						 * command.
 						 */
+	mask	MKMSG_FAILED	0xa0|SEQINT	/*
+						 * Target completed command
+						 * without honoring our ATN
+						 * request to issue a message. 
+						 */
+	mask	MISSED_BUSFREE	0xb0|SEQINT	/*
+						 * The sequencer never saw
+						 * the bus go free after
+						 * either a command complete
+						 * or disconnect message.
+						 */
+	mask	SCB_MISMATCH	0xc0|SEQINT	/*
+						 * Downloaded SCB's tag does
+						 * not match the entry we
+						 * intended to download.
+						 */
+	mask	NO_FREE_SCB	0xd0|SEQINT	/*
+						 * get_free_or_disc_scb failed.
+						 */
+	mask	OUT_OF_RANGE	0xe0|SEQINT
 
 	mask	SEQINT_MASK	0xf0|SEQINT	/* SEQINT Status Codes */
 	mask	INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
@@ -735,7 +842,6 @@
 	bit	SQPARERR	0x08
 	bit	ILLOPCODE	0x04
 	bit	ILLSADDR	0x02
-	bit	DSCTMOUT	0x02	/* Ultra3 only */
 	bit	ILLHADDR	0x01
 }
 
@@ -779,6 +885,16 @@
 	bit	FIFOEMP		0x01
 }
 
+register DFWADDR {
+	address			0x95
+	access_mode RW
+}
+
+register DFRADDR {
+	address			0x97
+	access_mode RW
+}
+
 register DFDAT {
 	address			0x099
 	access_mode RW
@@ -815,17 +931,6 @@
 }
 
 /*
- * SCSIDATL IMAGE Register (p. 5-104)
- * Write to this register also go to SCSIDATL but this register will preserve
- * the data for later reading as long as the SCSIDATL_IMGEN bit in the
- * OPTIONMODE register is set.
- */
-register SCSIDATL_IMG {
-	address			0x09c
-	access_mode RW
-}
-
-/*
  * Queue Out FIFO (p. 3-61)
  * Queue of SCBs that have completed and await the host
  */
@@ -834,21 +939,18 @@
 	access_mode WO
 }
 
-/*
- * CRC Control 1 Register (p. 5-105)
- * Control bits for the Ultra 160/m CRC facilities
- */
 register CRCCONTROL1 {
 	address			0x09d
 	access_mode RW
-	bit	CRCONSEEN	0x80 /* CRC ON Single Edge ENable */
-	bit	CRCVALCHKEN	0x40 /* CRC Value Check Enable */
-	bit	CRCENDCHKEN	0x20 /* CRC End Check Enable */
-	bit	CRCREQCHKEN	0x10
-	bit	TARGCRCENDEN	0x08 /* Enable End CRC transfer when target */
-	bit	TARGCRCCNTEN	0x04 /* Enable CRC transfer when target */
+	bit	CRCONSEEN		0x80
+	bit	CRCVALCHKEN		0x40
+	bit	CRCENDCHKEN		0x20
+	bit	CRCREQCHKEN		0x10
+	bit	TARGCRCENDEN		0x08
+	bit	TARGCRCCNTEN		0x04
 }
 
+
 /*
  * Queue Out Count (p. 3-61)
  * Number of queued SCBs in the Out FIFO
@@ -858,19 +960,15 @@
 	access_mode RO
 }
 
-/*
- * SCSI Phase Register (p. 5-106)
- * Current bus phase
- */
 register SCSIPHASE {
 	address			0x09e
 	access_mode RO
-	bit	SP_STATUS		0x20
-	bit	SP_COMMAND		0x10
-	bit	SP_MSG_IN		0x08
-	bit	SP_MSG_OUT		0x04
-	bit	SP_DATA_IN		0x02
-	bit	SP_DATA_OUT	0x01
+	bit	STATUS_PHASE	0x20
+	bit	COMMAND_PHASE	0x10
+	bit	MSG_IN_PHASE	0x08
+	bit	MSG_OUT_PHASE	0x04
+	bit	DATA_IN_PHASE	0x02
+	bit	DATA_OUT_PHASE	0x01
 }
 
 /*
@@ -887,33 +985,19 @@
  */
 scb {
 	address			0x0a0
-	SCB_CONTROL {
-		size	1
-		bit	MK_MESSAGE      0x80
-		bit	DISCENB         0x40
-		bit	TAG_ENB		0x20
-		bit	DISCONNECTED	0x04
-		mask	SCB_TAG_TYPE	0x03
-	}
-	SCB_TCL {
-		size	1
-		bit	SELBUSB		0x08
-		mask	TID		0xf0
-		mask	LID		0x07
-	}
-	SCB_TARGET_STATUS {
-		size	1
-	}
-	SCB_SGCOUNT {
-		size	1
+	SCB_CDB_PTR {
+		size	4
+		alias	SCB_RESIDUAL_DATACNT
+		alias	SCB_CDB_STORE
+		alias	SCB_TARGET_INFO
 	}
-	SCB_SGPTR {
+	SCB_RESIDUAL_SGPTR {
 		size	4
 	}
-	SCB_RESID_SGCNT {
+	SCB_SCSI_STATUS {
 		size	1
 	}
-	SCB_RESID_DCNT	{
+	SCB_CDB_STORE_PAD {
 		size	3
 	}
 	SCB_DATAPTR {
@@ -921,31 +1005,67 @@
 	}
 	SCB_DATACNT {
 		/*
-		 * Really only 3 bytes, but padded to make
-		 * the kernel's job easier.
+		 * The last byte is really the high address bits for
+		 * the data address.
 		 */
 		size	4
+		bit	SG_LAST_SEG		0x80	/* In the fourth byte */
+		mask	SG_HIGH_ADDR_BITS	0x7F	/* In the fourth byte */
 	}
-	SCB_CMDPTR {
+	SCB_SGPTR {
 		size	4
+		bit	SG_RESID_VALID	0x04	/* In the first byte */
+		bit	SG_FULL_RESID	0x02	/* In the first byte */
+		bit	SG_LIST_NULL	0x01	/* In the first byte */
+	}
+	SCB_CONTROL {
+		size	1
+		bit	TARGET_SCB			0x80
+		bit	DISCENB				0x40
+		bit	TAG_ENB				0x20
+		bit	MK_MESSAGE			0x10
+		bit	ULTRAENB			0x08
+		bit	DISCONNECTED			0x04
+		mask	SCB_TAG_TYPE			0x03
 	}
-	SCB_CMDLEN {
+	SCB_SCSIID {
+		size	1
+		bit	TWIN_CHNLB			0x80
+		mask	TWIN_TID			0x70
+		mask	TID				0xf0
+		mask	OID				0x0f
+	}
+	SCB_LUN {
+		mask	LID				0xff
 		size	1
 	}
 	SCB_TAG {
 		size	1
 	}
-	SCB_NEXT {
+	SCB_CDB_LEN {
 		size	1
 	}
-	SCB_PREV {
+	SCB_SCSIRATE {
 		size	1
 	}
-	SCB_BUSYTARGETS {
-		size	4
+	SCB_SCSIOFFSET {
+		size	1
+	}
+	SCB_NEXT {
+		size	1
+	}
+	SCB_64_SPARE {
+		size	16
+	}
+	SCB_64_BTT {
+		size	16
 	}
 }
 
+const	SCB_UPLOAD_SIZE		32
+const	SCB_DOWNLOAD_SIZE	32
+const	SCB_DOWNLOAD_SIZE_64	48
+
 const	SG_SIZEOF	0x08		/* sizeof(struct ahc_dma) */
 
 /* --------------------- AHA-2840-only definitions -------------------- */
@@ -969,11 +1089,6 @@
 
 /* --------------------- AIC-7870-only definitions -------------------- */
 
-register DSPCISTATUS {
-	address			0x086
-	mask	DFTHRSH_100	0xc0
-}
-
 register CCHADDR {
 	address			0x0E0
 	size 8
@@ -995,7 +1110,7 @@
 	address			0x0EB
 	bit	CCSGDONE	0x80
 	bit	CCSGEN		0x08
-	bit	FLAG		0x02
+	bit	SG_FETCH_NEEDED 0x02	/* Bit used for software state */
 	bit	CCSGRESET	0x01
 }
 
@@ -1021,6 +1136,14 @@
 	address			0xEC
 }
 
+/*
+ * SCB bank address (7895/7896/97 only)
+ */
+register SCBBADDR {
+	address			0x0F0
+	access_mode RW
+}
+
 register CCSCBPTR {
 	address			0x0F1
 }
@@ -1029,29 +1152,19 @@
 	address			0x0F4
 }
 
-register HESCB_QOFF {
-	address			0x0F5
-}
-
 register SNSCB_QOFF {
 	address			0x0F6
 }
 
-register SESCB_QOFF {
-	address			0x0F7
-}
-
 register SDSCB_QOFF {
 	address			0x0F8
 }
 
 register QOFF_CTLSTA {
 	address			0x0FA
-	bit	ESTABLISH_SCB_AVAIL	0x80
 	bit	SCB_AVAIL	0x40
 	bit	SNSCB_ROLLOVER	0x20
 	bit	SDSCB_ROLLOVER	0x10
-	bit	SESCB_ROLLOVER	0x08
 	mask	SCB_QSIZE	0x07
 	mask	SCB_QSIZE_256	0x06
 }
@@ -1078,66 +1191,22 @@
 	mask	WR_DFTHRSH_MAX	0x70
 }
 
-register SG_CACHEPTR {
-	access_mode RW
+register SG_CACHE_PRE {
+	access_mode WO
 	address			0x0fc
-	mask	SG_USER_DATA	0xfc
+	mask	SG_ADDR_MASK	0xf8
+	bit	ODD_SEG		0x04
 	bit	LAST_SEG	0x02
 	bit	LAST_SEG_DONE	0x01
 }
 
-register BRDCTL	{
-	address			0x01d
-	bit	BRDDAT7		0x80
-	bit	BRDDAT6		0x40
-	bit	BRDDAT5		0x20
-	bit	BRDSTB		0x10
-	bit	BRDCS		0x08
-	bit	BRDRW		0x04
-	bit	BRDCTL1		0x02
-	bit	BRDCTL0		0x01
-	/* 7890 Definitions */
-	bit	BRDDAT4		0x10
-	bit	BRDDAT3		0x08
-	bit	BRDDAT2		0x04
-	bit	BRDRW_ULTRA2	0x02
-	bit	BRDSTB_ULTRA2	0x01
-}
-
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  
- *
- * After successful arbitration for the memory port, the SEECS bit of 
- * the SEECTL register is connected to the chip select.  The SEECK, 
- * SEEDO, and SEEDI are connected to the clock, data out, and data in 
- * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
- * gives us an 800 nsec timer.  After a write to the SEECTL register, 
- * the SEERDY goes high 800 nsec later.  The one exception to this is 
- * when we first request access to the memory port.  The SEERDY goes 
- * high to signify that access has been granted and, for this case, has 
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to 
- * read the serial EEPROM.
- */
-register SEECTL {
-	address			0x01e
-	bit	EXTARBACK	0x80
-	bit	EXTARBREQ	0x40
-	bit	SEEMS		0x20
-	bit	SEERDY		0x10
-	bit	SEECS		0x08
-	bit	SEECK		0x04
-	bit	SEEDO		0x02
-	bit	SEEDI		0x01
+register SG_CACHE_SHADOW {
+	access_mode RO
+	address			0x0fc
+	mask	SG_ADDR_MASK	0xf8
+	bit	ODD_SEG		0x04
+	bit	LAST_SEG	0x02
+	bit	LAST_SEG_DONE	0x01
 }
 /* ---------------------- Scratch RAM Offsets ------------------------- */
 /* These offsets are either to values that are initialized by the board's
@@ -1160,21 +1229,46 @@
 	/*
 	 * 1 byte per target starting at this address for configuration values
 	 */
-	TARG_SCSIRATE {
+	BUSY_TARGETS {
+		alias		TARG_SCSIRATE
 		size		16
 	}
 	/*
-	 * Bit vector of targets that have ULTRA enabled.
+	 * Bit vector of targets that have ULTRA enabled as set by
+	 * the BIOS.  The Sequencer relies on a per-SCB field to
+	 * control whether to enable Ultra transfers or not.  During
+	 * initialization, we read this field and reuse it for 2
+	 * entries in the busy target table.
 	 */
 	ULTRA_ENB {
+		alias		CMDSIZE_TABLE
 		size		2
 	}
 	/*
-	 * Bit vector of targets that have disconnection disabled.
+	 * Bit vector of targets that have disconnection disabled as set by
+	 * the BIOS.  The Sequencer relies in a per-SCB field to control the
+	 * disconnect priveldge.  During initialization, we read this field
+	 * and reuse it for 2 entries in the busy target table.
 	 */
 	DISC_DSB {
 		size		2
 	}
+	CMDSIZE_TABLE_TAIL {
+		size		4
+	}
+	/*
+	 * Partial transfer past cacheline end to be
+	 * transferred using an extra S/G.
+	 */
+	MWI_RESIDUAL {
+		size		1
+	}
+	/*
+	 * SCBID of the next SCB to be started by the controller.
+	 */
+	NEXT_QUEUED_SCB {
+		size		1
+	}
 	/*
 	 * Single byte buffer used to designate the type or message
 	 * to send to a target.
@@ -1198,29 +1292,27 @@
 	}
 	SEQ_FLAGS {
 		size		1
-		bit	IDENTIFY_SEEN	0x80
-		bit	SCBPTR_VALID	0x20
-		bit	DPHASE		0x10
-		bit	AMTARGET	0x08
-		bit	WIDE_BUS	0x02
-		bit	TWIN_BUS	0x01
+		bit	IDENTIFY_SEEN		0x80
+		bit	TARGET_CMD_IS_TAGGED	0x40
+		bit	DPHASE			0x20
+		/* Target flags */
+		bit	TARG_CMD_PENDING	0x10
+		bit	CMDPHASE_PENDING	0x08
+		bit	DPHASE_PENDING		0x04
+		bit	SPHASE_PENDING		0x02
+		bit	NO_DISCONNECT		0x01
 	}
 	/*
 	 * Temporary storage for the
 	 * target/channel/lun of a
 	 * reconnecting target
 	 */
-	SAVED_TCL {
+	SAVED_SCSIID {
 		size		1
 	}
-	/* Working value of the number of SG segments left */
-	SG_COUNT {
+	SAVED_LUN {
 		size		1
 	}
-	/* Working value of SG pointer */
-	SG_NEXT	{
-		size		4
-	}
 	/*
 	 * The last bus phase as seen by the sequencer. 
 	 */
@@ -1261,23 +1353,25 @@
 		size		1
 	}
 	/*
-	 * Address of the hardware scb array in the host.
+	 * head of list of SCBs that have
+	 * completed but have not been
+	 * put into the qoutfifo.
 	 */
-	HSCB_ADDR {
-		size		4
+	COMPLETE_SCBH {
+		size		1
 	}
 	/*
-	 * Address of the 256 byte array storing the SCBID of outstanding
-	 * untagged SCBs indexed by TCL.
+	 * Address of the hardware scb array in the host.
 	 */
-	SCBID_ADDR {
+	HSCB_ADDR {
 		size		4
 	}
 	/*
-	 * Address of the array of command descriptors used to store
-	 * information about incoming selections.
+	 * Base address of our shared data with the kernel driver in host
+	 * memory.  This includes the qoutfifo and target mode
+	 * incoming command queue.
 	 */
-	TMODE_CMDADDR {
+	SHARED_DATA_ADDR {
 		size		4
 	}
 	KERNEL_QINPOS {
@@ -1290,18 +1384,25 @@
 		size		1
 	}
 	/*
-	 * Offset into the command descriptor array for the next
-	 * available desciptor to use.
+	 * Kernel and sequencer offsets into the queue of
+	 * incoming target mode command descriptors.  The
+	 * queue is full when the KERNEL_TQINPOS == TQINPOS.
 	 */
-	TMODE_CMDADDR_NEXT {
+	KERNEL_TQINPOS {
+		size		1
+	}
+	TQINPOS {                
 		size		1
 	}
 	ARG_1 {
 		size		1
-		mask	SEND_MSG	0x80
-		mask	SEND_SENSE	0x40
-		mask	SEND_REJ	0x20
-		mask	MSGOUT_PHASEMIS	0x10
+		mask	SEND_MSG		0x80
+		mask	SEND_SENSE		0x40
+		mask	SEND_REJ		0x20
+		mask	MSGOUT_PHASEMIS		0x10
+		mask	EXIT_MSG_LOOP		0x08
+		mask	CONT_MSG_LOOP		0x04
+		mask	CONT_TARG_SESSION	0x02
 		alias	RETURN_1
 	}
 	ARG_2 {
@@ -1317,15 +1418,49 @@
 	}
 
 	/*
-	 * Number of times we have filled the CCSGRAM with prefetched
-	 * SG elements.
+	 * Interrupt kernel for a message to this target on
+	 * the next transaction.  This is usually used for
+	 * negotiation requests.
+	 */
+	TARGET_MSG_REQUEST {
+		size		2
+	}
+
+	/*
+	 * Sequences the kernel driver has okayed for us.  This allows
+	 * the driver to do things like prevent initiator or target
+	 * operations.
 	 */
-	PREFETCH_CNT {
+	SCSISEQ_TEMPLATE {
 		size		1
+		bit	ENSELO		0x40
+		bit	ENSELI		0x20
+		bit	ENRSELI		0x10
+		bit	ENAUTOATNO	0x08
+		bit	ENAUTOATNI	0x04
+		bit	ENAUTOATNP	0x02
 	}
 
+	/*
+	 * Track whether the transfer byte count for
+	 * the current data phase is odd.
+	 */
+	DATA_COUNT_ODD {
+		size		1
+	}
 
 	/*
+	 * The initiator specified tag for this target mode transaction.
+	 */
+	INITIATOR_TAG {
+		size		1
+	}
+
+	SEQ_FLAGS2 {
+		size		1
+		bit	SCB_DMA		0x01
+	}
+	/*
 	 * These are reserved registers in the card's scratch ram.  Some of
 	 * the values are specified in the AHA2742 technical reference manual
 	 * and are initialized by the BIOS at boot time.
@@ -1335,9 +1470,16 @@
 		size		1
 		bit	TERM_ENB	0x80
 		bit	RESET_SCSI	0x40
+		bit	ENSPCHK		0x20
 		mask	HSCSIID		0x07	/* our SCSI ID */
 		mask	HWSCSIID	0x0f	/* our SCSI ID if Wide Bus */
 	}
+	INTDEF {
+		address		0x05c
+		size		1
+		bit	EDGE_TRIG	0x80
+		mask	VECTOR		0x0f
+	}
 	HOSTCONF {
 		address		0x05d
 		size		1
@@ -1358,16 +1500,13 @@
 	}
 }
 
+const TID_SHIFT		4
 const SCB_LIST_NULL	0xff
+const TARGET_CMD_CMPLT	0xfe
 
 const CCSGADDR_MAX	0x80
 const CCSGRAM_MAXSEGS	16
 
-/* Offsets into the SCBID array where different data is stored */
-const UNTAGGEDSCB_OFFSET	0
-const QOUTFIFO_OFFSET		1
-const QINFIFO_OFFSET		2
-
 /* WDTR Message values */
 const BUS_8_BIT			0x00
 const BUS_16_BIT		0x01
@@ -1381,16 +1520,23 @@
 
 /* Target mode command processing constants */
 const CMD_GROUP_CODE_SHIFT	0x05
-const CMD_GROUP0_BYTE_DELTA	-4
-const CMD_GROUP2_BYTE_DELTA	-6
-const CMD_GROUP4_BYTE_DELTA	4
-const CMD_GROUP5_BYTE_DELTA	11
 
-/*
- * Downloaded (kernel inserted) constants
- */
+const STATUS_BUSY		0x08
+const STATUS_QUEUE_FULL	0x28
+const SCB_TARGET_PHASES		0
+const SCB_TARGET_DATA_DIR	1
+const SCB_TARGET_STATUS		2
+const SCB_INITIATOR_TAG		3
+const TARGET_DATA_IN		1
 
 /*
- * Number of command descriptors in the command descriptor array.
+ * Downloaded (kernel inserted) constants
  */
-const TMODE_NUMCMDS	download
+/* Offsets into the SCBID array where different data is stored */
+const QOUTFIFO_OFFSET download
+const QINFIFO_OFFSET download
+const CACHESIZE_MASK download
+const INVERTED_CACHESIZE_MASK download
+const SG_PREFETCH_CNT download
+const SG_PREFETCH_ALIGN_MASK download
+const SG_PREFETCH_ADDR_MASK download
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx.seq	Wed Jun 21 17:25:03 2000
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Sun Mar  4 14:30:18 2001
@@ -1,7 +1,7 @@
 /*
  * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
  *
- * Copyright (c) 1994-1999 Justin Gibbs.
+ * Copyright (c) 1994-2001 Justin Gibbs.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -9,16 +9,12 @@
  * 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.
+ *    without modification.
  * 2. The name of the author may not be used to endorse or promote products
  *    derived from this software without specific prior written permission.
  *
- * Where this Software is combined with software released under the terms of 
- * the GNU Public License (GPL) and the terms of the GPL would require the 
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -32,7 +28,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $
+ * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $
  */
 
 #include "aic7xxx.reg"
@@ -48,7 +46,7 @@
  * a later time.  This problem cannot be resolved by holding a single entry
  * in scratch ram since a reconnecting target can request sense and this will
  * create yet another SCB waiting for selection.  The solution used here is to 
- * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
+ * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
  * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
  * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
  * this list everytime a request sense occurs or after completing a non-tagged
@@ -56,200 +54,386 @@
  * automatically consume the entries.
  */
 
-reset:
-	clr	SCSISIGO;		/* De-assert BSY */
-	and	SXFRCTL1, ~BITBUCKET;
-	/* Always allow reselection */
-	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
-
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		/* Ensure that no DMA operations are in progress */
-		clr	CCSGCTL;
-		clr	CCSCBCTL;
-	}
-
-	call	clear_target_state;
+bus_free_sel:
+	/*
+	 * Turn off the selection hardware.  We need to reset the
+	 * selection request in order to perform a new selection.
+	 */
+	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
+	and	SIMODE1, ~ENBUSFREE;
 poll_for_work:
+	call	clear_target_state;
 	and	SXFRCTL0, ~SPIOEN;
-	if ((p->features & AHC_QUEUE_REGS) == 0) {
-		mov	A, QINPOS;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		clr	SCSIBUSL;
 	}
-poll_for_work_loop:
-	if ((p->features & AHC_QUEUE_REGS) == 0) {
-		and	SEQCTL, ~PAUSEDIS;
-	}
-	test	SSTAT0, SELDO|SELDI	jnz selection;
-	test	SCSISEQ, ENSELO	jnz poll_for_work;
-	if ((p->features & AHC_TWIN) != 0) {
-		/*
-		 * Twin channel devices cannot handle things like SELTO
-		 * interrupts on the "background" channel.  So, if we
-		 * are selecting, keep polling the current channel util
-		 * either a selection or reselection occurs.
-		 */
+	test	SCSISEQ, ENSELO	jnz poll_for_selection;
+	if ((ahc->features & AHC_TWIN) != 0) {
 		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
-		test	SSTAT0, SELDO|SELDI	jnz selection;
-		test	SCSISEQ, ENSELO	jnz poll_for_work;
-		xor	SBLKCTL,SELBUSB;	/* Toggle back */
+		test	SCSISEQ, ENSELO		jnz poll_for_selection;
 	}
 	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
+poll_for_work_loop:
+	if ((ahc->features & AHC_TWIN) != 0) {
+		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
+	}
+	test	SSTAT0, SELDO|SELDI	jnz selection;
 test_queue:
 	/* Has the driver posted any work for us? */
-	if ((p->features & AHC_QUEUE_REGS) != 0) {
+BEGIN_CRITICAL
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
 		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
-		mov	NONE, SNSCB_QOFF;
-		inc	QINPOS;
 	} else {
-		or	SEQCTL, PAUSEDIS;
+		mov	A, QINPOS;
 		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
-		inc	QINPOS;
-		and	SEQCTL, ~PAUSEDIS;
 	}
+	mov	ARG_1, NEXT_QUEUED_SCB;
 
-/*
- * We have at least one queued SCB now and we don't have any 
- * SCBs in the list of SCBs awaiting selection.  If we have
- * any SCBs available for use, pull the tag from the QINFIFO
- * and get to work on it.
- */
-	if ((p->flags & AHC_PAGESCBS) != 0) {
+	/*
+	 * We have at least one queued SCB now and we don't have any 
+	 * SCBs in the list of SCBs awaiting selection.  Allocate a
+	 * card SCB for the host's SCB and get to work on it.
+	 */
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
 		mov	ALLZEROS	call	get_free_or_disc_scb;
-	}
-
-dequeue_scb:
-	add	A, -1, QINPOS;
-	mvi	QINFIFO_OFFSET call fetch_byte;
-
-	if ((p->flags & AHC_PAGESCBS) == 0) {
+	} else {
 		/* In the non-paging case, the SCBID == hardware SCB index */
-		mov	SCBPTR, RETURN_2;
+		mov	SCBPTR, ARG_1;
 	}
+	or	SEQ_FLAGS2, SCB_DMA;
+END_CRITICAL
 dma_queued_scb:
-/*
- * DMA the SCB from host ram into the current SCB location.
- */
+	/*
+	 * DMA the SCB from host ram into the current SCB location.
+	 */
 	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-	mov	RETURN_2	 call dma_scb;
-
-/*
- * Preset the residual fields in case we never go through a data phase.
- * This isn't done by the host so we can avoid a DMA to clear these
- * fields for the normal case of I/O that completes without underrun
- * or overrun conditions.
- */
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		bmov    SCB_RESID_DCNT, SCB_DATACNT, 3;
-	} else {
-		mov     SCB_RESID_DCNT[0],SCB_DATACNT[0];
-		mov     SCB_RESID_DCNT[1],SCB_DATACNT[1];
-		mov     SCB_RESID_DCNT[2],SCB_DATACNT[2];
-	}
-	mov     SCB_RESID_SGCNT, SCB_SGCOUNT;
-
-start_scb:
+	mov	ARG_1	call dma_scb;
 	/*
-	 * Place us on the waiting list in case our selection
-	 * doesn't win during bus arbitration.
+	 * Check one last time to see if this SCB was canceled
+	 * before we completed the DMA operation.  If it was,
+	 * the QINFIFO next pointer will not match our saved
+	 * value.
 	 */
+	mov	A, ARG_1;
+BEGIN_CRITICAL
+	cmp	NEXT_QUEUED_SCB, A jne abort_qinscb;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		cmp	SCB_TAG, A je . + 2;
+		mvi	SCB_MISMATCH call set_seqint;
+	}
+	mov	NEXT_QUEUED_SCB, SCB_NEXT;
 	mov	SCB_NEXT,WAITING_SCBH;
 	mov	WAITING_SCBH, SCBPTR;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		mov	NONE, SNSCB_QOFF;
+	} else {
+		inc	QINPOS;
+	}
+	and	SEQ_FLAGS2, ~SCB_DMA;
+END_CRITICAL
 start_waiting:
 	/*
-	 * Pull the first entry off of the waiting SCB list.
+	 * Start the first entry on the waiting SCB list.
 	 */
 	mov	SCBPTR, WAITING_SCBH;
 	call	start_selection;
-	jmp	poll_for_work;
+
+poll_for_selection:
+	/*
+	 * Twin channel devices cannot handle things like SELTO
+	 * interrupts on the "background" channel.  So, while
+	 * selecting, keep polling the current channel until
+	 * either a selection or reselection occurs.
+	 */
+	test	SSTAT0, SELDO|SELDI	jz poll_for_selection;
+
+selection:
+	/*
+	 * We aren't expecting a bus free, so interrupt
+	 * the kernel driver if it happens.
+	 */
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;
+
+	/*
+	 * Guard against a bus free after (re)selection
+	 * but prior to enabling the busfree interrupt.  SELDI
+	 * and SELDO will be cleared in that case.
+	 */
+	test	SSTAT0, SELDI|SELDO	jz bus_free_sel;
+	test	SSTAT0,SELDO	jnz select_out;
+select_in:
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+			test	SSTAT0, TARGET	jz initiator_reselect;
+		}
+		mvi	CLRSINT0, CLRSELDI;
+
+		/*
+		 * We've just been selected.  Assert BSY and
+		 * setup the phase for receiving messages
+		 * from the target.
+		 *
+		 * If bus reset interrupts have been disabled (from a
+		 * previous reset), re-enable them now.  Resets are only
+		 * of interest when we have outstanding transactions, so
+		 * we can safely defer re-enabling the interrupt until,
+		 * as a target, we start receiving transactions again.
+		 */
+		test	SIMODE1, ENSCSIRST	jnz . + 3;
+		mvi	CLRSINT1, CLRSCSIRSTI;
+		or	SIMODE1, ENSCSIRST;
+		mvi	SCSISIGO, P_MESGOUT|BSYO;
+
+		/*
+		 * Setup the DMA for sending the identify and
+		 * command information.
+		 */
+		or	SEQ_FLAGS, CMDPHASE_PENDING;
+
+		mov     A, TQINPOS;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mvi	DINDEX, CCHADDR;
+			mvi	SHARED_DATA_ADDR call set_32byte_addr;
+			mvi	CCSCBCTL, CCSCBRESET;
+		} else {
+			mvi	DINDEX, HADDR;
+			mvi	SHARED_DATA_ADDR call set_32byte_addr;
+			mvi	DFCNTRL, FIFORESET;
+		}
+
+		/* Initiator that selected us */
+		and	SAVED_SCSIID, SELID_MASK, SELID;
+		/* The Target ID we were selected at */
+		if ((ahc->features & AHC_MULTI_TID) != 0) {
+			and	A, OID, TARGIDIN;
+		} else if ((ahc->features & AHC_ULTRA2) != 0) {
+			and	A, OID, SCSIID_ULTRA2;
+		} else {
+			and	A, OID, SCSIID;
+		}
+		or	SAVED_SCSIID, A;
+		if ((ahc->features & AHC_TWIN) != 0) {
+			test 	SBLKCTL, SELBUSB jz . + 2;
+			or	SAVED_SCSIID, TWIN_CHNLB;
+		}
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, SAVED_SCSIID;
+		} else {
+			mov	DFDAT, SAVED_SCSIID;
+		}
+
+		/*
+		 * If ATN isn't asserted, the target isn't interested
+		 * in talking to us.  Go directly to bus free.
+		 * XXX SCSI-1 may require us to assume lun 0 if
+		 * ATN is false.
+		 */
+		test	SCSISIGI, ATNI	jz	target_busfree;
+
+		/*
+		 * Watch ATN closely now as we pull in messages from the
+		 * initiator.  We follow the guidlines from section 6.5
+		 * of the SCSI-2 spec for what messages are allowed when.
+		 */
+		call	target_inb;
+
+		/*
+		 * Our first message must be one of IDENTIFY, ABORT, or
+		 * BUS_DEVICE_RESET.
+		 */
+		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
+		/* Store for host */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, DINDEX;
+		} else {
+			mov	DFDAT, DINDEX;
+		}
+
+		/* Remember for disconnection decision */
+		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
+		/* XXX Honor per target settings too */
+		or	SEQ_FLAGS, NO_DISCONNECT;
+
+		test	SCSISIGI, ATNI	jz	ident_messages_done;
+		call	target_inb;
+		/*
+		 * If this is a tagged request, the tagged message must
+		 * immediately follow the identify.  We test for a valid
+		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
+		 * < MSG_IGN_WIDE_RESIDUE.
+		 */
+		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;
+		jnc	ident_messages_done;
+		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
+		jc	ident_messages_done;
+		/* Store for host */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, DINDEX;
+		} else {
+			mov	DFDAT, DINDEX;
+		}
+		
+		/*
+		 * If the initiator doesn't feel like providing a tag number,
+		 * we've got a failed selection and must transition to bus
+		 * free.
+		 */
+		test	SCSISIGI, ATNI	jz	target_busfree;
+
+		/*
+		 * Store the tag for the host.
+		 */
+		call	target_inb;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, DINDEX;
+		} else {
+			mov	DFDAT, DINDEX;
+		}
+		mov	INITIATOR_TAG, DINDEX;
+		or	SEQ_FLAGS, TARGET_CMD_IS_TAGGED;
+		test	SCSISIGI, ATNI	jz . + 2;
+		/* Initiator still wants to give us messages */
+		call	target_inb;
+		jmp	ident_messages_done;
+
+		/*
+		 * Pushed message loop to allow the kernel to
+		 * run it's own target mode message state engine.
+		 */
+host_target_message_loop:
+		mvi	HOST_MSG_LOOP call set_seqint;
+		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;
+		test	SSTAT0, SPIORDY jz .;
+		jmp	host_target_message_loop;
+
+ident_messages_done:
+		/* If ring buffer is full, return busy or queue full */
+		if ((ahc->features & AHC_HS_MAILBOX) != 0) {
+			and	A, HOST_TQINPOS, HS_MAILBOX;
+		} else {
+			mov	A, KERNEL_TQINPOS;
+		}
+		cmp	TQINPOS, A jne tqinfifo_has_space;
+		mvi	P_STATUS|BSYO call change_phase;
+		test	SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3;
+		mvi	STATUS_QUEUE_FULL call target_outb;
+		jmp	target_busfree_wait;
+		mvi	STATUS_BUSY call target_outb;
+		jmp	target_busfree_wait;
+tqinfifo_has_space:	
+		/* Terminate the ident list */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mvi	CCSCBRAM, SCB_LIST_NULL;
+		} else {
+			mvi	DFDAT, SCB_LIST_NULL;
+		}
+		or	SEQ_FLAGS, TARG_CMD_PENDING|IDENTIFY_SEEN;
+		test	SCSISIGI, ATNI	jnz target_mesgout_pending;
+		jmp	target_ITloop;
+	}
+
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
+ */
+initiator_reselect:
+	/* XXX test for and handle ONE BIT condition */
+	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
+	and	SAVED_SCSIID, SELID_MASK, SELID;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		and	A, OID, SCSIID_ULTRA2;
+	} else {
+		and	A, OID, SCSIID;
+	}
+	or	SAVED_SCSIID, A;
+	if ((ahc->features & AHC_TWIN) != 0) {
+		test	SBLKCTL, SELBUSB	jz . + 2;
+		or	SAVED_SCSIID, TWIN_CHNLB;
+	}
+	mvi	CLRSINT0, CLRSELDI;
+	jmp	ITloop;
+}
+
+abort_qinscb:
+	call	add_scb_to_free_list;
+	jmp	poll_for_work_loop;
 
 start_selection:
-	if ((p->features & AHC_TWIN) != 0) {
+	/*
+	 * If bus reset interrupts have been disabled (from a previous
+	 * reset), re-enable them now.  Resets are only of interest
+	 * when we have outstanding transactions, so we can safely
+	 * defer re-enabling the interrupt until, as an initiator,
+	 * we start sending out transactions again.
+	 */
+	test	SIMODE1, ENSCSIRST	jnz . + 3;
+	mvi	CLRSINT1, CLRSCSIRSTI;
+	or	SIMODE1, ENSCSIRST;
+	if ((ahc->features & AHC_TWIN) != 0) {
 		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
-		and	A,SELBUSB,SCB_TCL;	/* Get new channel bit */
-		or	SINDEX,A;
+		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
+		or	SINDEX, SELBUSB;
 		mov	SBLKCTL,SINDEX;		/* select channel */
 	}
 initialize_scsiid:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		and	A, TID, SCB_TCL;	/* Get target ID */
-		and	SCSIID_ULTRA2, OID;	/* Clear old target */
-		or	SCSIID_ULTRA2, A;
-	} else {
-		and	A, TID, SCB_TCL;	/* Get target ID */
-		and	SCSIID, OID;		/* Clear old target */
-		or	SCSIID, A;
-	}
-	mov	SCSIDATL, ALLZEROS;		/* clear out the latched */
-						/* data register, this */
-						/* fixes a bug on some */
-						/* controllers where the */
-						/* last byte written to */
-						/* this register can leak */
-						/* onto the data bus at */
-						/* bad times, such as during */
-						/* selection timeouts */
-	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mov	SCSIID_ULTRA2, SCB_SCSIID;
+	} else if ((ahc->features & AHC_TWIN) != 0) {
+		and	SCSIID, TWIN_TID|OID, SCB_SCSIID;
+	} else {
+		mov	SCSIID, SCB_SCSIID;
+	}
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		mov	SINDEX, SCSISEQ_TEMPLATE;
+		test	SCB_CONTROL, TARGET_SCB jz . + 2;
+		or	SINDEX, TEMODE;
+		mov	SCSISEQ, SINDEX ret;
+	} else {
+		mov	SCSISEQ, SCSISEQ_TEMPLATE ret;
+	}
 
 /*
- * Initialize Ultra mode setting and clear the SCSI channel.
+ * Initialize transfer settings and clear the SCSI channel.
  * SINDEX should contain any additional bit's the client wants
- * set in SXFRCTL0.
+ * set in SXFRCTL0.  We also assume that the current SCB is
+ * a valid SCB for the target we wish to talk to.
  */
 initialize_channel:
-	or	SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
-	if ((p->features & AHC_ULTRA) != 0) {
-ultra:
-		mvi	SINDEX, ULTRA_ENB+1;
-		test	SAVED_TCL, 0x80		jnz ultra_2; /* Target ID > 7 */
-		dec	SINDEX;
-ultra_2:
-		mov     FUNCTION1,SAVED_TCL;
-		mov     A,FUNCTION1;
-		test	SINDIR, A	jz ndx_dtr;
+	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
+set_transfer_settings:
+	if ((ahc->features & AHC_ULTRA) != 0) {
+		test	SCB_CONTROL, ULTRAENB jz . + 2;
 		or	SXFRCTL0, FAST20;
 	} 
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCSIRATE.
- */
-ndx_dtr:
-	shr	A,4,SAVED_TCL;
-	if ((p->features & AHC_TWIN) != 0) {
-		test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
-		or	SAVED_TCL, SELBUSB; 
-		or	A,0x08;			/* Channel B entries add 8 */
-ndx_dtr_2:
-	}
-
-	if ((p->features & AHC_ULTRA2) != 0) {
-		add	SINDEX, TARG_OFFSET, A;
-		mov	SCSIOFFSET, SINDIR;
+	/*
+	 * Initialize SCSIRATE with the appropriate value for this target.
+	 */
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;
+	} else {
+		mov	SCSIRATE, SCB_SCSIRATE ret;
 	}
 
-	add	SINDEX,TARG_SCSIRATE,A;
-	mov	SCSIRATE,SINDIR ret;
-
-
-selection:
-	test	SSTAT0,SELDO	jnz select_out;
+if ((ahc->flags & AHC_TARGETROLE) != 0) {
 /*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target yet.
+ * We carefully toggle SPIOEN to allow us to return the 
+ * message byte we receive so it can be checked prior to
+ * driving REQ on the bus for the next byte.
  */
-initiator_reselect:
-	mvi	CLRSINT0, CLRSELDI;
-	/* XXX test for and handle ONE BIT condition */
-	and	SAVED_TCL, SELID_MASK, SELID;
-	mvi	CLRSINT1,CLRBUSFREE;
-	or	SIMODE1, ENBUSFREE;		/*
-						 * We aren't expecting a
-						 * bus free, so interrupt
-						 * the kernel driver if it
-						 * happens.
-						 */
-	mvi	SPIOEN call	initialize_channel;
-	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */
-	jmp	ITloop;
+target_inb:
+	/*
+	 * Drive REQ on the bus by enabling SCSI PIO.
+	 */
+	or	SXFRCTL0, SPIOEN;
+	/* Wait for the byte */
+	test	SSTAT0, SPIORDY jz .;
+	/* Prevent our read from triggering another REQ */
+	and	SXFRCTL0, ~SPIOEN;
+	/* Save latched contents */
+	mov	DINDEX, SCSIDATL ret;
+}
 
 /*
  * After the selection, remove this SCB from the "waiting SCB"
@@ -259,33 +443,198 @@
  */
 select_out:
 	/* Turn off the selection hardware */
-	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
-						 * ATN on parity errors
-						 * for "in" phases
-						 */
+	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
 	mvi	CLRSINT0, CLRSELDO;
 	mov	SCBPTR, WAITING_SCBH;
 	mov	WAITING_SCBH,SCB_NEXT;
-	mov	SAVED_TCL, SCB_TCL;
-	mvi	CLRSINT1,CLRBUSFREE;
-	or	SIMODE1, ENBUSFREE;		/*
-						 * We aren't expecting a
-						 * bus free, so interrupt
-						 * the kernel driver if it
-						 * happens.
-						 */
-	mvi	SPIOEN call	initialize_channel;
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted.
- */
+	mov	SAVED_SCSIID, SCB_SCSIID;
+	mov	SAVED_LUN, SCB_LUN;
+	call	initialize_channel;
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		test	SSTAT0, TARGET	jz initiator_select;
+
+		/*
+		 * We've just re-selected an initiator.
+		 * Assert BSY and setup the phase for
+		 * sending our identify messages.
+		 */
+		mvi	P_MESGIN|BSYO call change_phase;
+
+		/*
+		 * Start out with a simple identify message.
+		 */
+		or	SCB_LUN, MSG_IDENTIFYFLAG call target_outb;
+
+		/*
+		 * If we are the result of a tagged command, send
+		 * a simple Q tag and the tag id.
+		 */
+		test	SCB_CONTROL, TAG_ENB	jz . + 3;
+		mvi	MSG_SIMPLE_Q_TAG call target_outb;
+		mov	SCB_TARGET_INFO[SCB_INITIATOR_TAG] call target_outb;
+target_synccmd:
+		/*
+		 * Now determine what phases the host wants us
+		 * to go through.
+		 */
+		mov	SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES];
+		
+target_ITloop:
+		/*
+		 * Start honoring ATN signals now that
+		 * we properly identified ourselves.
+		 */
+		test	SCSISIGI, ATNI			jnz target_mesgout;
+		test	SEQ_FLAGS, CMDPHASE_PENDING	jnz target_cmdphase;
+		test	SEQ_FLAGS, DPHASE_PENDING	jnz target_dphase;
+		test	SEQ_FLAGS, SPHASE_PENDING	jnz target_sphase;
+
+		/*
+		 * No more work to do.  Either disconnect or not depending
+		 * on the state of NO_DISCONNECT.
+		 */
+		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 
+		if ((ahc->flags & AHC_PAGESCBS) != 0) {
+			mov	ALLZEROS	call	get_free_or_disc_scb;
+		}
+		mov	RETURN_1, ALLZEROS;
+		call	complete_target_cmd;
+		cmp	RETURN_1, CONT_MSG_LOOP jne .;
+		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+		mov	SCB_TAG	 call dma_scb;
+		jmp	target_synccmd;
+
+target_mesgout:
+		mvi	SCSISIGO, P_MESGOUT|BSYO;
+target_mesgout_continue:
+		call	target_inb;
+target_mesgout_pending:
+		/* Local Processing goes here... */
+		jmp	host_target_message_loop;
+		
+target_disconnect:
+		mvi	P_MESGIN|BSYO call change_phase;
+		test	SEQ_FLAGS, DPHASE	jz . + 2;
+		mvi	MSG_SAVEDATAPOINTER call target_outb;
+		mvi	MSG_DISCONNECT call target_outb;
+
+target_busfree_wait:
+		/* Wait for preceeding I/O session to complete. */
+		test	SCSISIGI, ACKI jnz .;
+target_busfree:
+		and	SIMODE1, ~ENBUSFREE;
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			clr	SCSIBUSL;
+		}
+		clr	SCSISIGO;
+		mvi	LASTPHASE, P_BUSFREE;
+		call	complete_target_cmd;
+		jmp	poll_for_work;
+
+target_cmdphase:
+		mvi	P_COMMAND|BSYO call change_phase;
+		call	target_inb;
+		mov	A, DINDEX;
+		/* Store for host */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, A;
+		} else {
+			mov	DFDAT, A;
+		}
+
+		/*
+		 * Determine the number of bytes to read
+		 * based on the command group code via table lookup.
+		 * We reuse the first 8 bytes of the TARG_SCSIRATE
+		 * BIOS array for this table. Count is one less than
+		 * the total for the command since we've already fetched
+		 * the first byte.
+		 */
+		shr	A, CMD_GROUP_CODE_SHIFT;
+		add	SINDEX, CMDSIZE_TABLE, A;
+		mov	A, SINDIR;
+
+		test	A, 0xFF jz command_phase_done;
+		or	SXFRCTL0, SPIOEN;
+command_loop:
+		test	SSTAT0, SPIORDY jz .;
+		cmp	A, 1 jne . + 2;
+		and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, SCSIDATL;
+		} else {
+			mov	DFDAT, SCSIDATL;
+		}
+		dec	A;
+		test	A, 0xFF jnz command_loop;
+
+command_phase_done:
+		and	SEQ_FLAGS, ~CMDPHASE_PENDING;
+		jmp	target_ITloop;
+
+target_dphase:
+		/*
+		 * Data phases on the bus are from the
+		 * perspective of the initiator.  The dma
+		 * code looks at LASTPHASE to determine the
+		 * data direction of the DMA.  Toggle it for
+		 * target transfers.
+		 */
+		xor	LASTPHASE, IOI, SCB_TARGET_INFO[SCB_TARGET_DATA_DIR];
+		or	SCB_TARGET_INFO[SCB_TARGET_DATA_DIR], BSYO
+			call change_phase;
+		jmp	p_data;
+
+target_sphase:
+		mvi	P_STATUS|BSYO call change_phase;
+		mvi	LASTPHASE, P_STATUS;
+		mov	SCB_TARGET_INFO[SCB_TARGET_STATUS] call target_outb;
+		/* XXX Watch for ATN or parity errors??? */
+		mvi	SCSISIGO, P_MESGIN|BSYO;
+		/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
+		mov	ALLZEROS call target_outb;
+		jmp	target_busfree_wait;
+	
+complete_target_cmd:
+		test	SEQ_FLAGS, TARG_CMD_PENDING	jnz . + 2;
+		mov	SCB_TAG jmp complete_post;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			/* Set the valid byte */
+			mvi	CCSCBADDR, 24;
+			mov	CCSCBRAM, ALLONES;
+			mvi	CCHCNT, 28;
+			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			test	CCSCBCTL, CCSCBDONE jz .;
+			clr	CCSCBCTL;
+		} else {
+			/* Set the valid byte */
+			or	DFCNTRL, FIFORESET;
+			mvi	DFWADDR, 3; /* Third 64bit word or byte 24 */
+			mov	DFDAT, ALLONES;
+			mvi	28	call set_hcnt;
+			or	DFCNTRL, HDMAEN|FIFOFLUSH;
+			call	dma_finish;
+		}
+		inc	TQINPOS;
+		mvi	INTSTAT,CMDCMPLT ret;
+	}
+
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+initiator_select:
+	/*
+	 * As soon as we get a successful selection, the target
+	 * should go into the message out phase since we have ATN
+	 * asserted.
+	 */
 	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
 	or	SEQ_FLAGS, IDENTIFY_SEEN;
 
-/*
- * Main loop for information transfer phases.  Wait for the target
- * to assert REQ before checking MSG, C/D and I/O for the bus phase.
- */
+	/*
+	 * Main loop for information transfer phases.  Wait for the
+	 * target to assert REQ before checking MSG, C/D and I/O for
+	 * the bus phase.
+	 */
+mesgin_phasemis:
 ITloop:
 	call	phase_lock;
 
@@ -297,17 +646,20 @@
 	cmp	A,P_STATUS	je p_status;
 	cmp	A,P_MESGIN	je p_mesgin;
 
-	mvi	INTSTAT,BAD_PHASE;	/* unknown phase - signal driver */
+	mvi	BAD_PHASE call set_seqint;
 	jmp	ITloop;			/* Try reading the bus again. */
 
 await_busfree:
 	and	SIMODE1, ~ENBUSFREE;
-	call	clear_target_state;
 	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		clr	SCSIBUSL;	/* Prevent bit leakage durint SELTO */
+	}
 	and	SXFRCTL0, ~SPIOEN;
 	test	SSTAT1,REQINIT|BUSFREE	jz .;
 	test	SSTAT1, BUSFREE jnz poll_for_work;
-	mvi	INTSTAT, BAD_PHASE;
+	mvi	MISSED_BUSFREE call set_seqint;
+}
 	
 clear_target_state:
 	/*
@@ -316,42 +668,160 @@
 	 * clear DFCNTRL too.
 	 */
 	clr	DFCNTRL;
+	or	SXFRCTL0, CLRSTCNT|CLRCHN;
 
 	/*
 	 * We don't know the target we will connect to,
 	 * so default to narrow transfers to avoid
 	 * parity problems.
 	 */
-	if ((p->features & AHC_ULTRA2) != 0) {
-		bmov    SCSIRATE, ALLZEROS, 2;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	SCSIRATE, ALLZEROS, 2;
 	} else {
-		clr     SCSIRATE;
-		and     SXFRCTL0, ~(FAST20);
+		clr	SCSIRATE;
+		if ((ahc->features & AHC_ULTRA) != 0) {
+			and	SXFRCTL0, ~(FAST20);
+		}
 	}
 	mvi	LASTPHASE, P_BUSFREE;
 	/* clear target specific flags */
 	clr	SEQ_FLAGS ret;
 
+sg_advance:
+	clr	A;			/* add sizeof(struct scatter) */
+	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
+	adc	SCB_RESIDUAL_SGPTR[1],A;
+	adc	SCB_RESIDUAL_SGPTR[2],A;
+	adc	SCB_RESIDUAL_SGPTR[3],A ret;
+
+if ((ahc->features & AHC_CMD_CHAN) != 0) {
+disable_ccsgen:
+	test	CCSGCTL, CCSGEN jz return;
+	test	CCSGCTL, CCSGDONE jz .;
+disable_ccsgen_fetch_done:
+	clr	CCSGCTL;
+	test	CCSGCTL, CCSGEN jnz .;
+	ret;
+idle_loop:
+	/* Did we just finish fetching segs? */
+	cmp	CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
+
+	/* Are we actively fetching segments? */
+	test	CCSGCTL, CCSGEN jnz return;
+
+	/*
+	 * Do we need any more segments?
+	 */
+	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
+
+	/*
+	 * Do we have any prefetch left???
+	 */
+	cmp	CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
+
+	/*
+	 * Need to fetch segments, but we can only do that
+	 * if the command channel is completely idle.  Make
+	 * sure we don't have an SCB prefetch going on.
+	 */
+	test	CCSCBCTL, CCSCBEN jnz return;
+
+	/*
+	 * We fetch a "cacheline aligned" and sized amount of data
+	 * so we don't end up referencing a non-existant page.
+	 * Cacheline aligned is in quotes because the kernel will
+	 * set the prefetch amount to a reasonable level if the
+	 * cacheline size is unknown.
+	 */
+	mvi	CCHCNT, SG_PREFETCH_CNT;
+	and	CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
+	bmov	CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
+	mvi	CCSGCTL, CCSGEN|CCSGRESET ret;
+idle_sgfetch_complete:
+	call	disable_ccsgen_fetch_done;
+	and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
+idle_sg_avail:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		/* Does the hardware have space for another SG entry? */
+		test	DFSTATUS, PRELOAD_AVAIL jz return;
+		bmov 	HADDR, CCSGRAM, 4;
+		bmov	SINDEX, CCSGRAM, 1;
+		test	SINDEX, 0x1 jz . + 2;
+		xor	DATA_COUNT_ODD, 0x1;
+		bmov	HCNT[0], SINDEX, 1;
+		bmov	HCNT[1], CCSGRAM, 2;
+		bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
+		call	sg_advance;
+		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
+		test	DATA_COUNT_ODD, 0x1 jz . + 2;
+		or	SINDEX, ODD_SEG;
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
+		or	SINDEX, LAST_SEG;
+		mov	SG_CACHE_PRE, SINDEX;
+		/* Load the segment by writing DFCNTRL again */
+		mov	DFCNTRL, DMAPARAMS;
+	}
+	ret;
+}
+
+if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
+/*
+ * Calculate the trailing portion of this S/G segment that cannot
+ * be transferred using memory write and invalidate PCI transactions.  
+ * XXX Can we optimize this for PCI writes only???
+ */
+calc_mwi_residual:
+	/*
+	 * If the ending address is on a cacheline boundary,
+	 * there is no need for an extra segment.
+	 */
+	mov	A, HCNT[0];
+	add	A, A, HADDR[0];
+	and	A, CACHESIZE_MASK;
+	test	A, 0xFF jz return;
+
+	/*
+	 * If the transfer is less than a cachline,
+	 * there is no need for an extra segment.
+	 */
+	test	HCNT[1], 0xFF	jnz calc_mwi_residual_final;
+	test	HCNT[2], 0xFF	jnz calc_mwi_residual_final;
+	add	NONE, INVERTED_CACHESIZE_MASK, HCNT[0];
+	jnc	return;
+
+calc_mwi_residual_final:
+	mov	MWI_RESIDUAL, A;
+	not	A;
+	inc	A;
+	add	HCNT[0], A;
+	adc	HCNT[1], -1;
+	adc	HCNT[2], -1 ret;
+}
+
 /*
  * If we re-enter the data phase after going through another phase, the
  * STCNT may have been cleared, so restore it from the residual field.
  */
 data_phase_reinit:
-	if ((p->features & AHC_ULTRA2) != 0) {
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		/*
+		 * The preload circuitry requires us to
+		 * reload the address too, so pull it from
+		 * the shaddow address.
+		 */
 		bmov	HADDR, SHADDR, 4;
-		bmov    HCNT, SCB_RESID_DCNT, 3;
-	}
-	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
-		bmov    STCNT, SCB_RESID_DCNT, 3;
-	}
-	if ((p->features & AHC_CMD_CHAN) == 0) {
+		bmov	HCNT, SCB_RESIDUAL_DATACNT, 3;
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	STCNT, SCB_RESIDUAL_DATACNT, 3;
+	} else {
 		mvi	DINDEX, STCNT;
-		mvi	SCB_RESID_DCNT	call bcopy_3;
+		mvi	SCB_RESIDUAL_DATACNT call bcopy_3;
 	}
+	and	DATA_COUNT_ODD, 0x1, SCB_RESIDUAL_DATACNT[0];
 	jmp	data_phase_loop;
 
 p_data:
-	if ((p->features & AHC_ULTRA2) != 0) {
+	if ((ahc->features & AHC_ULTRA2) != 0) {
 		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
 	} else {
 		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
@@ -362,8 +832,9 @@
 					 * Ensure entering a data
 					 * phase is okay - seen identify, etc.
 					 */
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		mvi	CCSGADDR, CCSGADDR_MAX;
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		/* We don't have any valid S/G elements */
+		mvi	CCSGADDR, SG_PREFETCH_CNT;
 	}
 	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
 
@@ -372,256 +843,471 @@
 
 	/*
 	 * Initialize the DMA address and counter from the SCB.
-	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
-	 * modify the values in the SCB itself until we see a
-	 * save data pointers message.
+	 * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG
+	 * flag in the highest byte of the data count.  We cannot
+	 * modify the saved values in the SCB until we see a save
+	 * data pointers message.
 	 */
-	if ((p->features & AHC_CMD_CHAN) != 0) {
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
 		bmov	HADDR, SCB_DATAPTR, 7;
-		bmov    STCNT, HCNT, 3;
-		bmov    SG_COUNT, SCB_SGCOUNT, 5;
+		bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
 	} else {
 		mvi	DINDEX, HADDR;
 		mvi	SCB_DATAPTR	call bcopy_7;
-		call	set_stcnt_from_hcnt;
-		mvi	DINDEX, SG_COUNT;
-		mvi	SCB_SGCOUNT	call bcopy_5;
+		mvi	DINDEX, SCB_RESIDUAL_DATACNT + 3;
+		mvi	SCB_DATACNT + 3 call bcopy_5;
+	}
+	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
+		call	calc_mwi_residual;
+	}
+	and	SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
+	and	DATA_COUNT_ODD, 0x1, HCNT[0];
+
+	if ((ahc->features & AHC_ULTRA2) == 0) {
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			bmov	STCNT, HCNT, 3;
+		} else {
+			call	set_stcnt_from_hcnt;
+		}
 	}
 
 data_phase_loop:
-/* Guard against overruns */
-	test	SG_COUNT, 0xff jnz data_phase_inbounds;
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
+	/* Guard against overruns */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds;
+
+	/*
+	 * Turn on `Bit Bucket' mode, wait until the target takes
+	 * us to another phase, and then notify the host.
+	 */
+	and	DMAPARAMS, DIRECTION;
+	mov	DFCNTRL, DMAPARAMS;
 	or	SXFRCTL1,BITBUCKET;
-	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		if ((p->features & AHC_ULTRA2) != 0) {
-			bmov	HCNT, ALLONES, 3;
-		}
-		bmov	STCNT, ALLONES, 3;
-	} else {
-		mvi	STCNT[0], 0xFF;
-		mvi	STCNT[1], 0xFF;
-		mvi	STCNT[2], 0xFF;
-	}
+	test	SSTAT1,PHASEMIS	jz .;
+	and	SXFRCTL1, ~BITBUCKET;
+	mvi	DATA_OVERRUN call set_seqint;
+	jmp	ITloop;
+
 data_phase_inbounds:
-/* If we are the last SG block, tell the hardware. */
-	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
-	if ((p->features & AHC_ULTRA2) == 0) {
-		and	DMAPARAMS, ~WIDEODD;
-	} else {
-		mvi	SG_CACHEPTR, LAST_SEG;
-	}
-data_phase_wideodd:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		mov	SINDEX, ALLONES;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
+		or	SINDEX, LAST_SEG;
+		test	DATA_COUNT_ODD, 0x1 jz . + 2;
+		or	SINDEX, ODD_SEG;
+		mov	SG_CACHE_PRE, SINDEX;
 		mov	DFCNTRL, DMAPARAMS;
-		test	SSTAT0, SDONE jnz .;
-data_phase_dma_loop:
-		test	SSTAT0, SDONE jnz data_phase_dma_done;
-		test	SSTAT1,PHASEMIS	jz data_phase_dma_loop;	/* ie. underrun */
-data_phase_dma_phasemis:
-		test	SSTAT0,SDONE	jnz data_phase_dma_done;
-		clr	SINDEX;			/* Remember the phasemiss */
-	} else {
-		mov	DMAPARAMS  call dma;
-	}
+ultra2_dma_loop:
+		call	idle_loop;
+		/*
+		 * The transfer is complete if either the last segment
+		 * completes or the target changes phase.
+		 */
+		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
+		if ((ahc->flags & AHC_TARGETROLE) != 0) {
+			 /*
+			  * As a target, we control the phases,
+			  * so ignore PHASEMIS.
+			  */
+			test	SSTAT0, TARGET jnz ultra2_dma_loop;
+		}
+		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+			test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
+		}
 
-data_phase_dma_done:
-/* Go tell the host about any overruns */
-	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+ultra2_dmafinish:
+		test	DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
+		if ((ahc->features & AHC_DT) == 0) {
+			and	DFCNTRL, ~SCSIEN;
+			test	DFCNTRL, SCSIEN jnz .;
+		}
+ultra2_dmafifoflush:
+		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
+			/*
+			 * On Rev A of the aic7890, the autoflush
+			 * features doesn't function correctly.
+			 * Perform an explicit manual flush.  During
+			 * a manual flush, the FIFOEMP bit becomes
+			 * true every time the PCI FIFO empties
+			 * regardless of the state of the SCSI FIFO.
+			 * It can take up to 4 clock cycles for the
+			 * SCSI FIFO to get data into the PCI FIFO
+			 * and for FIFOEMP to de-assert.  Here we
+			 * guard against this condition by making
+			 * sure the FIFOEMP bit stays on for 5 full
+			 * clock cycles.
+			 */
+			or	DFCNTRL, FIFOFLUSH;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		}
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+ultra2_dmafifoempty:
+		/* Don't clobber an inprogress host data transfer */
+		test	DFSTATUS, MREQPEND	jnz ultra2_dmafifoempty;
+ultra2_dmahalt:
+		and     DFCNTRL, ~(SCSIEN|HDMAEN);
+		test	DFCNTRL, HDMAEN jnz .;
 
-/* Exit if we had an underrun.  dma clears SINDEX in this case. */
-	test	SINDEX,0xff	jz data_phase_finish;
+		/*
+		 * If, by chance, we stopped before being able
+		 * to fetch additional segments for this transfer,
+		 * yet the last S/G was completely exhausted,
+		 * call our idle loop until it is able to load
+		 * another segment.  This will allow us to immediately
+		 * pickup on the next segment on the next data phase.
+		 *
+		 * If we happened to stop on the last segment, then
+		 * our residual information is still correct from
+		 * the idle loop and there is no need to perform
+		 * any fixups.  Just jump to data_phase_finish.
+		 */
+ultra2_ensure_sg:
+		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
+		/* Record if we've consumed all S/G entries */
+		test	SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish;
+		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
+		jmp	data_phase_finish;
+
+ultra2_shvalid:
+                test    SSTAT2, SHVALID	jnz sgptr_fixup;
+		call	idle_loop;
+		jmp	ultra2_ensure_sg;
 
-/*
- * Advance the scatter-gather pointers if needed 
- */
-sg_advance:
-	dec	SG_COUNT;	/* one less segment to go */
+sgptr_fixup:
+		/*
+		 * Fixup the residual next S/G pointer.  The S/G preload
+		 * feature of the chip allows us to load two elements
+		 * in addition to the currently active element.  We
+		 * store the bottom byte of the next S/G pointer in
+		 * the SG_CACEPTR register so we can restore the
+		 * correct value when the DMA completes.  If the next
+		 * sg ptr value has advanced to the point where higher
+		 * bytes in the address have been affected, fix them
+		 * too.
+		 */
+		test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
+		test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
+		add	SCB_RESIDUAL_SGPTR[1], -1;
+		adc	SCB_RESIDUAL_SGPTR[2], -1; 
+		adc	SCB_RESIDUAL_SGPTR[3], -1;
+sgptr_fixup_done:
+		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
+		clr	DATA_COUNT_ODD;
+		test	SG_CACHE_SHADOW, ODD_SEG jz . + 2;
+		or	DATA_COUNT_ODD, 0x1;
+		clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
+	} else {
+		/* If we are the last SG block, tell the hardware. */
+		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+		  && ahc->pci_cachesize != 0) {
+			test	MWI_RESIDUAL, 0xFF jnz dma_mid_sg;
+		}
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
+		if ((ahc->flags & AHC_TARGETROLE) != 0) {
+			test	SSTAT0, TARGET jz dma_last_sg;
+			if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) {
+				test	DMAPARAMS, DIRECTION jz dma_mid_sg;
+			}
+		}
+dma_last_sg:
+		and	DMAPARAMS, ~WIDEODD;
+dma_mid_sg:
+		/* Start DMA data transfer. */
+		mov	DFCNTRL, DMAPARAMS;
+dma_loop:
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			call	idle_loop;
+		}
+		test	SSTAT0,DMADONE	jnz dma_dmadone;
+		test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
+dma_phasemis:
+		/*
+		 * We will be "done" DMAing when the transfer count goes to
+		 * zero, or the target changes the phase (in light of this,
+		 * it makes sense that the DMA circuitry doesn't ACK when
+		 * PHASEMIS is active).  If we are doing a SCSI->Host transfer,
+		 * the data FIFO should be flushed auto-magically on STCNT=0
+		 * or a phase change, so just wait for FIFO empty status.
+		 */
+dma_checkfifo:
+		test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
+dma_fifoflush:
+		test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
+dma_fifoempty:
+		/* Don't clobber an inprogress host data transfer */
+		test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
 
-	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
-	if ((p->features & AHC_CMD_CHAN) != 0) {
 		/*
-		 * Do we have any prefetch left???
+		 * Now shut off the DMA and make sure that the DMA
+		 * hardware has actually stopped.  Touching the DMA
+		 * counters, etc. while a DMA is active will result
+		 * in an ILLSADDR exception.
+		 */
+dma_dmadone:
+		and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+		/*
+		 * Some revisions of the aic78XX have a problem where, if the
+		 * data fifo is full, but the PCI input latch is not empty, 
+		 * HDMAEN cannot be cleared.  The fix used here is to drain
+		 * the prefetched but unused data from the data fifo until
+		 * there is space for the input latch to drain.
 		 */
-		cmp	CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
+			mov	NONE, DFDAT;
+		}
+		test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+
+		/* See if we have completed this last segment */
+		test	STCNT[0], 0xff	jnz data_phase_finish;
+		test	STCNT[1], 0xff	jnz data_phase_finish;
+		test	STCNT[2], 0xff	jnz data_phase_finish;
 
 		/*
-		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
+		 * Advance the scatter-gather pointers if needed 
 		 */
-		add	A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
-		mvi	A, CCSGADDR_MAX;
-		jc	. + 2;
-		shl	A, 3, SG_COUNT;
-		mov	CCHCNT, A;
-		bmov	CCHADDR, SG_NEXT, 4;
-		mvi	CCSGCTL, CCSGEN|CCSGRESET;
-		test	CCSGCTL, CCSGDONE jz .;
-		and	CCSGCTL, ~CCSGEN;
-		test	CCSGCTL, CCSGEN jnz .;
-		mvi	CCSGCTL, CCSGRESET;
-prefetched_segs_avail:
-		bmov 	HADDR, CCSGRAM, 8;
-		if ((p->features & AHC_ULTRA2) == 0) {
-			bmov    STCNT, HCNT, 3;
+		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+		  && ahc->pci_cachesize != 0) {
+			test	MWI_RESIDUAL, 0xFF jz no_mwi_resid;
+			/*
+			 * Reload HADDR from SHADDR and setup the
+			 * count to be the size of our residual.
+			 */
+			if ((ahc->features & AHC_CMD_CHAN) != 0) {
+				bmov	HADDR, SHADDR, 4;
+				mov	HCNT, MWI_RESIDUAL;
+				bmov	HCNT[1], ALLZEROS, 2;
+			} else {
+				mvi	DINDEX, HADDR;
+				mvi	SHADDR call bcopy_4;
+				mov	MWI_RESIDUAL call set_hcnt;
+			}
+			clr	MWI_RESIDUAL;
+			jmp	sg_load_done;
+no_mwi_resid:
 		}
-	} else {
-		mvi	DINDEX, HADDR;
-		mvi	SG_NEXT	call bcopy_4;
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
+		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
+		jmp	data_phase_finish;
+sg_load:
+		/*
+		 * Load the next SG element's data address and length
+		 * into the DMA engine.  If we don't have hardware
+		 * to perform a prefetch, we'll have to fetch the
+		 * segment from host memory first.
+		 */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			/* Wait for the idle loop to complete */
+			test	CCSGCTL, CCSGEN jz . + 3;
+			call	idle_loop;
+			test	CCSGCTL, CCSGEN jnz . - 1;
+			bmov 	HADDR, CCSGRAM, 7;
+			test	CCSGRAM, SG_LAST_SEG jz . + 2;
+			or	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG;
+		} else {
+			mvi	DINDEX, HADDR;
+			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;
 
-		mvi	HCNT[0],SG_SIZEOF;
-		clr	HCNT[1];
-		clr	HCNT[2];
+			mvi	SG_SIZEOF	call set_hcnt;
 
-		or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
 
-		call	dma_finish;
+			call	dma_finish;
 
-		/*
-		 * Copy data from FIFO into SCB data pointer and data count.
-		 * This assumes that the SG segments are of the form:
-		 * struct ahc_dma_seg {
-		 *	u_int32_t	addr;	four bytes, little-endian order
-		 *	u_int32_t	len;	four bytes, little endian order
-		 * };
-		 */
-		mvi	HADDR	call dfdat_in_7;
-		call	set_stcnt_from_hcnt;
-	}
+			mvi	DINDEX, HADDR;
+			call	dfdat_in_7;
+			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;
+		}
 
-/* Advance the SG pointer */
-	clr	A;			/* add sizeof(struct scatter) */
-	add	SG_NEXT[0],SG_SIZEOF;
-	adc	SG_NEXT[1],A;
+		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+		  && ahc->pci_cachesize != 0) {
+			call calc_mwi_residual;
+		}
 
-	test    SSTAT1, REQINIT jz .;
-	test	SSTAT1,PHASEMIS	jz data_phase_loop;
+		/* Point to the new next sg in memory */
+		call	sg_advance;
 
-/* This drops the last SG segment down to the shadow layer for us */
-	if ((p->features & AHC_ULTRA2) != 0) {
-		mov	DFCNTRL, DMAPARAMS;
-		test	SSTAT0, SDONE	jnz .;
-	}
+sg_load_done:
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			bmov	STCNT, HCNT, 3;
+		} else {
+			call	set_stcnt_from_hcnt;
+		}
+		/* Track odd'ness */
+		test	HCNT[0], 0x1 jz . + 2;
+		xor	DATA_COUNT_ODD, 0x1;
 
+		if ((ahc->flags & AHC_TARGETROLE) != 0) {
+			test	SSTAT0, TARGET jnz data_phase_loop;
+		}
+	}
 data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
- * were transferred on the SCSI (as opposed to the host) bus.
- */
-	if ((p->features & AHC_ULTRA2) != 0) {
-		call	ultra2_dmafinish;
-	}
-	if ((p->features & AHC_ULTRA2) == 0) {
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov    SCB_RESID_DCNT, STCNT, 3;
-			mov	SCB_RESID_SGCNT, SG_COUNT;
-		} else {
-			mov	SCB_RESID_DCNT[0],STCNT[0];
-			mov	SCB_RESID_DCNT[1],STCNT[1];
-			mov	SCB_RESID_DCNT[2],STCNT[2];
-			mov	SCB_RESID_SGCNT, SG_COUNT;
+	/*
+	 * If the target has left us in data phase, loop through
+	 * the dma code again.  In the case of ULTRA2 adapters,
+	 * we should only loop if there is a data overrun.  For
+	 * all other adapters, we'll loop after each S/G element
+	 * is loaded as well as if there is an overrun.
+	 */
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		test	SSTAT0, TARGET jnz data_phase_done;
+	}
+	if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+		test	SSTAT1, REQINIT jz .;
+		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	}
+
+data_phase_done:
+	/*
+	 * After a DMA finishes, save the SG and STCNT residuals back into
+	 * the SCB.  We use STCNT instead of HCNT, since it's a reflection
+	 * of how many bytes were transferred on the SCSI (as opposed to the
+	 * host) bus.
+	 */
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		/* Kill off any pending prefetch */
+		call	disable_ccsgen;
+	}
+
+	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+	  && ahc->pci_cachesize != 0) {
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			test	MWI_RESIDUAL, 0xFF jz bmov_resid;
+		}
+		mov	A, MWI_RESIDUAL;
+		add	SCB_RESIDUAL_DATACNT[0], A, STCNT[0];
+		clr	A;
+		adc	SCB_RESIDUAL_DATACNT[1], A, STCNT[1];
+		adc	SCB_RESIDUAL_DATACNT[2], A, STCNT[2];
+		clr	MWI_RESIDUAL;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			jmp	. + 2;
+bmov_resid:
+			bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
 		}
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
+	} else {
+		mov	SCB_RESIDUAL_DATACNT[0], STCNT[0];
+		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];
+		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];
 	}
 
-	jmp	ITloop;
+	/*
+	 * Since we've been through a data phase, the SCB_RESID* fields
+	 * are now initialized.  Clear the full residual flag.
+	 */
+	and	SCB_SGPTR[0], ~SG_FULL_RESID;
 
-data_phase_overrun:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		call	ultra2_dmafinish;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		/* Clear the channel in case we return to data phase later */
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
 	}
-/*
- * Turn off BITBUCKET mode and notify the host
- */
-	and	SXFRCTL1, ~BITBUCKET;
-	mvi	INTSTAT,DATA_OVERRUN;
-	jmp	ITloop;
 
-ultra2_dmafinish:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
-		and	DFCNTRL, ~SCSIEN;
-		test	DFCNTRL, SCSIEN jnz .;
-ultra2_dmafifoflush:
-		or	DFCNTRL, FIFOFLUSH;
-		test	DFSTATUS, FIFOEMP jz . - 1;
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
+		and	SEQ_FLAGS, ~DPHASE_PENDING;
 		/*
-		 * hardware bug alert!  This needless set of jumps is to
-		 * protect against a FIFOEMP status bit glitch in the
-		 * silicon.
+		 * For data-in phases, wait for any pending acks from the
+		 * initiator before changing phase.
 		 */
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, MREQPEND	jnz .;
-ultra2_dmahalt:
-		test	SCSIOFFSET, 0x7f	jnz ultra2_shutdown;
-ultra2_await_nreq:
-		test	SCSISIGI, REQI	jz ultra2_shutdown;
-		test	SSTAT1, (PHASEMIS|REQINIT)	jz ultra2_await_nreq;
-ultra2_shutdown:
-		and     DFCNTRL, ~(HDMAEN|SCSIEN);
-		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
-		bmov	SCB_RESID_DCNT, STCNT, 3;
-		mov	SCB_RESID_SGCNT, SG_COUNT;
-		or	SXFRCTL0, CLRSTCNT|CLRCHN;
-		ret;
+		test	DFCNTRL, DIRECTION jz target_ITloop;
+		test	SSTAT1, REQINIT	jnz .;
+		jmp	target_ITloop;
+	} else {
+		jmp	ITloop;
 	}
 
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
 /*
  * Command phase.  Set up the DMA registers and let 'er rip.
  */
 p_command:
 	call	assert;
 
-/*
- * Load HADDR and HCNT.
- */
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		bmov	HADDR, SCB_CMDPTR, 5;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	HCNT[0], SCB_CDB_LEN,  1;
 		bmov	HCNT[1], ALLZEROS, 2;
-		if ((p->features & AHC_ULTRA2) == 0) {
-			bmov	STCNT, HCNT, 3;
-		}
+		mvi	SG_CACHE_PRE, LAST_SEG;
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	STCNT[0], SCB_CDB_LEN, 1;
+		bmov	STCNT[1], ALLZEROS, 2;
 	} else {
-		mvi	DINDEX, HADDR;
-		mvi	SCB_CMDPTR	call bcopy_5;
-		clr	HCNT[1];
-		clr	HCNT[2];
-		call	set_stcnt_from_hcnt;
+		mov	STCNT[0], SCB_CDB_LEN;
+		clr	STCNT[1];
+		clr	STCNT[2];
+	}
+	add	NONE, -13, SCB_CDB_LEN;
+	mvi	SCB_CDB_STORE jnc p_command_embedded;
+p_command_from_host:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	HADDR[0], SCB_CDB_PTR, 4;
+		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+	} else {
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			bmov	HADDR[0], SCB_CDB_PTR, 4;
+			bmov	HCNT, STCNT, 3;
+		} else {
+			mvi	DINDEX, HADDR;
+			mvi	SCB_CDB_PTR call bcopy_4;
+			mov	SCB_CDB_LEN call set_hcnt;
+		}
+		mvi	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
 	}
-
-	if ((p->features & AHC_ULTRA2) == 0) {
-		mvi	(SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+	jmp	p_command_loop;
+p_command_embedded:
+	/*
+	 * The data fifo seems to require 4 byte alligned
+	 * transfers from the sequencer.  Force this to
+	 * be the case by clearing HADDR[0] even though
+	 * we aren't going to touch host memeory.
+	 */
+	clr	HADDR[0];
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mvi	DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
+		bmov	DFDAT, SCB_CDB_STORE, 12; 
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			/*
+			 * On the 7895 the data FIFO will
+			 * get corrupted if you try to dump
+			 * data from external SCB memory into
+			 * the FIFO while it is enabled.  So,
+			 * fill the fifo and then enable SCSI
+			 * transfers.
+			 */
+			mvi	DFCNTRL, (DIRECTION|FIFORESET);
+		} else {
+			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
+		}
+		bmov	DFDAT, SCB_CDB_STORE, 12; 
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH);
+		} else {
+			or	DFCNTRL, FIFOFLUSH;
+		}
 	} else {
-		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
-		test	SSTAT0, SDONE jnz .;
-p_command_dma_loop:
-		test	SSTAT0, SDONE jnz p_command_ultra2_dma_done;
-		test	SSTAT1,PHASEMIS	jz p_command_dma_loop;	/* ie. underrun */
-p_command_ultra2_dma_done:
-		test	SCSISIGI, REQI	jz p_command_ultra2_shutdown;
-		test	SSTAT1, (PHASEMIS|REQINIT)	jz p_command_ultra2_dma_done;
-p_command_ultra2_shutdown:
-		and     DFCNTRL, ~(HDMAEN|SCSIEN);
-		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
-		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
+		call	copy_to_fifo_6;
+		call	copy_to_fifo_6;
+		or	DFCNTRL, FIFOFLUSH;
+	}
+p_command_loop:
+	test	SSTAT0, SDONE jnz . + 2;
+	test    SSTAT1, PHASEMIS jz p_command_loop;
+	/*
+	 * Wait for our ACK to go-away on it's own
+	 * instead of being killed by SCSIEN getting cleared.
+	 */
+	test	SCSISIGI, ACKI jnz .;
+	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		/* Drop any residual from the S/G Preload queue */
+		or	SXFRCTL0, CLRSTCNT;
 	}
 	jmp	ITloop;
 
@@ -632,21 +1318,26 @@
 p_status:
 	call	assert;
 
-	mov	SCB_TARGET_STATUS, SCSIDATL;
+	mov	SCB_SCSI_STATUS, SCSIDATL;
 	jmp	ITloop;
 
 /*
- * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
- * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
- * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
- * it's own message.
+ * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
+ * indentify message sequence and send it to the target.  The host may
+ * override this behavior by setting the MK_MESSAGE bit in the SCB
+ * control byte.  This will cause us to interrupt the host and allow
+ * it to handle the message phase completely on its own.  If the bit
+ * associated with this target is set, we will also interrupt the host,
+ * thereby allowing it to send a message on the next selection regardless
+ * of the transaction being sent.
  * 
  * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
- * This is done to allow the hsot to send messages outside of an identify
+ * This is done to allow the host to send messages outside of an identify
  * sequence while protecting the seqencer from testing the MK_MESSAGE bit
  * on an SCB that might not be for the current nexus. (For example, a
  * BDR message in responce to a bad reselection would leave us pointed to
  * an SCB that doesn't have anything to do with the current target).
+ *
  * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
  * bus device reset).
  *
@@ -655,23 +1346,27 @@
  * reason.
  */
 p_mesgout_retry:
-	or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
 p_mesgout:
 	mov	SINDEX, MSG_OUT;
 	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
-p_mesgout_identify:
-	if ((p->features & AHC_WIDE) != 0) {
-		and	SINDEX,0xf,SCB_TCL;	/* lun */
-	} else {
-		and	SINDEX,0x7,SCB_TCL;	/* lun */
+	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
+	mov	FUNCTION1, SCB_SCSIID;
+	mov	A, FUNCTION1;
+	mov	SINDEX, TARGET_MSG_REQUEST[0];
+	if ((ahc->features & AHC_TWIN) != 0) {
+		/* Second Channel uses high byte bits */
+		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
+		mov	SINDEX, TARGET_MSG_REQUEST[1];
+	} else if ((ahc->features & AHC_WIDE) != 0) {
+		test	SCB_SCSIID, 0x80	jz . + 2; /* target > 7 */
+		mov	SINDEX, TARGET_MSG_REQUEST[1];
 	}
-	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
-	or	SINDEX,A;		/* or in disconnect privledge */
-	or	SINDEX,MSG_IDENTIFYFLAG;
-p_mesgout_mk_message:
-	test	SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
-	mov	SCSIDATL, SINDEX;	/* Send the last byte */
-	jmp	p_mesgout_from_host + 1;/* Skip HOST_MSG test */
+	test	SINDEX, A	jnz host_message_loop;
+p_mesgout_identify:
+	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
+	test	SCB_CONTROL, DISCENB jnz . + 2;
+	and	SINDEX, ~DISCENB;
 /*
  * Send a tag message if TAG_ENB is set in the SCB control block.
  * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
@@ -686,34 +1381,27 @@
 	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
 	mov	SCB_TAG	jmp p_mesgout_onebyte;
 /*
- * Interrupt the driver, and allow it to send a message
- * if it asks.
+ * Interrupt the driver, and allow it to handle this message
+ * phase and any required retries.
  */
 p_mesgout_from_host:
 	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
-	mvi     INTSTAT,AWAITING_MSG;
-	nop;
-	/*
-	 * Did the host detect a phase change?
-	 */
-	cmp	RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+	jmp	host_message_loop;
 
 p_mesgout_onebyte:
 	mvi	CLRSINT1, CLRATNO;
 	mov	SCSIDATL, SINDEX;
 
 /*
- * If the next bus phase after ATN drops is a message out, it means
+ * If the next bus phase after ATN drops is message out, it means
  * that the target is requesting that the last message(s) be resent.
  */
 	call	phase_lock;
-	cmp     LASTPHASE, P_MESGOUT    je p_mesgout_retry;
+	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
 
 p_mesgout_done:
 	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
 	mov	LAST_MSG, MSG_OUT;
-	cmp	MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
-	and	SCB_CONTROL, ~MK_MESSAGE;
 	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
 	jmp	ITloop;
 
@@ -728,113 +1416,137 @@
 	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
 	cmp	ALLZEROS,A		je mesgin_complete;
 	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
-	cmp	A,MSG_EXTENDED		je mesgin_extended;
-	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject;
+	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_ign_wide_residue;
 	cmp	A,MSG_NOOP		je mesgin_done;
-	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_wide_residue;
 
-rej_mesgin:
 /*
- * We have no idea what this message in is, so we issue a message reject
- * and hope for the best.  In any case, rejection should be a rare
- * occurrence - signal the driver when it happens.
+ * Pushed message loop to allow the kernel to
+ * run it's own message state engine.  To avoid an
+ * extra nop instruction after signaling the kernel,
+ * we perform the phase_lock before checking to see
+ * if we should exit the loop and skip the phase_lock
+ * in the ITloop.  Performing back to back phase_locks
+ * shouldn't hurt, but why do it twice...
  */
-	mvi	INTSTAT,SEND_REJECT;		/* let driver know */
+host_message_loop:
+	mvi	HOST_MSG_LOOP call set_seqint;
+	call	phase_lock;
+	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop + 1;
+	jmp	host_message_loop;
 
-	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
+mesgin_ign_wide_residue:
+if ((ahc->features & AHC_WIDE) != 0) {
+	test	SCSIRATE, WIDEXFER jz mesgin_reject;
+	/* Pull the residue byte */
+	mvi	ARG_1	call inb_next;
+	cmp	ARG_1, 0x01 jne mesgin_reject;
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
+	test	DATA_COUNT_ODD, 0x1	jz mesgin_done;
+	mvi	IGN_WIDE_RES call set_seqint;
+	jmp	mesgin_done;
+}
 
+mesgin_reject:
+	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
 mesgin_done:
 	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
 	jmp	ITloop;
 
-
 mesgin_complete:
 /*
- * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * We received a "command complete" message.  Put the SCB_TAG into the QOUTFIFO,
  * and trigger a completion interrupt.  Before doing so, check to see if there
  * is a residual or the status byte is something other than STATUS_GOOD (0).
  * In either of these conditions, we upload the SCB back to the host so it can
  * process this information.  In the case of a non zero status byte, we 
  * additionally interrupt the kernel driver synchronously, allowing it to
  * decide if sense should be retrieved.  If the kernel driver wishes to request
- * sense, it will fill the kernel SCB with a request sense command and set
- * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
- * the SCB, and process it as the next command by adding it to the waiting list.
- * If the kernel driver does not wish to request sense, it need only clear
- * RETURN_1, and the command is allowed to complete normally.  We don't bother
- * to post to the QOUTFIFO in the error cases since it would require extra
- * work in the kernel driver to ensure that the entry was removed before the
- * command complete code tried processing it.
+ * sense, it will fill the kernel SCB with a request sense command, requeue
+ * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
+ * RETURN_1 to SEND_SENSE.
+ */
+
+/*
+ * If ATN is raised, we still want to give the target a message.
+ * Perhaps there was a parity error on this last message byte.
+ * Either way, the target should take us to message out phase
+ * and then attempt to complete the command again.  We should use a
+ * critical section here to guard against a timeout triggering
+ * for this command and setting ATN while we are still processing
+ * the completion.
+	test	SCSISIGI, ATNI jnz mesgin_done;
  */
 
 /*
- * First check for residuals
+ * See if we attempted to deliver a message but the target ingnored us.
  */
-	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
-	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Good Status? */
+	test	SCB_CONTROL, MK_MESSAGE jz . + 2;
+	mvi	MKMSG_FAILED call set_seqint;
+
+/*
+ * Check for residuals
+ */
+	test	SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
+	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
+	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
+check_status:
+	test	SCB_SCSI_STATUS,0xff	jz complete;	/* Good Status? */
 upload_scb:
+	or	SCB_SGPTR, SG_RESID_VALID;
 	mvi	DMAPARAMS, FIFORESET;
 	mov	SCB_TAG		call dma_scb;
-check_status:
-	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Just a residual? */
-	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
-	nop;
+	test	SCB_SCSI_STATUS, 0xff	jz complete;	/* Just a residual? */
+	mvi	BAD_STATUS call set_seqint;		/* let driver know */
 	cmp	RETURN_1, SEND_SENSE	jne complete;
-	/* This SCB becomes the next to execute as it will retrieve sense */
-	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-	mov	SCB_TAG		call dma_scb;
-add_to_waiting_list:
-	mov	SCB_NEXT,WAITING_SCBH;
-	mov	WAITING_SCBH, SCBPTR;
-	/*
-	 * Prepare our selection hardware before the busfree so we have a
-	 * high probability of winning arbitration.
-	 */
-	call	start_selection;
+	call	add_scb_to_free_list;
 	jmp	await_busfree;
-
 complete:
-	/* If we are untagged, clear our address up in host ram */
-	test	SCB_CONTROL, TAG_ENB jnz complete_post;
-	mov	A, SAVED_TCL;
-	mvi	UNTAGGEDSCB_OFFSET call post_byte_setup;
-	mvi	SCB_LIST_NULL call post_byte;
+	mov	SCB_TAG call complete_post;
+	jmp	await_busfree;
+}
 
 complete_post:
-	/* Post the SCB and issue an interrupt */
-	if ((p->features & AHC_QUEUE_REGS) != 0) {
+	/* Post the SCBID in SINDEX and issue an interrupt */
+	call	add_scb_to_free_list;
+	mov	ARG_1, SINDEX;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
 		mov	A, SDSCB_QOFF;
 	} else {
 		mov	A, QOUTPOS;
 	}
 	mvi	QOUTFIFO_OFFSET call post_byte_setup;
-	mov	SCB_TAG call post_byte;
-	if ((p->features & AHC_QUEUE_REGS) == 0) {
+	mov	ARG_1 call post_byte;
+	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
 		inc 	QOUTPOS;
 	}
-	mvi	INTSTAT,CMDCMPLT;
-
-add_to_free_list:
-	call	add_scb_to_free_list;
-	jmp	await_busfree;
-
-/*
- * Is it an extended message?  Copy the message to our message buffer and
- * notify the host.  The host will tell us whether to reject this message,
- * respond to it with the message that the host placed in our message buffer,
- * or simply to do nothing.
- */
-mesgin_extended:
-	mvi	INTSTAT,EXTENDED_MSG;		/* let driver know */
-	jmp	ITloop;
+	mvi	INTSTAT,CMDCMPLT ret;
 
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
- * and await the bus going free.
+ * and await the bus going free.  If this is an untagged transaction
+ * store the SCB id for it in our untagged target table for lookup on
+ * a reselction.
  */
 mesgin_disconnect:
+	/*
+	 * If ATN is raised, we still want to give the target a message.
+	 * Perhaps there was a parity error on this last message byte
+	 * or we want to abort this command.  Either way, the target
+	 * should take us to message out phase and then attempt to
+	 * disconnect again.
+	 * XXX - Wait for more testing.
+	test	SCSISIGI, ATNI jnz mesgin_done;
+	 */
+
 	or	SCB_CONTROL,DISCONNECTED;
-	call	add_scb_to_disc_list;
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		call	add_scb_to_disc_list;
+	}
+	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
+	mov	ARG_1, SCB_TAG;
+	mov	SAVED_LUN, SCB_LUN;
+	mov	SCB_SCSIID	call set_busy_target;
 	jmp	await_busfree;
 
 /*
@@ -846,22 +1558,20 @@
  */
 mesgin_sdptrs:
 	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
+
 	/*
-	 * The SCB SGPTR becomes the next one we'll download,
-	 * and the SCB DATAPTR becomes the current SHADDR.
+	 * The SCB_SGPTR becomes the next one we'll download,
+	 * and the SCB_DATAPTR becomes the current SHADDR.
 	 * Use the residual number since STCNT is corrupted by
 	 * any message transfer.
 	 */
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		bmov    SCB_SGCOUNT, SG_COUNT, 5;
-		bmov    SCB_DATAPTR, SHADDR, 4;
-		bmov    SCB_DATACNT, SCB_RESID_DCNT, 3;
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	SCB_DATAPTR, SHADDR, 4;
+		bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
 	} else {
-		mvi	DINDEX, SCB_SGCOUNT;
-		mvi	SG_COUNT	call bcopy_5;
 		mvi	DINDEX, SCB_DATAPTR;
-		mvi	SHADDR		call bcopy_4;
-		mvi	SCB_RESID_DCNT	call	bcopy_3;
+		mvi	SHADDR call bcopy_4;
+		mvi	SCB_RESIDUAL_DATACNT call bcopy_8;
 	}
 	jmp	mesgin_done;
 
@@ -880,109 +1590,166 @@
 	jmp	mesgin_done;
 
 /*
+ * Index into our Busy Target table.  SINDEX and DINDEX are modified
+ * upon return.  SCBPTR may be modified by this action.
+ */
+set_busy_target:
+	shr	DINDEX, 4, SINDEX;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		mov	SCBPTR, SAVED_LUN;
+		add	DINDEX, SCB_64_BTT;
+	} else {
+		add	DINDEX, BUSY_TARGETS;
+	}
+	mov	DINDIR, ARG_1 ret;
+
+/*
  * Identify message?  For a reconnecting target, this tells us the lun
  * that the reconnection is for - find the correct SCB and switch to it,
  * clearing the "disconnected" bit so we don't "find" it by accident later.
  */
 mesgin_identify:
-	
-	if ((p->features & AHC_WIDE) != 0) {
-		and	A,0x0f;		/* lun in lower four bits */
+	/*
+	 * Determine whether a target is using tagged or non-tagged
+	 * transactions by first looking at the transaction stored in
+	 * the busy target array.  If there is no untagged transaction
+	 * for this target or the transaction is for a different lun, then
+	 * this must be an untagged transaction.
+	 */
+	shr	SINDEX, 4, SAVED_SCSIID;
+	and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		add	SINDEX, SCB_64_BTT;
+		mov	SCBPTR, SAVED_LUN;
+		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+			add	NONE, -SCB_64_BTT, SINDEX;
+			jc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+			add	NONE, -(SCB_64_BTT + 16), SINDEX;
+			jnc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+		}
 	} else {
-		and	A,0x07;		/* lun in lower three bits */
+		add	SINDEX, BUSY_TARGETS;
+		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+			add	NONE, -BUSY_TARGETS, SINDEX;
+			jc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+			add	NONE, -(BUSY_TARGETS + 16), SINDEX;
+			jnc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+		}
 	}
-	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
-
-	mvi     ARG_2, SCB_LIST_NULL;   /* SCBID of prev SCB in disc List */
-	call	get_untagged_SCBID;
+	mov	ARG_1, SINDIR;
 	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
-	if ((p->flags & AHC_PAGESCBS) != 0) {
-		test	SEQ_FLAGS, SCBPTR_VALID	jz use_retrieveSCB;
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		mov	ARG_1 call findSCB;
+	} else {
+		mov	SCBPTR, ARG_1;
 	}
-	/*
-	 * If the SCB was found in the disconnected list (as is
-	 * always the case in non-paging scenarios), SCBPTR is already
-	 * set to the correct SCB.  So, simply setup the SCB and get
-	 * on with things.
-	 */
-	mov	SCBPTR	call rem_scb_from_disc_list;
-	jmp	setup_SCB;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		jmp setup_SCB_id_lun_okay;
+	} else {
+		/*
+		 * We only allow one untagged command per-target
+		 * at a time.  So, if the lun doesn't match, look
+		 * for a tag message.
+		 */
+		mov	A, SCB_LUN;
+		cmp	SAVED_LUN, A	je setup_SCB_id_lun_okay;
+		if ((ahc->flags & AHC_PAGESCBS) != 0) {
+			/*
+			 * findSCB removes the SCB from the
+			 * disconnected list, so we must replace
+			 * it there should this SCB be for another
+			 * lun.
+			 */
+			call	cleanup_scb;
+		}
+	}
+
 /*
  * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
  * If we get one, we use the tag returned to find the proper
- * SCB.  With SCB paging, this requires using search for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
+ * SCB.  With SCB paging, we must search for non-tagged
+ * transactions since the SCB may exist in any slot.  If we're not
+ * using SCB paging, we can use the tag as the direct index to the
+ * SCB.
  */
 snoop_tag:
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x80;
+	}
 	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
-snoop_tag_loop:
 	call	phase_lock;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x1;
+	}
 	cmp	LASTPHASE, P_MESGIN	jne not_found;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x2;
+	}
 	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
 get_tag:
-	mvi	ARG_1	call inb_next;	/* tag value */
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		mvi	ARG_1	call inb_next;	/* tag value */
+		mov	ARG_1	call findSCB;
+	} else {
+		mvi	ARG_1	call inb_next;	/* tag value */
+		mov	SCBPTR, ARG_1;
+	}
 
-use_retrieveSCB:
-	call	retrieveSCB;
+/*
+ * Ensure that the SCB the tag points to is for
+ * an SCB transaction to the reconnecting target.
+ */
 setup_SCB:
-	mov	A, SAVED_TCL;
-	cmp	SCB_TCL, A	jne not_found_cleanup_scb;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x4;
+	}
+	mov	A, SCB_SCSIID;
+	cmp	SAVED_SCSIID, A	jne not_found_cleanup_scb;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x8;
+	}
+setup_SCB_id_okay:
+	mov	A, SCB_LUN;
+	cmp	SAVED_LUN, A	jne not_found_cleanup_scb;
+setup_SCB_id_lun_okay:
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x10;
+	}
 	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
 	and	SCB_CONTROL,~DISCONNECTED;
-	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
+	test	SCB_CONTROL, TAG_ENB	jnz setup_SCB_tagged;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		mov	A, SCBPTR;
+	}
+	mvi	ARG_1, SCB_LIST_NULL;
+	mov	SAVED_SCSIID	call	set_busy_target;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		mov	SCBPTR, A;
+	}
+setup_SCB_tagged:
+	mvi	SEQ_FLAGS,IDENTIFY_SEEN;	/* make note of IDENTIFY */
+	call	set_transfer_settings;
 	/* See if the host wants to send a message upon reconnection */
 	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
-	and	SCB_CONTROL, ~MK_MESSAGE;
 	mvi	HOST_MSG	call mk_mesg;
 	jmp	mesgin_done;
 
 not_found_cleanup_scb:
-	test	SCB_CONTROL, DISCONNECTED jz . + 3;
-	call	add_scb_to_disc_list;
-	jmp	not_found;
-	call	add_scb_to_free_list;
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		call	cleanup_scb;
+	}
 not_found:
-	mvi	INTSTAT, NO_MATCH;
-	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
-	jmp	mesgin_done;
-
-/*
- * Message reject?  Let the kernel driver handle this.  If we have an 
- * outstanding WDTR or SDTR negotiation, assume that it's a response from 
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
-	mvi	INTSTAT, REJECT_MSG;
-	jmp	mesgin_done;
-
-/*
- * Wide Residue.  We handle the simple cases, but pass of the one hard case
- * to the kernel (when the residue byte happened to cause us to advance our
- * sg element array, so we know have to back that advance out).
- */
-mesgin_wide_residue:
-	mvi	ARG_1	call inb_next; /* ACK the wide_residue and get */
-				       /* the size byte */
-/*
- * In order for this to be reliable, we have to do all sorts of horrible
- * magic in terms of resetting the datafifo and reloading the shadow layer
- * with the correct new values (so that a subsequent save data pointers
- * message will do the right thing).  We let the kernel do that work.
- */
- 	mvi	INTSTAT, WIDE_RESIDUE;
+	mvi	NO_MATCH call set_seqint;
 	jmp	mesgin_done;
-	
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
 
-/*
- * Locking the driver out, build a one-byte message passed in SINDEX
- * if there is no active message already.  SINDEX is returned intact.
- */
 mk_mesg:
 	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
 	mov	MSG_OUT,SINDEX ret;
@@ -1002,7 +1769,9 @@
  * and that REQ is already set when inb_first is called.  inb_{first,next}
  * use the same calling convention as inb.
  */
-
+inb_next_wait_perr:
+	mvi	PERR_DETECTED call set_seqint;
+	jmp	inb_next_wait;
 inb_next:
 	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
 inb_next_wait:
@@ -1012,7 +1781,8 @@
 	 * before continuing.
 	 */
 	test	SSTAT1, REQINIT	jz inb_next_wait;
-	test	SSTAT1, SCSIPERR jnz .;
+	test	SSTAT1, SCSIPERR jnz inb_next_wait_perr;
+inb_next_check_phase:
 	and	LASTPHASE, PHASE_MASK, SCSISIGI;
 	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
 inb_first:
@@ -1020,71 +1790,48 @@
 	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
 inb_last:
 	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
+}
 
-mesgin_phasemis:
+if ((ahc->flags & AHC_TARGETROLE) != 0) {
 /*
- * We expected to receive another byte, but the target changed phase
+ * Change to a new phase.  If we are changing the state of the I/O signal,
+ * from out to in, wait an additional data release delay before continuing.
  */
-	mvi	INTSTAT, MSGIN_PHASEMIS;
-	jmp	ITloop;
-
-/*
- * DMA data transfer.  HADDR and HCNT must be loaded first, and
- * SINDEX should contain the value to load DFCNTRL with - 0x3d for
- * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
- * during initialization.
- */
-if ((p->features & AHC_ULTRA2) == 0) {
-dma:
-	mov	DFCNTRL,SINDEX;
-dma_loop:
-	test	SSTAT0,DMADONE	jnz dma_dmadone;
-	test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
-dma_phasemis:
-	test	SSTAT0,SDONE	jnz dma_checkfifo;
-	mov	SINDEX,ALLZEROS;		/* Notify caller of phasemiss */
+change_phase:
+	/* Wait for preceeding I/O session to complete. */
+	test	SCSISIGI, ACKI jnz .;
+
+	/* Change the phase */
+	and	DINDEX, IOI, SCSISIGI;
+	mov	SCSISIGO, SINDEX;
+	and	A, IOI, SINDEX;
 
-/*
- * We will be "done" DMAing when the transfer count goes to zero, or
- * the target changes the phase (in light of this, it makes sense that
- * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
- * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
- * magically on STCNT=0 or a phase change, so just wait for FIFO empty
- * status.
- */
-dma_checkfifo:
-	test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
-dma_fifoflush:
-	test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
+	/*
+	 * If the data direction has changed, from
+	 * out (initiator driving) to in (target driving),
+	 * we must wait at least a data release delay plus
+	 * the normal bus settle delay. [SCSI III SPI 10.11.0]
+	 */
+	cmp 	DINDEX, A je change_phase_wait;
+	test	SINDEX, IOI jz change_phase_wait;
+	call	change_phase_wait;
+change_phase_wait:
+	nop;
+	nop;
+	nop;
+	nop ret;
 
-dma_fifoempty:
-	/* Don't clobber an inprogress host data transfer */
-	test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
 /*
- * Now shut the DMA enables off and make sure that the DMA enables are 
- * actually off first lest we get an ILLSADDR.
+ * Send a byte to an initiator in Automatic PIO mode.
  */
-dma_dmadone:
-	cmp	LASTPHASE, P_COMMAND	je dma_await_nreq;
-	test	SCSIRATE, 0x0f	jnz dma_shutdown;
-dma_await_nreq:
-	test	SCSISIGI, REQI	jz dma_shutdown;
-	test	SSTAT1, (PHASEMIS|REQINIT)	jz dma_await_nreq;
-dma_shutdown:
-	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
-dma_halt:
-	/*
-	 * Some revisions of the aic7880 have a problem where, if the
-	 * data fifo is full, but the PCI input latch is not empty, 
-	 * HDMAEN cannot be cleared.  The fix used here is to attempt
-	 * to drain the data fifo until there is space for the input
-	 * latch to drain and HDMAEN de-asserts.
-	 */
-	mov	NONE, DFDAT;
-	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+target_outb:
+	or	SXFRCTL0, SPIOEN;
+	test	SSTAT0, SPIORDY	jz .;
+	mov	SCSIDATL, SINDEX;
+	test	SSTAT0, SPIORDY	jz .;
+	and	SXFRCTL0, ~SPIOEN ret;
 }
-return:
-	ret;
+	
 
 /*
  * Assert that if we've been reselected, then we've seen an IDENTIFY
@@ -1093,138 +1840,69 @@
 assert:
 	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
 
-	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
+	mvi	NO_IDENT jmp set_seqint;	/* no - tell the kernel */
 
 /*
- * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBID ARG_1.  The search begins at the SCB index passed in
- * via SINDEX which is an SCB that must be on the disconnected list.  If
- * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
- * is set to the proper SCB.
+ * Locate a disconnected SCB by SCBID.  Upon return, SCBPTR and SINDEX will
+ * be set to the position of the SCB.  If the SCB cannot be found locally,
+ * it will be paged in from host memory.  RETURN_2 stores the address of the
+ * preceding SCB in the disconnected list which can be used to speed up
+ * removal of the found SCB from the disconnected list.
  */
+if ((ahc->flags & AHC_PAGESCBS) != 0) {
+BEGIN_CRITICAL
 findSCB:
-	mov	SCBPTR,SINDEX;			/* Initialize SCBPTR */
-	cmp	ARG_1, SCB_LIST_NULL	jne findSCB_by_SCBID;
-	mov	A, SAVED_TCL;
-	mvi	SCB_TCL	jmp findSCB_loop;	/* &SCB_TCL -> SINDEX */
-findSCB_by_SCBID:
-	mov	A, ARG_1;			/* Tag passed in ARG_1 */
-	mvi	SCB_TAG	jmp findSCB_loop;	/* &SCB_TAG -> SINDEX */
+	mov	A, SINDEX;			/* Tag passed in SINDEX */
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound;
+	mov	SCBPTR, DISCONNECTED_SCBH;	/* Initialize SCBPTR */
+	mvi	ARG_2, SCB_LIST_NULL;		/* Head of list */
+	jmp	findSCB_loop;
 findSCB_next:
-	mov     ARG_2, SCBPTR;
-	cmp	SCB_NEXT, SCB_LIST_NULL je notFound;
+	cmp	SCB_NEXT, SCB_LIST_NULL je findSCB_notFound;
+	mov	ARG_2, SCBPTR;
 	mov	SCBPTR,SCB_NEXT;
-	dec	SINDEX;		/* Last comparison moved us too far */
 findSCB_loop:
-	cmp	SINDIR, A	jne findSCB_next;
-	mov	SINDEX, SCBPTR 	ret;
-notFound:
-	mvi	SINDEX, SCB_LIST_NULL	ret;
-
-/*
- * Retrieve an SCB by SCBID first searching the disconnected list falling
- * back to DMA'ing the SCB down from the host.  This routine assumes that
- * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
- * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
- * we go directly to the host for the SCB.
- */
-retrieveSCB:
-	test	SEQ_FLAGS, SCBPTR_VALID	jz retrieve_from_host;
-	mov	SCBPTR	call findSCB;	/* Continue the search */
-	cmp	SINDEX, SCB_LIST_NULL	je retrieve_from_host;
-
-/*
- * This routine expects SINDEX to contain the index of the SCB to be
- * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
- * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
- * if it is at the head.
- */
+	cmp	SCB_TAG, A	jne findSCB_next;
 rem_scb_from_disc_list:
-/* Remove this SCB from the disconnection list */
-	cmp     ARG_2, SCB_LIST_NULL    je rHead;
+	cmp	ARG_2, SCB_LIST_NULL	je rHead;
 	mov	DINDEX, SCB_NEXT;
+	mov	SINDEX, SCBPTR;
 	mov	SCBPTR, ARG_2;
 	mov	SCB_NEXT, DINDEX;
 	mov	SCBPTR, SINDEX ret;
 rHead:
 	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
-
-retrieve_from_host:
-/*
- * We didn't find it.  Pull an SCB and DMA down the one we want.
- * We should never get here in the non-paging case.
- */
-	mov	ALLZEROS	call	get_free_or_disc_scb;
+END_CRITICAL
+findSCB_notFound:
+	/*
+	 * We didn't find it.  Page in the SCB.
+	 */
+	mov	ARG_1, A; /* Save tag */
+	mov	ALLZEROS call get_free_or_disc_scb;
 	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-	/* Jump instead of call as we want to return anyway */
 	mov	ARG_1	jmp dma_scb;
-
-/*
- * Determine whether a target is using tagged or non-tagged transactions
- * by first looking for a matching transaction based on the TCL and if
- * that fails, looking up this device in the host's untagged SCB array.
- * The TCL to search for is assumed to be in SAVED_TCL.  The value is
- * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
- * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
- * in an SCB instead of having to go to the host.
- */
-get_untagged_SCBID:
-	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
-	mvi	ARG_1, SCB_LIST_NULL;
-	mov	DISCONNECTED_SCBH call findSCB;
-	cmp	SINDEX, SCB_LIST_NULL	je get_SCBID_from_host;
-	or	SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
-	test	SCB_CONTROL, TAG_ENB	jnz . + 2;
-	mov	ARG_1, SCB_TAG	ret;
-	mvi	ARG_1, SCB_LIST_NULL ret;
-
-/*
- * Fetch a byte from host memory given an index of (A + (256 * SINDEX))
- * and a base address of SCBID_ADDR.  The byte is returned in RETURN_2.
- */
-fetch_byte:
-	mov	ARG_2, SINDEX;
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		mvi	DINDEX, CCHADDR;
-		mvi	SCBID_ADDR call set_1byte_addr;
-		mvi	CCHCNT, 1;
-		mvi	CCSGCTL, CCSGEN|CCSGRESET;
-		test	CCSGCTL, CCSGDONE jz .;
-		mvi	CCSGCTL, CCSGRESET;
-		bmov	RETURN_2, CCSGRAM, 1 ret;
-	} else {
-		mvi	DINDEX, HADDR;
-		mvi	SCBID_ADDR call set_1byte_addr;
-		mvi	HCNT[0], 1;
-		clr	HCNT[1];
-		clr	HCNT[2];
-		mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
-		call	dma_finish;
-		mov	RETURN_2, DFDAT ret;
-	}
+}
 
 /*
  * Prepare the hardware to post a byte to host memory given an
- * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
+ * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR.
  */
 post_byte_setup:
 	mov	ARG_2, SINDEX;
-	if ((p->features & AHC_CMD_CHAN) != 0) {
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
 		mvi	DINDEX, CCHADDR;
-		mvi	SCBID_ADDR call	set_1byte_addr;
+		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
 		mvi	CCHCNT, 1;
 		mvi	CCSCBCTL, CCSCBRESET ret;
 	} else {
 		mvi	DINDEX, HADDR;
-		mvi	SCBID_ADDR call	set_1byte_addr;
-		mvi	HCNT[0], 1;
-		clr	HCNT[1];
-		clr	HCNT[2];
+		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
+		mvi	1	call set_hcnt;
 		mvi	DFCNTRL, FIFORESET ret;
 	}
 
 post_byte:
-	if ((p->features & AHC_CMD_CHAN) != 0) {
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
 		bmov	CCSCBRAM, SINDEX, 1;
 		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
 		test	CCSCBCTL, CCSCBDONE jz .;
@@ -1235,23 +1913,34 @@
 		jmp	dma_finish;
 	}
 
-get_SCBID_from_host:
-	mov	A, SAVED_TCL;
-	mvi	UNTAGGEDSCB_OFFSET call fetch_byte;
-	mov	RETURN_1,  RETURN_2 ret;
-
+phase_lock_perr:
+	mvi	PERR_DETECTED call set_seqint;
 phase_lock:     
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
 	test	SSTAT1, REQINIT jz phase_lock;
-	test	SSTAT1, SCSIPERR jnz phase_lock;
+	test	SSTAT1, SCSIPERR jnz phase_lock_perr;
+phase_lock_latch_phase:
 	and	SCSISIGO, PHASE_MASK, SCSISIGI;
 	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
 
-if ((p->features & AHC_CMD_CHAN) == 0) {
+if ((ahc->features & AHC_CMD_CHAN) == 0) {
+set_hcnt:
+	mov	HCNT[0], SINDEX;
+clear_hcnt:
+	clr	HCNT[1];
+	clr	HCNT[2] ret;
+
 set_stcnt_from_hcnt:
 	mov	STCNT[0], HCNT[0];
 	mov	STCNT[1], HCNT[1];
 	mov	STCNT[2], HCNT[2] ret;
 
+bcopy_8:
+	mov	DINDIR, SINDIR;
 bcopy_7:
 	mov	DINDIR, SINDIR;
 	mov	DINDIR, SINDIR;
@@ -1265,6 +1954,7 @@
 	mov	DINDIR, SINDIR ret;
 }
 
+if ((ahc->flags & AHC_TARGETROLE) != 0) {
 /*
  * Setup addr assuming that A is an index into
  * an array of 32byte objects, SINDEX contains
@@ -1275,16 +1965,30 @@
 set_32byte_addr:
 	shr	ARG_2, 3, A;
 	shl	A, 5;
+	jmp	set_1byte_addr;
+}
+
+/*
+ * Setup addr assuming that A is an index into
+ * an array of 64byte objects, SINDEX contains
+ * the base address of that array, and DINDEX
+ * contains the base address of the location
+ * to store the indexed address.
+ */
+set_64byte_addr:
+	shr	ARG_2, 2, A;
+	shl	A, 6;
+
 /*
- * Setup addr assuming that A + (ARG_1 * 256) is an
+ * Setup addr assuming that A + (ARG_2 * 256) is an
  * index into an array of 1byte objects, SINDEX contains
  * the base address of that array, and DINDEX contains
  * the base address of the location to store the computed
  * address.
  */
 set_1byte_addr:
-	add	DINDIR, A, SINDIR;
-	mov	A, ARG_2;
+	add     DINDIR, A, SINDIR;
+	mov     A, ARG_2;
 	adc	DINDIR, A, SINDIR;
 	clr	A;
 	adc	DINDIR, A, SINDIR;
@@ -1296,21 +2000,32 @@
  */
 dma_scb:
 	mov	A, SINDEX;
-	if ((p->features & AHC_CMD_CHAN) != 0) {
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
 		mvi	DINDEX, CCHADDR;
-		mvi	HSCB_ADDR call set_32byte_addr;
+		mvi	HSCB_ADDR call set_64byte_addr;
 		mov	CCSCBPTR, SCBPTR;
-		mvi	CCHCNT, 32;
 		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			mvi	CCHCNT, SCB_DOWNLOAD_SIZE_64;
+		} else {
+			mvi	CCHCNT, SCB_DOWNLOAD_SIZE;
+		}
 		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
 		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
 		jmp	dma_scb_finish;
 dma_scb_tohost:
-		if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		mvi	CCHCNT, SCB_UPLOAD_SIZE;
+		if ((ahc->features & AHC_ULTRA2) == 0) {
 			mvi	CCSCBCTL, CCSCBRESET;
-			bmov	CCSCBRAM, SCB_CONTROL, 32;
+			bmov	CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE;
 			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
 			test	CCSCBCTL, CCSCBDONE jz .;
+		} else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) {
+			mvi	CCSCBCTL, CCARREN|CCSCBRESET;
+			cmp	CCSCBCTL, ARRDONE|CCARREN jne .;
+			mvi	CCHCNT, SCB_UPLOAD_SIZE;
+			mvi	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			cmp	CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
 		} else {
 			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
 			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
@@ -1321,85 +2036,161 @@
 		ret;
 	} else {
 		mvi	DINDEX, HADDR;
-		mvi	HSCB_ADDR call set_32byte_addr;
-		mvi	HCNT[0], 32;
-		clr	HCNT[1];
-		clr	HCNT[2];
+		mvi	HSCB_ADDR call set_64byte_addr;
+		mvi	SCB_DOWNLOAD_SIZE call set_hcnt;
 		mov	DFCNTRL, DMAPARAMS;
 		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
 		/* Fill it with the SCB data */
 copy_scb_tofifo:
-		mvi	SINDEX, SCB_CONTROL;
-		add	A, 32, SINDEX;
+		mvi	SINDEX, SCB_BASE;
+		add	A, SCB_DOWNLOAD_SIZE, SINDEX;
 copy_scb_tofifo_loop:
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
-		mov	DFDAT,SINDIR;
+		call	copy_to_fifo_8;
 		cmp	SINDEX, A jne copy_scb_tofifo_loop;
 		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
 dma_scb_fromhost:
-		call	dma_finish;
+		mvi	DINDEX, SCB_BASE;
+		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
+			/*
+			 * The PCI module will only issue a PCI
+			 * retry if the data FIFO is empty.  If the
+			 * host disconnects in the middle of a
+			 * transfer, we must empty the fifo of all
+			 * available data to force the chip to
+			 * continue the transfer.  This does not
+			 * happen for SCSI transfers as the SCSI module
+			 * will drain the FIFO as data is made available.
+			 * When the hang occurs, we know that a multiple
+			 * of 8 bytes are in the FIFO because the PCI
+			 * module has an 8 byte input latch that only
+			 * dumps to the FIFO when HCNT == 0 or the
+			 * latch is full.
+			 */
+			clr	A;
+			/* Wait for some data to arrive. */
+dma_scb_hang_fifo:
+			test	DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo;
+dma_scb_hang_wait:
+			test	DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
+			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
+			/*
+			 * The PCI module no longer intends to perform
+			 * a PCI transaction and HDONE has not come true.
+			 * We are hung.  Drain the fifo.
+			 */
+dma_scb_hang_empty_fifo:
+			/*
+			 * Skip lines not yet transfered into the FIFO.
+			 */
+			add	SINDEX, 7, HCNT;
+			shr	SINDEX, 3;
+
+			/*
+			 * Skip lines already copied out of the FIFO.
+			 */
+			add	A, A, SINDEX;
+
+			call	dma_scb_hang_dma_drain_fifo;
+
+			/*
+			 * Set the lines transferred to all but
+			 * those yet to reach the FIFO.
+			 */
+			not	SINDEX;
+			add	A, 5, SINDEX;
+			jmp	dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+			and	DFCNTRL, ~HDMAEN;
+			test	DFCNTRL, HDMAEN jnz .;
+dma_scb_hang_dma_drain_fifo:
+			add	SEQADDR0, A;
+		} else {
+			call	dma_finish;
+		}
 		/* If we were putting the SCB, we are done */
-		test	DMAPARAMS, DIRECTION	jz	return;
-		mvi	SCB_CONTROL  call dfdat_in_7;
-		call	dfdat_in_7_continued;
-		call	dfdat_in_7_continued;
-		jmp	dfdat_in_7_continued;
+		call	dfdat_in_8;
+		call	dfdat_in_8;
+		call	dfdat_in_8;
+dfdat_in_8:
+		mov	DINDIR,DFDAT;
 dfdat_in_7:
-		mov     DINDEX,SINDEX;
-dfdat_in_7_continued:
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
+dfdat_in_2:
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT ret;
 	}
 
+copy_to_fifo_8:
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+copy_to_fifo_6:
+	mov	DFDAT,SINDIR;
+copy_to_fifo_5:
+	mov	DFDAT,SINDIR;
+copy_to_fifo_4:
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR ret;
 
 /*
  * Wait for DMA from host memory to data FIFO to complete, then disable
  * DMA and wait for it to acknowledge that it's off.
  */
-if ((p->features & AHC_CMD_CHAN) == 0) {
 dma_finish:
 	test	DFSTATUS,HDONE	jz dma_finish;
 	/* Turn off DMA */
 	and	DFCNTRL, ~HDMAEN;
 	test	DFCNTRL, HDMAEN jnz .;
 	ret;
-}
 
+/*
+ * Restore an SCB that failed to match an incoming reselection
+ * to the correct/safe state.  If the SCB is for a disconnected
+ * transaction, it must be returned to the disconnected list.
+ * If it is not in the disconnected state, it must be free.
+ */
+cleanup_scb:
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		test	SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list;
+	}
 add_scb_to_free_list:
-	if ((p->flags & AHC_PAGESCBS) != 0) {
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+BEGIN_CRITICAL
 		mov	SCB_NEXT, FREE_SCBH;
-		mov	FREE_SCBH, SCBPTR;
+		mvi	SCB_TAG, SCB_LIST_NULL;
+		mov	FREE_SCBH, SCBPTR ret;
+END_CRITICAL
+	} else {
+		mvi	SCB_TAG, SCB_LIST_NULL ret;
 	}
-	mvi	SCB_TAG, SCB_LIST_NULL ret;
 
-if ((p->flags & AHC_PAGESCBS) != 0) {
+if ((ahc->flags & AHC_PAGESCBS) != 0) {
 get_free_or_disc_scb:
+BEGIN_CRITICAL
 	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
 	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
 return_error:
+	mvi	NO_FREE_SCB call set_seqint;
 	mvi	SINDEX, SCB_LIST_NULL	ret;
 dequeue_disc_scb:
 	mov	SCBPTR, DISCONNECTED_SCBH;
-dma_up_scb:
+	mov	DISCONNECTED_SCBH, SCB_NEXT;
+END_CRITICAL
 	mvi	DMAPARAMS, FIFORESET;
-	mov	SCB_TAG		call dma_scb;
-unlink_disc_scb:
-	mov	DISCONNECTED_SCBH, SCB_NEXT ret;
+	mov	SCB_TAG	jmp dma_scb;
+BEGIN_CRITICAL
 dequeue_free_scb:
 	mov	SCBPTR, FREE_SCBH;
 	mov	FREE_SCBH, SCB_NEXT ret;
-}
+END_CRITICAL
 
 add_scb_to_disc_list:
 /*
@@ -1407,5 +2198,13 @@
  * candidates for paging out an SCB if one is needed for a new command.
  * Modifying the disconnected list is a critical(pause dissabled) section.
  */
+BEGIN_CRITICAL
 	mov	SCB_NEXT, DISCONNECTED_SCBH;
 	mov	DISCONNECTED_SCBH, SCBPTR ret;
+END_CRITICAL
+}
+set_seqint:
+	mov	INTSTAT, SINDEX;
+	nop;
+return:
+	ret;
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,205 @@
+/*
+ * Interface for the 93C66/56/46/26/06 serial eeprom parts.
+ *
+ * Copyright (c) 1995, 1996 Daniel M. Eischen
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.c#7 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.9 2000/11/10 20:13:41 gibbs Exp $
+ */
+
+/*
+ *   The instruction set of the 93C66/56/46/26/06 chips are as follows:
+ *
+ *               Start  OP	    *
+ *     Function   Bit  Code  Address**  Data     Description
+ *     -------------------------------------------------------------------
+ *     READ        1    10   A5 - A0             Reads data stored in memory,
+ *                                               starting at specified address
+ *     EWEN        1    00   11XXXX              Write enable must preceed
+ *                                               all programming modes
+ *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
+ *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
+ *     ERAL        1    00   10XXXX              Erase all registers
+ *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
+ *     EWDS        1    00   00XXXX              Disables all programming
+ *                                               instructions
+ *     *Note: A value of X for address is a don't care condition.
+ *    **Note: There are 8 address bits for the 93C56/66 chips unlike
+ *	      the 93C46/26/06 chips which have 6 address bits.
+ *
+ *   The 93C46 has a four wire interface: clock, chip select, data in, and
+ *   data out.  In order to perform one of the above functions, you need
+ *   to enable the chip select for a clock period (typically a minimum of
+ *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
+ *   respectively).  While the chip select remains high, you can clock in
+ *   the instructions (above) starting with the start bit, followed by the
+ *   OP code, Address, and Data (if needed).  For the READ instruction, the
+ *   requested 16-bit register contents is read from the data out line but
+ *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
+ *   first).  The clock cycling from low to high initiates the next data
+ *   bit to be sent from the chip.
+ *
+ */
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+
+/*
+ * Right now, we only have to read the SEEPROM.  But we make it easier to
+ * add other 93Cx6 functions.
+ */
+static struct seeprom_cmd {
+  	uint8_t len;
+ 	uint8_t bits[3];
+} seeprom_read = {3, {1, 1, 0}};
+
+/*
+ * Wait for the SEERDY to go high; about 800 ns.
+ */
+#define CLOCK_PULSE(sd, rdy)				\
+	while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) {	\
+		;  /* Do nothing */			\
+	}						\
+	(void)SEEPROM_INB(sd);	/* Clear clock */
+
+/*
+ * Read the serial EEPROM and returns 1 if successful and 0 if
+ * not successful.
+ */
+int
+read_seeprom(sd, buf, start_addr, count)
+	struct seeprom_descriptor *sd;
+	uint16_t *buf;
+	u_int start_addr;
+	u_int count;
+{
+	int i = 0;
+	u_int k = 0;
+	uint16_t v;
+	uint8_t temp;
+
+	/*
+	 * Read the requested registers of the seeprom.  The loop
+	 * will range from 0 to count-1.
+	 */
+	for (k = start_addr; k < count + start_addr; k++) {
+		/* Send chip select for one clock cycle. */
+		temp = sd->sd_MS ^ sd->sd_CS;
+		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+
+		/*
+		 * Now we're ready to send the read command followed by the
+		 * address of the 16-bit register we want to read.
+		 */
+		for (i = 0; i < seeprom_read.len; i++) {
+			if (seeprom_read.bits[i] != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if (seeprom_read.bits[i] != 0)
+				temp ^= sd->sd_DO;
+		}
+		/* Send the 6 or 8 bit address (MSB first, LSB last). */
+		for (i = (sd->sd_chip - 1); i >= 0; i--) {
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+		}
+
+		/*
+		 * Now read the 16 bit register.  An initial 0 precedes the
+		 * register contents which begins with bit 15 (MSB) and ends
+		 * with bit 0 (LSB).  The initial 0 will be shifted off the
+		 * top of our word as we let the loop run from 0 to 16.
+		 */
+		v = 0;
+		for (i = 16; i >= 0; i--) {
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			v <<= 1;
+			if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
+				v |= 1;
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+		}
+
+		buf[k - start_addr] = v;
+
+		/* Reset the chip select for the next command cycle. */
+		temp = sd->sd_MS;
+		SEEPROM_OUTB(sd, temp);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		SEEPROM_OUTB(sd, temp);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+	}
+#ifdef AHC_DUMP_EEPROM
+	printf("\nSerial EEPROM:\n\t");
+	for (k = 0; k < count; k = k + 1) {
+		if (((k % 8) == 0) && (k != 0)) {
+			printf ("\n\t");
+		}
+		printf (" 0x%x", buf[k]);
+	}
+	printf ("\n");
+#endif
+	return (1);
+}
+
+int
+verify_cksum(struct seeprom_config *sc)
+{
+	int i;
+	int maxaddr;
+	uint32_t checksum;
+	uint16_t *scarray;
+
+	maxaddr = (sizeof(*sc)/2) - 1;
+	checksum = 0;
+	scarray = (uint16_t *)sc;
+
+	for (i = 0; i < maxaddr; i++)
+		checksum = checksum + scarray[i];
+	if (checksum == 0
+	 || (checksum & 0xFFFF) != sc->checksum) {
+		return (0);
+	} else {
+		return(1);
+	}
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_93cx6.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,92 @@
+/*
+ * Interface to the 93C46/56 serial EEPROM that is used to store BIOS
+ * settings for the aic7xxx based adaptec SCSI controllers.  It can
+ * also be used for 93C26 and 93C06 serial EEPROMS.
+ *
+ * Copyright (c) 1994, 1995, 2000 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7xxx_93cx6.h#5 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.8 2000/11/10 20:13:41 gibbs Exp $
+ */
+#ifndef _AIC7XXX_93CX6_H_
+#define _AIC7XXX_93CX6_H_
+
+typedef enum {
+	C46 = 6,
+	C56_66 = 8
+} seeprom_chip_t;
+
+struct seeprom_descriptor {
+	struct ahc_softc *sd_ahc;
+	u_int sd_control_offset;
+	u_int sd_status_offset;
+	u_int sd_dataout_offset;
+	seeprom_chip_t sd_chip;
+	uint16_t sd_MS;
+	uint16_t sd_RDY;
+	uint16_t sd_CS;
+	uint16_t sd_CK;
+	uint16_t sd_DO;
+	uint16_t sd_DI;
+};
+
+/*
+ * This function will read count 16-bit words from the serial EEPROM and
+ * return their value in buf.  The port address of the aic7xxx serial EEPROM
+ * control register is passed in as offset.  The following parameters are
+ * also passed in:
+ *
+ *   CS  - Chip select
+ *   CK  - Clock
+ *   DO  - Data out
+ *   DI  - Data in
+ *   RDY - SEEPROM ready
+ *   MS  - Memory port mode select
+ *
+ *  A failed read attempt returns 0, and a successful read returns 1.
+ */
+
+#define	SEEPROM_INB(sd) \
+	ahc_inb(sd->sd_ahc, sd->sd_control_offset)
+#define	SEEPROM_OUTB(sd, value)					\
+do {								\
+	ahc_outb(sd->sd_ahc, sd->sd_control_offset, value);	\
+	ahc_flush_device_writes(sd->sd_ahc);			\
+} while(0)
+
+#define	SEEPROM_STATUS_INB(sd) \
+	ahc_inb(sd->sd_ahc, sd->sd_status_offset)
+#define	SEEPROM_DATA_INB(sd) \
+	ahc_inb(sd->sd_ahc, sd->sd_dataout_offset)
+
+int read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		 u_int start_addr, u_int count);
+int verify_cksum(struct seeprom_config *sc);
+
+#endif /* _AIC7XXX_93CX6_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h linux/drivers/scsi/aic7xxx/aic7xxx_inline.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_inline.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_inline.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,478 @@
+/*
+ * Inline routines shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $
+ */
+
+#ifndef _AIC7XXX_INLINE_H_
+#define _AIC7XXX_INLINE_H_
+
+/************************* Sequencer Execution Control ************************/
+static __inline int  sequencer_paused(struct ahc_softc *ahc);
+static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
+static __inline void pause_sequencer(struct ahc_softc *ahc);
+static __inline void unpause_sequencer(struct ahc_softc *ahc);
+
+/*
+ * Work around any chip bugs related to halting sequencer execution.
+ * On Ultra2 controllers, we must clear the CIOBUS stretch signal by
+ * reading a register that will set this signal and deassert it.
+ * Without this workaround, if the chip is paused, by an interrupt or
+ * manual pause while accessing scb ram, accesses to certain registers
+ * will hang the system (infinite pci retries).
+ */
+static __inline void
+ahc_pause_bug_fix(struct ahc_softc *ahc)
+{
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		(void)ahc_inb(ahc, CCSCBCTL);
+}
+
+/*
+ * Determine whether the sequencer has halted code execution.
+ * Returns non-zero status if the sequencer is stopped.
+ */
+static __inline int
+sequencer_paused(struct ahc_softc *ahc)
+{
+	return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
+}
+
+/*
+ * Request that the sequencer stop and wait, indefinitely, for it
+ * to stop.  The sequencer will only acknowledge that it is paused
+ * once it has reached an instruction boundary and PAUSEDIS is
+ * cleared in the SEQCTL register.  The sequencer may use PAUSEDIS
+ * for critical sections.
+ */
+static __inline void
+pause_sequencer(struct ahc_softc *ahc)
+{
+	ahc_outb(ahc, HCNTRL, ahc->pause);
+
+	/*
+	 * Since the sequencer can disable pausing in a critical section, we
+	 * must loop until it actually stops.
+	 */
+	while (sequencer_paused(ahc) == 0)
+		;
+
+	ahc_pause_bug_fix(ahc);
+}
+
+/*
+ * Allow the sequencer to continue program execution.
+ * We check here to ensure that no additional interrupt
+ * sources that would cause the sequencer to halt have been
+ * asserted.  If, for example, a SCSI bus reset is detected
+ * while we are fielding a different, pausing, interrupt type,
+ * we don't want to release the sequencer before going back
+ * into our interrupt handler and dealing with this new
+ * condition.
+ */
+static __inline void
+unpause_sequencer(struct ahc_softc *ahc)
+{
+	if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
+		ahc_outb(ahc, HCNTRL, ahc->unpause);
+}
+
+/*********************** Untagged Transaction Routines ************************/
+static __inline void	ahc_freeze_untagged_queues(struct ahc_softc *ahc);
+static __inline void	ahc_release_untagged_queues(struct ahc_softc *ahc);
+
+/*
+ * Block our completion routine from starting the next untagged
+ * transaction for this target or target lun.
+ */
+static __inline void
+ahc_freeze_untagged_queues(struct ahc_softc *ahc)
+{
+	if ((ahc->flags & AHC_SCB_BTT) == 0)
+		ahc->untagged_queue_lock++;
+}
+
+/*
+ * Allow the next untagged transaction for this target or target lun
+ * to be executed.  We use a counting semaphore to allow the lock
+ * to be acquired recursively.  Once the count drops to zero, the
+ * transaction queues will be run.
+ */
+static __inline void
+ahc_release_untagged_queues(struct ahc_softc *ahc)
+{
+	if ((ahc->flags & AHC_SCB_BTT) == 0) {
+		ahc->untagged_queue_lock--;
+		if (ahc->untagged_queue_lock == 0)
+			ahc_run_untagged_queues(ahc);
+	}
+}
+
+/************************** Memory mapping routines ***************************/
+static __inline struct ahc_dma_seg *
+			ahc_sg_bus_to_virt(struct scb *scb,
+					   uint32_t sg_busaddr);
+static __inline uint32_t
+			ahc_sg_virt_to_bus(struct scb *scb,
+					   struct ahc_dma_seg *sg);
+static __inline uint32_t
+			ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
+
+static __inline struct ahc_dma_seg *
+ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
+{
+	int sg_index;
+
+	sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
+	/* sg_list_phys points to entry 1, not 0 */
+	sg_index++;
+
+	return (&scb->sg_list[sg_index]);
+}
+
+static __inline uint32_t
+ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
+{
+	int sg_index;
+
+	/* sg_list_phys points to entry 1, not 0 */
+	sg_index = sg - &scb->sg_list[1];
+
+	return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
+}
+
+static __inline uint32_t
+ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
+{
+	return (ahc->scb_data->hscb_busaddr
+		+ (sizeof(struct hardware_scb) * index));
+}
+
+/******************************** Debugging ***********************************/
+static __inline char *ahc_name(struct ahc_softc *ahc);
+
+static __inline char *
+ahc_name(struct ahc_softc *ahc)
+{
+	return (ahc->name);
+}
+
+/*********************** Miscelaneous Support Functions ***********************/
+
+static __inline int	ahc_check_residual(struct scb *scb);
+static __inline struct ahc_initiator_tinfo *
+			ahc_fetch_transinfo(struct ahc_softc *ahc,
+					    char channel, u_int our_id,
+					    u_int remote_id,
+					    struct tmode_tstate **tstate);
+static __inline struct scb*
+			ahc_get_scb(struct ahc_softc *ahc);
+static __inline void	ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
+static __inline void	ahc_swap_with_next_hscb(struct ahc_softc *ahc,
+						struct scb *scb);
+static __inline void	ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
+static __inline struct scsi_sense_data *
+			ahc_get_sense_buf(struct ahc_softc *ahc,
+					  struct scb *scb);
+static __inline uint32_t
+			ahc_get_sense_bufaddr(struct ahc_softc *ahc,
+					      struct scb *scb);
+
+/*
+ * Determine whether the sequencer reported a residual
+ * for this SCB/transaction.
+ */
+static __inline int
+ahc_check_residual(struct scb *scb)
+{
+	struct status_pkt *sp;
+
+	sp = &scb->hscb->shared_data.status;
+	if ((scb->hscb->sgptr & SG_RESID_VALID) != 0)
+		return (1);
+	return (0);
+}
+
+/*
+ * Return pointers to the transfer negotiation information
+ * for the specified our_id/remote_id pair.
+ */
+static __inline struct ahc_initiator_tinfo *
+ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
+		    u_int remote_id, struct tmode_tstate **tstate)
+{
+	/*
+	 * Transfer data structures are stored from the perspective
+	 * of the target role.  Since the parameters for a connection
+	 * in the initiator role to a given target are the same as
+	 * when the roles are reversed, we pretend we are the target.
+	 */
+	if (channel == 'B')
+		our_id += 8;
+	*tstate = ahc->enabled_targets[our_id];
+	return (&(*tstate)->transinfo[remote_id]);
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new SCB.
+ */
+static __inline struct scb *
+ahc_get_scb(struct ahc_softc *ahc)
+{
+	struct scb *scb;
+
+	if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
+		ahc_alloc_scbs(ahc);
+		scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
+		if (scb == NULL)
+			return (NULL);
+	}
+	SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
+	return (scb);
+}
+
+/*
+ * Return an SCB resource to the free list.
+ */
+static __inline void
+ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
+{       
+	struct hardware_scb *hscb;
+
+	hscb = scb->hscb;
+	/* Clean up for the next user */
+	ahc->scb_data->scbindex[hscb->tag] = NULL;
+	scb->flags = SCB_FREE;
+	hscb->control = 0;
+
+	SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
+
+	/* Notify the OSM that a resource is now available. */
+	ahc_platform_scb_free(ahc, scb);
+}
+
+static __inline struct scb *
+ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
+{
+	return (ahc->scb_data->scbindex[tag]);
+
+}
+
+static __inline void
+ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
+{
+	struct hardware_scb *q_hscb;
+	u_int  saved_tag;
+
+	/*
+	 * Our queuing method is a bit tricky.  The card
+	 * knows in advance which HSCB to download, and we
+	 * can't disappoint it.  To achieve this, the next
+	 * SCB to download is saved off in ahc->next_queued_scb.
+	 * When we are called to queue "an arbitrary scb",
+	 * we copy the contents of the incoming HSCB to the one
+	 * the sequencer knows about, swap HSCB pointers and
+	 * finally assign the SCB to the tag indexed location
+	 * in the scb_array.  This makes sure that we can still
+	 * locate the correct SCB by SCB_TAG.
+	 */
+	q_hscb = ahc->next_queued_scb->hscb;
+	saved_tag = q_hscb->tag;
+	memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+	if ((scb->flags & SCB_CDB32_PTR) != 0) {
+		q_hscb->shared_data.cdb_ptr =
+		    ahc_hscb_busaddr(ahc, q_hscb->tag)
+		  + offsetof(struct hardware_scb, cdb32);	
+	}
+	q_hscb->tag = saved_tag;
+	q_hscb->next = scb->hscb->tag;
+
+	/* Now swap HSCB pointers. */
+	ahc->next_queued_scb->hscb = scb->hscb;
+	scb->hscb = q_hscb;
+
+	/* Now define the mapping from tag to SCB in the scbindex */
+	ahc->scb_data->scbindex[scb->hscb->tag] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
+ */
+static __inline void
+ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+	ahc_swap_with_next_hscb(ahc, scb);
+
+	if (scb->hscb->tag == SCB_LIST_NULL
+	 || scb->hscb->next == SCB_LIST_NULL)
+		panic("Attempt to queue invalid SCB tag %x:%x\n",
+		      scb->hscb->tag, scb->hscb->next);
+
+	/*
+	 * Keep a history of SCBs we've downloaded in the qinfifo.
+	 */
+	ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+	} else {
+		if ((ahc->features & AHC_AUTOPAUSE) == 0)
+			pause_sequencer(ahc);
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+		if ((ahc->features & AHC_AUTOPAUSE) == 0)
+			unpause_sequencer(ahc);
+	}
+}
+
+static __inline struct scsi_sense_data *
+ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
+{
+	int offset;
+
+	offset = scb - ahc->scb_data->scbarray;
+	return (&ahc->scb_data->sense[offset]);
+}
+
+static __inline uint32_t
+ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
+{
+	int offset;
+
+	offset = scb - ahc->scb_data->scbarray;
+	return (ahc->scb_data->sense_busaddr
+	      + (offset * sizeof(struct scsi_sense_data)));
+}
+
+/************************** Interrupt Processing ******************************/
+static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
+static __inline void ahc_intr(struct ahc_softc *ahc);
+
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHC_RUN_QOUTFIFO 0x1
+#define AHC_RUN_TQINFIFO 0x2
+static __inline u_int
+ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
+{
+	u_int retval;
+
+	retval = 0;
+	if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
+		retval |= AHC_RUN_QOUTFIFO;
+#ifdef AHC_TARGET_MODE
+	if ((ahc->flags & AHC_TARGETROLE) != 0
+	 && ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
+		retval |= AHC_RUN_TQINFIFO;
+#endif
+	return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+static __inline void
+ahc_intr(struct ahc_softc *ahc)
+{
+	u_int	intstat;
+	u_int 	queuestat;
+
+	/*
+	 * Instead of directly reading the interrupt status register,
+	 * infer the cause of the interrupt by checking our in-core
+	 * completion queues.  This avoids a costly PCI bus read in
+	 * most cases.
+	 */
+	intstat = 0;
+	if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
+		intstat = CMDCMPLT;
+
+	if ((intstat & INT_PEND) == 0
+	 || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) {
+
+		intstat = ahc_inb(ahc, INTSTAT);
+#if AHC_PCI_CONFIG > 0
+		if (ahc->unsolicited_ints > 500
+		 && (ahc->chip & AHC_PCI) != 0
+		 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
+			ahc_pci_intr(ahc);
+#endif
+	}
+
+	if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
+		/* Hot eject */
+		return;
+
+	if ((intstat & INT_PEND) == 0) {
+		ahc->unsolicited_ints++;
+		return;
+	}
+	ahc->unsolicited_ints = 0;
+
+	if (intstat & CMDCMPLT) {
+		ahc_outb(ahc, CLRINT, CLRCMDINT);
+
+		/*
+		 * Ensure that the chip sees that we've cleared
+		 * this interrupt before we walk the output fifo.
+		 * Otherwise, we may, due to posted bus writes,
+		 * clear the interrupt after we finish the scan,
+		 * and after the sequencer has added new entries
+		 * and asserted the interrupt again.
+		 */
+		ahc_flush_device_writes(ahc);
+#ifdef AHC_TARGET_MODE
+		if ((queuestat & AHC_RUN_QOUTFIFO) != 0)
+#endif
+			ahc_run_qoutfifo(ahc);
+#ifdef AHC_TARGET_MODE
+		if ((queuestat & AHC_RUN_TQINFIFO) != 0)
+			ahc_run_tqinfifo(ahc, /*paused*/FALSE);
+#endif
+	}
+	if (intstat & BRKADRINT) {
+		ahc_handle_brkadrint(ahc);
+		/* Fatal error, no more interrupts to handle. */
+		return;
+	}
+
+	if ((intstat & (SEQINT|SCSIINT)) != 0)
+		ahc_pause_bug_fix(ahc);
+
+	if ((intstat & SEQINT) != 0)
+		ahc_handle_seqint(ahc, intstat);
+
+	if ((intstat & SCSIINT) != 0)
+		ahc_handle_scsiint(ahc, intstat);
+}
+
+#endif  /* _AIC7XXX_INLINE_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,2650 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
+ * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
+ * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
+ * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
+ * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
+ * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
+ * ANSI SCSI-2 specification (draft 10c), ...
+ *
+ * --------------------------------------------------------------------------
+ *
+ *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ *  Substantially modified to include support for wide and twin bus
+ *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ *  SCB paging, and other rework of the code.
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000 Justin T. Gibbs.
+ * Copyright (c) 2000 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ *---------------------------------------------------------------------------
+ *
+ *  Thanks also go to (in alphabetical order) the following:
+ *
+ *    Rory Bolt     - Sequencer bug fixes
+ *    Jay Estabrook - Initial DEC Alpha support
+ *    Doug Ledford  - Much needed abort/reset bug fixes
+ *    Kai Makisara  - DMAing of SCBs
+ *
+ *  A Boot time option was also added for not resetting the scsi bus.
+ *
+ *    Form:  aic7xxx=extended
+ *           aic7xxx=no_reset
+ *           aic7xxx=ultra
+ *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
+ *           aic7xxx=verbose
+ *
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
+ *
+ *  Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp
+ */
+
+/*
+ * Further driver modifications made by Doug Ledford <dledford@redhat.com>
+ *
+ * Copyright (c) 1997-1999 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accomodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ */
+
+/*
+ * The next three defines are user configurable.  These should be the only
+ * defines a user might need to get in here and change.  There are other
+ * defines buried deeper in the code, but those really shouldn't need touched
+ * under normal conditions.
+ */
+
+#if defined(MODULE) || defined(PCMCIA)
+#include <linux/module.h>
+#endif
+
+#if defined(PCMCIA)
+#undef MODULE
+#endif
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#include <linux/init.h>		/* __setup */
+#endif
+
+#include "../sd.h"		/* For geometry detection */
+
+/*
+ * To generate the correct addresses for the controller to issue
+ * on the bus.  Originally added for DEC Alpha support.
+ */
+#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a))
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+struct proc_dir_entry proc_scsi_aic7xxx = {
+	PROC_SCSI_AIC7XXX, 7, "aic7xxx",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2,
+	0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+#endif
+
+/*
+ * Set this to the delay in seconds after SCSI bus reset.
+ * Note, we honor this only for the initial bus reset.
+ * The scsi error recovery code performs its own bus settle
+ * delay handling for error recovery actions.
+ */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#else
+#define AIC7XXX_RESET_DELAY 5000
+#endif
+
+/*
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
+ *
+ * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
+ * NOTE: This does affect performance since it has to maintain statistics.
+ */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
+
+/*
+ * To change the default number of tagged transactions allowed per-device,
+ * add a line to the lilo.conf file like:
+ * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ * which will result in the first four devices on the first two
+ * controllers being set to a tagged queue depth of 32.
+ *
+ * The tag_commands is an array of 16 to allow for wide and twin adapters.
+ * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15
+ * for channel 1.
+ */
+typedef struct {
+	uint8_t tag_commands[16];	/* Allow for wide/twin adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Modify this as you see fit for your system.
+ *
+ * 0			tagged queuing disabled
+ * 1 <= n <= 253	n == max tags ever dispatched.
+ *
+ * The driver will throttle the number of commands dispatched to a
+ * device if it returns queue full.  For devices with a fixed maximum
+ * queue depth, the driver will eventually determine this depth and
+ * lock it in (a console message is printed to indicate that a lock
+ * has occurred).  On some devices, queue full is returned for a temporary
+ * resource shortage.  These devices will return queue full at varying
+ * depths.  The driver will throttle back when the queue fulls occur and
+ * attempt to slowly increase the depth over time as the device recovers
+ * from the resource shortage.
+ *
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to attempt to use up to 64 tags for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+
+/*
+ * NOTE: The below structure is for reference only, the actual structure
+ *       to modify in order to change things is just below this comment block.
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+	{{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}},
+	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+	{{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+*/
+
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#else
+#define AIC7XXX_CMDS_PER_DEVICE AHC_MAX_QUEUE
+#endif
+
+#define AIC7XXX_CONFIGED_TAG_COMMANDS {					\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE		\
+}
+
+/*
+ * By default, use the number of commands specified by
+ * the users kernel configuration.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS}
+};
+
+/*
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW   DID_ERROR
+
+void
+ahc_print_path(struct ahc_softc *ahc, struct scb *scb)
+{
+	printk("(scsi%d:%c:%d:%d): ",
+	       ahc->platform_data->host->host_no,
+	       scb != NULL ? SCB_GET_CHANNEL(ahc, scb) : 'X',
+	       scb != NULL ? SCB_GET_TARGET(ahc, scb) : -1,
+	       scb != NULL ? SCB_GET_LUN(scb) : -1);
+}
+
+/*
+ * XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *       cards in the system.  This should be fixed.  Exceptions to this
+ *       rule are noted in the comments.
+ */
+
+/*
+ * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
+ * has no effect on any later resets that might occur due to things like
+ * SCSI bus timeouts.
+ */
+static uint32_t aic7xxx_no_reset;
+
+/*
+ * Certain PCI motherboards will scan PCI devices from highest to lowest,
+ * others scan from lowest to highest, and they tend to do all kinds of
+ * strange things when they come into contact with PCI bridge chips.  The
+ * net result of all this is that the PCI card that is actually used to boot
+ * the machine is very hard to detect.  Most motherboards go from lowest
+ * PCI slot number to highest, and the first SCSI controller found is the
+ * one you boot from.  The only exceptions to this are when a controller
+ * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
+ * from lowest PCI slot number to highest PCI slot number.  We also force
+ * all controllers with their BIOS disabled to the end of the list.  This
+ * works on *almost* all computers.  Where it doesn't work, we have this
+ * option.  Setting this option to non-0 will reverse the order of the sort
+ * to highest first, then lowest, but will still leave cards with their BIOS
+ * disabled at the very end.  That should fix everyone up unless there are
+ * really strange cirumstances.
+ */
+static int aic7xxx_reverse_scan = 0;
+
+/*
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
+ */
+static uint32_t aic7xxx_extended = 0;
+
+/*
+ * The IRQ trigger method used on EISA controllers. Does not effect PCI cards.
+ *   -1 = Use detected settings.
+ *    0 = Force Edge triggered mode.
+ *    1 = Force Level triggered mode.
+ */
+static int aic7xxx_irq_trigger = -1;
+
+/*
+ * This variable is used to override the termination settings on a controller.
+ * This should not be used under normal conditions.  However, in the case
+ * that a controller does not have a readable SEEPROM (so that we can't
+ * read the SEEPROM settings directly) and that a controller has a buggered
+ * version of the cable detection logic, this can be used to force the
+ * correct termination.  It is preferable to use the manual termination
+ * settings in the BIOS if possible, but some motherboard controllers store
+ * those settings in a format we can't read.  In other cases, auto term
+ * should also work, but the chipset was put together with no auto term
+ * logic (common on motherboard controllers).  In those cases, we have
+ * 32 bits here to work with.  That's good for 8 controllers/channels.  The
+ * bits are organized as 4 bits per channel, with scsi0 getting the lowest
+ * 4 bits in the int.  A 1 in a bit position indicates the termination setting
+ * that corresponds to that bit should be enabled, a 0 is disabled.
+ * It looks something like this:
+ *
+ *    0x0f =  1111-Single Ended Low Byte Termination on/off
+ *            ||\-Single Ended High Byte Termination on/off
+ *            |\-LVD Low Byte Termination on/off
+ *            \-LVD High Byte Termination on/off
+ *
+ * For non-Ultra2 controllers, the upper 2 bits are not important.  So, to
+ * enable both high byte and low byte termination on scsi0, I would need to
+ * make sure that the override_term variable was set to 0x03 (bits 0011).
+ * To make sure that all termination is enabled on an Ultra2 controller at
+ * scsi2 and only high byte termination on scsi1 and high and low byte
+ * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011)
+ *
+ * For the most part, users should never have to use this, that's why I
+ * left it fairly cryptic instead of easy to understand.  If you need it,
+ * most likely someone will be telling you what your's needs to be set to.
+ */
+static int aic7xxx_override_term = -1;
+
+/*
+ * Certain motherboard chipset controllers tend to screw
+ * up the polarity of the term enable output pin.  Use this variable
+ * to force the correct polarity for your system.  This is a bitfield variable
+ * similar to the previous one, but this one has one bit per channel instead
+ * of four.
+ *    0 = Force the setting to active low.
+ *    1 = Force setting to active high.
+ * Most Adaptec cards are active high, several motherboards are active low.
+ * To force a 2940 card at SCSI 0 to active high and a motherboard 7895
+ * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3
+ * to active high, you would need to set stpwlev=0x9 (bits 1001).
+ *
+ * People shouldn't need to use this, but if you are experiencing lots of
+ * SCSI timeout problems, this may help.  There is one sure way to test what
+ * this option needs to be.  Using a boot floppy to boot the system, configure
+ * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and
+ * if needed then also pass a value to override_term to make sure that the
+ * driver is enabling SCSI termination, then set this variable to either 0
+ * or 1.  When the driver boots, make sure there are *NO* SCSI cables
+ * connected to your controller.  If it finds and inits the controller
+ * without problem, then the setting you passed to stpwlev was correct.  If
+ * the driver goes into a reset loop and hangs the system, then you need the
+ * other setting for this variable.  If neither setting lets the machine
+ * boot then you have definite termination problems that may not be fixable.
+ */
+static int aic7xxx_stpwlev = -1;
+
+/*
+ * Set this to non-0 in order to force the driver to panic the kernel
+ * and print out debugging info on a SCSI abort or reset cycle.
+ */
+static int aic7xxx_panic_on_abort = 0;
+
+/*
+ * PCI bus parity checking of the Adaptec controllers.  This is somewhat
+ * dubious at best.  To my knowledge, this option has never actually
+ * solved a PCI parity problem, but on certain machines with broken PCI
+ * chipset configurations, it can generate tons of false error messages.
+ * It's included in the driver for completeness.
+ *   0 = Shut off PCI parity check
+ *  -1 = Normal polarity pci parity checking
+ *   1 = reverse polarity pci parity checking
+ *
+ * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
+ * variable to -1 you would actually want to simply pass the variable
+ * name without a number.  That will invert the 0 which will result in
+ * -1.
+ */
+static int aic7xxx_pci_parity = 0;
+
+/*
+ * Set this to a non-0 value to make us dump out the 32 bit instruction
+ * registers on the card after completing the sequencer download.  This
+ * allows the actual sequencer download to be verified.  It is possible
+ * to use this option and still boot up and run your system.  This is
+ * only intended for debugging purposes.
+ */
+static int aic7xxx_dump_sequencer = 0;
+
+/*
+ * Certain newer motherboards have put new PCI based devices into the
+ * IO spaces that used to typically be occupied by VLB or EISA cards.
+ * This overlap can cause these newer motherboards to lock up when scanned
+ * for older EISA and VLB devices.  Setting this option to non-0 will
+ * cause the driver to skip scanning for any VLB or EISA controllers and
+ * only support the PCI controllers.  NOTE: this means that if the kernel
+ * os compiled with PCI support disabled, then setting this to non-0
+ * would result in never finding any devices :)
+ */
+int aic7xxx_no_probe;
+
+/*
+ * aic7xxx_detect() has been run, so register all device arrivals
+ * immediately with the system rather than deferring to the sorted
+ * attachment performed by aic7xxx_detect().
+ */
+int aic7xxx_detect_complete;
+
+/*
+ * So that we can set how long each device is given as a selection timeout.
+ * The table of values goes like this:
+ *   0 - 256ms
+ *   1 - 128ms
+ *   2 - 64ms
+ *   3 - 32ms
+ * We default to 256ms because some older devices need a longer time
+ * to respond to initial selection.
+ */
+static int aic7xxx_seltime = 0x00;
+
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char *aic7xxx = NULL;
+
+MODULE_PARM(aic7xxx, "s");
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+static void ahc_handle_scsi_status(struct ahc_softc *,
+				   struct ahc_linux_device *, struct scb *);
+static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
+static void ahc_sem_timeout(u_long arg);
+static void ahc_release_sim_queue(u_long arg);
+static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
+static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc);
+static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
+				       Scsi_Device *scsi_devs);
+static void aic7xxx_device_queue_depth(struct ahc_softc *ahc,
+				       Scsi_Device *device);
+static struct ahc_linux_target*	ahc_alloc_target(struct ahc_softc *,
+						 u_int, u_int);
+static void			ahc_free_target(struct ahc_softc *ahc,
+						struct ahc_linux_target *targ);
+static struct ahc_linux_device*	ahc_alloc_device(struct ahc_softc *,
+						 struct ahc_linux_target *,
+						 u_int);
+static void			ahc_free_device(struct ahc_softc *ahc,
+						struct ahc_linux_device *dev);
+static void ahc_run_device_queue(struct ahc_softc *ahc,
+				 struct ahc_linux_device *dev);
+static void ahc_setup_tag_info(char *p, char *end);
+static int ahc_next_unit(void);
+
+static __inline struct ahc_linux_device*
+		     ahc_get_device(struct ahc_softc *ahc, u_int channel,
+				    u_int target, u_int lun, int /*alloc*/);
+static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc,
+					    Scsi_Cmnd *cmd);
+static __inline void ahc_run_complete_queue(struct ahc_softc *ahc,
+					    struct ahc_cmd *acmd);
+static __inline void ahc_check_device_queue(struct ahc_softc *ahc,
+					  struct ahc_linux_device *dev);
+static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
+static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb);
+
+static __inline struct ahc_linux_device*
+ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
+	       u_int lun, int alloc)
+{
+	struct ahc_linux_target *targ;
+	struct ahc_linux_device *dev;
+	u_int target_offset;
+
+	target_offset = target;
+	if (channel != 0)
+		target_offset += 8;
+	targ = ahc->platform_data->targets[target_offset];
+	if (targ == NULL) {
+		if (alloc != 0) {
+			targ = ahc_alloc_target(ahc, channel, target);
+			if (targ == NULL)
+				return (NULL);
+		} else
+			return (NULL);
+	}
+	dev = targ->devices[lun];
+	if (dev == NULL && alloc != 0)
+		dev = ahc_alloc_device(ahc, targ, lun);
+	return (dev);
+}
+
+static __inline void
+ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+{
+	/*
+	 * Typically, the complete queue has very few entries
+	 * queued to it before the queue is emptied by
+	 * ahc_run_complete_queue, so sorting the entries
+	 * by generation number should be inexpensive.
+	 * We perform the sort so that commands that complete
+	 * with an error are retuned in the order origionally
+	 * queued to the controller so that any subsequent retries
+	 * are performed in order.  The underlying ahc routines do
+	 * not guarantee the order that aborted commands will be
+	 * returned to us.
+	 */
+	struct ahc_completeq *completeq;
+	struct ahc_cmd *list_cmd;
+	struct ahc_cmd *acmd;
+
+	/*
+	 * If we want the request requeued, make sure there
+	 * are sufficent retries.  In the old scsi error code,
+	 * we used to be able to specify a result code that
+	 * bypassed the retry count.  Now we must use this
+	 * hack.
+	 */
+	if (cmd->result == (CAM_REQUEUE_REQ << 16))
+		cmd->retries--;
+	completeq = &ahc->platform_data->completeq;
+	list_cmd = TAILQ_FIRST(completeq);
+	acmd = (struct ahc_cmd *)cmd;
+	while (list_cmd != NULL
+	    && acmd_scsi_cmd(list_cmd).serial_number
+	     < acmd_scsi_cmd(acmd).serial_number)
+		list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);
+	if (list_cmd != NULL)
+		TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);
+	else
+		TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);
+}
+
+static __inline void
+ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
+{	
+	u_long done_flags;
+
+	ahc_done_lock(ahc, &done_flags);
+	while (acmd != NULL) {
+		Scsi_Cmnd *cmd;
+
+		cmd = &acmd_scsi_cmd(acmd);
+		acmd = TAILQ_NEXT(acmd, acmd_links.tqe);
+		cmd->host_scribble = NULL;
+		cmd->scsi_done(cmd);
+	}
+	ahc_done_unlock(ahc, &done_flags);
+}
+
+static __inline void
+ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0
+	 && dev->active == 0) {
+		dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY;
+		dev->qfrozen--;
+	}
+
+	if (TAILQ_FIRST(&dev->busyq) == NULL
+	 || dev->openings == 0 || dev->qfrozen != 0)
+		return;
+
+	ahc_run_device_queue(ahc, dev);
+}
+
+static __inline void
+ahc_run_device_queues(struct ahc_softc *ahc)
+{
+	struct ahc_linux_device *dev;
+
+	while ((ahc->flags & AHC_RESOURCE_SHORTAGE) == 0
+	    && ahc->platform_data->qfrozen == 0
+	    && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) {
+		LIST_REMOVE(dev, links);
+		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
+		ahc_check_device_queue(ahc, dev);
+	}
+}
+
+static __inline void
+ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+{
+	/*
+	 * Determine whether we care to filter
+	 * information out of this command.  If so,
+	 * pass it on to ahc_filter_command() for more
+	 * heavy weight processing.
+	 */
+	if (cmd->cmnd[0] == INQUIRY)
+		ahc_filter_command(ahc, cmd);
+}
+
+static __inline void
+ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+	Scsi_Cmnd *cmd;
+
+	cmd = scb->io_ctx;
+	if (cmd->use_sg != 0) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *)cmd->request_buffer;
+		pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg,
+			     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	} else if (cmd->request_bufflen != 0)
+		pci_unmap_single(ahc->dev_softc,
+				 ahc_le32toh(scb->sg_list[0].addr),
+				 cmd->request_bufflen,
+				 scsi_to_pci_dma_dir(cmd->sc_data_direction));
+}
+
+/******************************** Macros **************************************/
+#define BUILD_SCSIID(ahc, cmd)						\
+	((((cmd)->target << TID_SHIFT) & TID)				\
+	| (((cmd)->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b)	\
+	| (((cmd)->channel == 0) ? 0 : TWIN_CHNLB))
+
+/******************************** Bus DMA *************************************/
+int
+ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent,
+		   bus_size_t alignment, bus_size_t boundary,
+		   bus_addr_t lowaddr, bus_addr_t highaddr,
+		   bus_dma_filter_t *filter, void *filterarg,
+		   bus_size_t maxsize, int nsegments,
+		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag)
+{
+	bus_dma_tag_t dmat;
+
+	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+	if (dmat == NULL)
+		return (ENOMEM);
+
+	/*
+	 * Linux is very simplistic about DMA memory.  For now don't
+	 * maintain all specification information.  Once Linux supplies
+	 * better facilities for doing these operations, or the
+	 * needs of this particular driver change, we might need to do
+	 * more here.
+	 */
+	dmat->alignment = alignment;
+	dmat->boundary = boundary;
+	dmat->maxsize = maxsize;
+	*ret_tag = dmat;
+	return (0);
+}
+
+void
+ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat)
+{
+	free(dmat, M_DEVBUF);
+}
+
+int
+ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr,
+		 int flags, bus_dmamap_t *mapp)
+{
+	bus_dmamap_t map;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
+	if (map == NULL)
+		return (ENOMEM);
+	*vaddr = pci_alloc_consistent(ahc->dev_softc,
+				      dmat->maxsize, &map->bus_addr);
+#else
+	/*
+	 * At least in 2.2.14, malloc is a slab allocator so all
+	 * allocations are aligned.  We assume, for these kernel versions
+	 * that all allocations will be bellow 4Gig, physically contiguous,
+	 * and accessable via DMA by the controller.
+	 */
+	map = NULL; /* No additional information to store */
+	*vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT);
+#endif
+	if (*vaddr == NULL)
+		return (ENOMEM);
+	*mapp = map;
+	return(0);
+}
+
+void
+ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat,
+		void* vaddr, bus_dmamap_t map)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	pci_free_consistent(ahc->dev_softc, dmat->maxsize,
+			    vaddr, map->bus_addr);
+#else
+	free(vaddr, M_DEVBUF);
+#endif
+}
+
+int
+ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map,
+		void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,
+		void *cb_arg, int flags)
+{
+	/*
+	 * Assume for now that this will only be used during
+	 * initialization and not for per-transaction buffer mapping.
+	 */
+	bus_dma_segment_t stack_sg;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	stack_sg.ds_addr = map->bus_addr;
+#else
+	stack_sg.ds_addr = VIRT_TO_BUS(buf);
+#endif
+	stack_sg.ds_len = dmat->maxsize;
+	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
+	return (0);
+}
+
+void
+ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	/*
+	 * The map may is NULL in our < 2.3.X implementation.
+	 */
+	if (map != NULL)
+		free(map, M_DEVBUF);
+}
+
+int
+ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	/* Nothing to do */
+	return (0);
+}
+
+/********************* Platform Dependent Functions ***************************/
+int
+ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
+{
+	int	value;
+	int	rvalue;
+	int	lvalue;
+
+	/*
+	 * Under Linux, cards are ordered as follows:
+	 *	1) VLB/EISA BIOS enabled devices sorted by BIOS address.
+	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.
+	 *	3) All remaining VLB/EISA devices sorted by ioport.
+	 *	4) All remaining PCI devices sorted by bus/slot/func.
+	 */
+	value = (lahc->flags & AHC_BIOS_ENABLED)
+	      - (rahc->flags & AHC_BIOS_ENABLED);
+	if (value != 0)
+		/* Controllers with BIOS enabled have a *higher* priority */
+		return (-value);
+
+	/*
+	 * Same BIOS setting, now sort based on bus type.
+	 * EISA and VL controllers sort together.  EISA/VL
+	 * have higher priority than PCI.
+	 */
+	rvalue = (rahc->chip & AHC_BUS_MASK);
+ 	if (rvalue == AHC_VL)
+		rvalue = AHC_EISA;
+	lvalue = (lahc->chip & AHC_BUS_MASK);
+ 	if (lvalue == AHC_VL)
+		lvalue = AHC_EISA;
+	value = lvalue - rvalue;
+	if (value != 0)
+		return (value);
+
+	/* Still equal.  Sort by BIOS address, ioport, or bus/slot/func. */
+	switch (rvalue) {
+	case AHC_PCI:
+		value = ahc_get_pci_bus(lahc->dev_softc)
+		      - ahc_get_pci_bus(rahc->dev_softc);
+		if (value != 0)
+			break;
+		value = ahc_get_pci_slot(lahc->dev_softc)
+		      - ahc_get_pci_slot(rahc->dev_softc);
+		if (value != 0)
+			break;
+		value = ahc_get_pci_function(lahc->dev_softc)
+		      - ahc_get_pci_function(rahc->dev_softc);
+		/*
+		 * On multi-function devices, the user can choose
+		 * to have function 1 probed before function 0.
+		 * Function 0 is the only one that will have
+		 * CHANNEL_B_PRIMARY set.
+		 */
+		if (value < 0
+		 && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0)
+			/* Swap the two */
+			value = -value;
+		break;
+	case AHC_EISA:
+		if ((rahc->flags & AHC_BIOS_ENABLED) != 0) {
+			value = lahc->platform_data->bios_address
+			      - rahc->platform_data->bios_address; 
+		} else {
+			value = lahc->bsh.ioport
+			      - rahc->bsh.ioport; 
+		}
+		break;
+	default:
+		panic("ahc_softc_sort: invalid bus type");
+	}
+	return (value);
+}
+
+static void
+ahc_setup_tag_info(char *p, char *end)
+{
+	char	*base;
+	char	*tok;
+	char	*tok_end;
+	char	*tok_end2;
+	int      i;
+	int      instance;
+	int	 device;
+	int	 done;
+	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
+
+	if (*p != ':')
+		return;
+
+	instance = -1;
+	device = -1;
+	done = FALSE;
+	base = p;
+	/* Forward us just past the ':' */
+	tok = base + 1;
+	tok_end = strchr(tok, '\0');
+	if (tok_end < end)
+		*tok_end = ',';
+	while (!done) {
+		switch (*tok) {
+		case '{':
+			if (instance == -1)
+				instance = 0;
+			else if (device == -1)
+				device = 0;
+			tok++;
+			break;
+		case '}':
+			if (device != -1)
+				device = -1;
+			else if (instance != -1)
+				instance = -1;
+			tok++;
+			break;
+		case ',':
+		case '.':
+			if (instance == -1)
+				done = TRUE;
+			else if (device >= 0)
+				device++;
+			else if (instance >= 0)
+				instance++;
+			if ((device >= AHC_NUM_TARGETS) ||
+			    (instance >= NUM_ELEMENTS(aic7xxx_tag_info)))
+				done = TRUE;
+			tok++;
+			if (!done) {
+				base = tok;
+			}
+			break;
+		case '\0':
+			done = TRUE;
+			break;
+		default:
+			done = TRUE;
+			tok_end = strchr(tok, '\0');
+			for (i = 0; tok_list[i]; i++) {
+				tok_end2 = strchr(tok, tok_list[i]);
+				if ((tok_end2) && (tok_end2 < tok_end)) {
+					tok_end = tok_end2;
+					done = FALSE;
+				}
+			}
+			if ((instance >= 0) && (device >= 0) &&
+			    (instance < NUM_ELEMENTS(aic7xxx_tag_info)) &&
+			    (device < AHC_NUM_TARGETS))
+				aic7xxx_tag_info[instance].tag_commands[device] =
+				    simple_strtoul(tok, NULL, 0) & 0xff;
+			tok = tok_end;
+			break;
+		}
+	}
+	while ((p != base) && (p != NULL))
+		p = strtok(NULL, ",.");
+}
+
+/*
+ * Handle Linux boot parameters. This routine allows for assigning a value
+ * to a parameter with a ':' between the parameter and the value.
+ * ie. aic7xxx=unpause:0x0A,extended
+ */
+int
+aic7xxx_setup(char *s)
+{
+	int	i, n;
+	char   *p;
+	char   *end;
+
+	static struct {
+		const char *name;
+		uint32_t *flag;
+	} options[] = {
+		{ "extended", &aic7xxx_extended },
+		{ "no_reset", &aic7xxx_no_reset },
+		{ "irq_trigger", &aic7xxx_irq_trigger },
+		{ "verbose", &aic7xxx_verbose },
+		{ "reverse_scan", &aic7xxx_reverse_scan },
+		{ "override_term", &aic7xxx_override_term },
+		{ "stpwlev", &aic7xxx_stpwlev },
+		{ "no_probe", &aic7xxx_no_probe },
+		{ "panic_on_abort", &aic7xxx_panic_on_abort },
+		{ "pci_parity", &aic7xxx_pci_parity },
+		{ "dump_sequencer", &aic7xxx_dump_sequencer },
+		{ "seltime", &aic7xxx_seltime },
+		{ "tag_info", NULL }
+	};
+
+	end = strchr(s, '\0');
+
+	for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) {
+		for (i = 0; i < NUM_ELEMENTS(options); i++) {
+			n = strlen(options[i].name);
+
+			if (strncmp(options[i].name, p, n) != 0)
+				continue;
+
+			if (strncmp(p, "tag_info", n) == 0) {
+				ahc_setup_tag_info(p + n, end);
+			} else if (p[n] == ':') {
+				*(options[i].flag) =
+				    simple_strtoul(p + n + 1, NULL, 0);
+			} else if (!strncmp(p, "verbose", n)) {
+				*(options[i].flag) = 1;
+			} else {
+				*(options[i].flag) = ~(*(options[i].flag));
+			}
+		}
+	}
+	return 1;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
+__setup("aic7xxx=", aic7xxx_setup);
+#endif
+
+int aic7xxx_verbose;
+
+/*
+ * Try to detect an Adaptec 7XXX controller.
+ */
+int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+	struct	ahc_softc *ahc;
+	int     found;
+
+	/*
+	 * Sanity checking of Linux SCSI data structures so
+	 * that some of our hacks^H^H^H^H^Hassumptions aren't
+	 * violated.
+	 */
+	if (offsetof(struct ahc_cmd_internal, end)
+	  > offsetof(struct scsi_cmnd, host_scribble)) {
+		printf("aic7xxx_detect: SCSI data structures changed.\n");
+		printf("aic7xxx_detect: Unable to attach\n");
+		return (0);
+	}
+#ifdef MODULE
+	/*
+	 * If we've been passed any parameters, process them now.
+	 */
+	if (aic7xxx)
+		aic7xxx_setup(aic7xxx);
+	if (dummy_buffer[0] != 'P')
+		printk(KERN_WARNING
+"aic7xxx: Please read the file /usr/src/linux/drivers/scsi/README.aic7xxx\n"
+"aic7xxx: to see the proper way to specify options to the aic7xxx module\n"
+"aic7xxx: Specifically, don't use any commas when passing arguments to\n"
+"aic7xxx: insmod or else it might trash certain memory areas.\n");
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
+	template->proc_name = "aic7xxx";
+#else
+	template->proc_dir = &proc_scsi_aic7xxx;
+#endif
+	template->sg_tablesize = AHC_NSEG;
+
+#ifdef CONFIG_PCI
+	ahc_linux_pci_probe(template);
+#endif
+
+	aic7770_linux_probe(template);
+
+	/*
+	 * Register with the SCSI layer all
+	 * controllers we've found.
+	 */
+	found = 0;
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+
+		if (aic7xxx_register_host(ahc, template) == 0)
+			found++;
+	}
+	aic7xxx_detect_complete++;
+	return (found);
+}
+
+int
+aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
+{
+	char  buf[80];
+	struct Scsi_Host *host;
+	char *new_name;
+	u_long s;
+
+
+	template->name = ahc->description;
+	host = scsi_register(template, sizeof(struct ahc_softc *));
+	if (host == NULL)
+		return (ENOMEM);
+
+	ahc_lock(ahc, &s);
+	*((struct ahc_softc **)host->hostdata) = ahc;
+	ahc->platform_data->host = host;
+	host->can_queue = AHC_MAX_QUEUE;
+	host->cmd_per_lun = 2;
+	host->sg_tablesize = AHC_NSEG;
+	host->select_queue_depths = aic7xxx_select_queue_depth;
+	host->this_id = ahc->our_id;
+	host->irq = ahc->platform_data->irq;
+	host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
+	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
+	ahc_set_unit(ahc, ahc_next_unit());
+	sprintf(buf, "scsi%d", host->host_no);
+	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (new_name != NULL) {
+		strcpy(new_name, buf);
+		ahc_set_name(ahc, new_name);
+	}
+	host->unique_id = ahc->unit;
+	aic7xxx_initialize_scsi_bus(ahc);
+	ahc_unlock(ahc, &s);
+	return (0);
+}
+
+/*
+ * Find the smallest available unit number to use
+ * for a new device.  We don't just use a static
+ * count to handle the "repeated hot-(un)plug"
+ * scenario.
+ */
+static int
+ahc_next_unit()
+{
+	struct ahc_softc *ahc;
+	int unit;
+
+	unit = 0;
+retry:
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		if (ahc->unit == unit) {
+			unit++;
+			goto retry;
+		}
+	}
+	return (unit);
+}
+
+/*
+ * Place the SCSI bus into a known state by either resetting it,
+ * or forcing transfer negotiations on the next command to any
+ * target.
+ */
+void
+aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc)
+{
+	int i;
+	int numtarg;
+
+	i = 0;
+	numtarg = 0;
+
+	if (aic7xxx_no_reset != 0)
+		ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B);
+
+	if ((ahc->flags & AHC_RESET_BUS_A) != 0)
+		ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE);
+	else
+		numtarg = (ahc->features & AHC_WIDE) ? 16 : 8;
+
+	if ((ahc->features & AHC_TWIN) != 0) {
+
+		if ((ahc->flags & AHC_RESET_BUS_B) != 0) {
+			ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE);
+		} else {
+			if (numtarg == 0)
+				i = 8;
+			numtarg += 8;
+		}
+	}
+
+	for (; i < numtarg; i++) {
+		struct ahc_devinfo devinfo;
+		struct ahc_initiator_tinfo *tinfo;
+		struct tmode_tstate *tstate;
+		u_int our_id;
+		u_int target_id;
+		char channel;
+
+		channel = 'A';
+		our_id = ahc->our_id;
+		target_id = i;
+		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 'B';
+			our_id = ahc->our_id_b;
+			target_id = i % 8;
+		}
+		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+					    target_id, &tstate);
+		tinfo->goal = tinfo->user;
+		ahc_compile_devinfo(&devinfo, our_id, target_id,
+				   CAM_LUN_WILDCARD, channel, ROLE_INITIATOR);
+		ahc_update_target_msg_request(ahc, &devinfo, tinfo,
+					     /*force*/FALSE, /*paused*/FALSE);
+	}
+	/* Give the bus some time to recover */
+	if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {
+		ahc->platform_data->qfrozen++;
+		init_timer(&ahc->platform_data->reset_timer);
+		ahc->platform_data->reset_timer.data = (u_long)ahc;
+		ahc->platform_data->reset_timer.expires =
+		    jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;
+		ahc->platform_data->reset_timer.function =
+		    ahc_release_sim_queue;
+		add_timer(&ahc->platform_data->reset_timer);
+	}
+}
+
+int
+ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
+{
+	ahc->platform_data =
+	    malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT);
+	if (ahc->platform_data == NULL)
+		return (ENOMEM);
+	memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));
+	TAILQ_INIT(&ahc->platform_data->completeq);
+	LIST_INIT(&ahc->platform_data->device_runq);
+	ahc_lockinit(ahc);
+	ahc_done_lockinit(ahc);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	init_MUTEX_LOCKED(&ahc->platform_data->eh_sem);
+#else
+	ahc->platform_data->eh_sem = MUTEX_LOCKED;
+#endif
+	ahc->seltime = (aic7xxx_seltime & 0x3) << 4;
+	ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4;
+	return (0);
+}
+
+void
+ahc_platform_free(struct ahc_softc *ahc)
+{
+	if (ahc->platform_data != NULL) {
+		if (ahc->platform_data->host != NULL)
+			scsi_unregister(ahc->platform_data->host);
+		if (ahc->platform_data->irq)
+			free_irq(ahc->platform_data->irq, ahc);
+		if (ahc->tag == BUS_SPACE_PIO
+		 && ahc->bsh.ioport != 0)
+			release_region(ahc->bsh.ioport, 256);
+		if (ahc->tag == BUS_SPACE_MEMIO
+		 && ahc->bsh.maddr != NULL) {
+			u_long base_addr;
+
+			base_addr = (u_long)ahc->bsh.maddr;
+			base_addr &= PAGE_MASK;
+			iounmap((void *)base_addr);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			release_mem_region(ahc->platform_data->mem_busaddr,
+					   0x1000);
+#endif
+		}
+		free(ahc->platform_data, M_DEVBUF);
+	}
+}
+
+void
+ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
+{
+	ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb),
+				SCB_GET_CHANNEL(ahc, scb),
+				SCB_GET_LUN(scb), SCB_LIST_NULL,
+				ROLE_UNKNOWN, CAM_REQUEUE_REQ);
+}
+
+void
+ahc_platform_set_tags(struct ahc_softc *ahc,
+		      struct ahc_devinfo *devinfo, int enable)
+{
+	struct ahc_linux_device *dev;
+
+	dev = ahc_get_device(ahc, devinfo->channel - 'A',
+			     devinfo->target,
+			     devinfo->lun, /*alloc*/FALSE);
+	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0
+	 && (dev->active != 0)) {
+		dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY;
+		dev->qfrozen++;
+	}
+
+	if (enable) {
+		/*
+		 * Start out agressively and allow our
+		 * dynamic queue depth algorithm take
+		 * care of the rest.
+		 */
+		dev->maxtags = AHC_MAX_QUEUE;
+		dev->openings = dev->maxtags - dev->active;
+	} else {
+		/* We can only have one opening */
+		dev->maxtags = 0;
+		dev->openings =  1 - dev->active;
+	}
+}
+
+int
+ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel,
+			int lun, u_int tag, role_t role, uint32_t status)
+{
+	int chan;
+	int maxchan;
+	int targ;
+	int maxtarg;
+	int clun;
+	int maxlun;
+	int count;
+
+	if (tag != SCB_LIST_NULL)
+		return (0);
+
+	chan = 0;
+	if (channel != ALL_CHANNELS) {
+		chan = channel - 'A';
+		maxchan = chan + 1;
+	} else {
+		maxchan = (ahc->features & AHC_TWIN) ? 2 : 1;
+	}
+	targ = 0;
+	if (target != CAM_TARGET_WILDCARD) {
+		targ = target;
+		maxtarg = targ + 1;
+	} else {
+		maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8;
+	}
+	clun = 0;
+	if (lun != CAM_LUN_WILDCARD) {
+		clun = lun;
+		maxlun = clun + 1;
+	} else {
+		maxlun = 16;
+	}
+
+	count = 0;
+	for (; chan < maxchan; chan++) {
+		for (; targ < maxtarg; targ++) {
+			for (; clun < maxlun; clun++) {
+				struct ahc_linux_device *dev;
+				struct ahc_busyq *busyq;
+				struct ahc_cmd *acmd;
+
+				dev = ahc_get_device(ahc, chan, targ,
+						     clun, /*alloc*/FALSE);
+
+				if (dev == NULL)
+					continue;
+
+				busyq = &dev->busyq;
+				while ((acmd = TAILQ_FIRST(busyq)) != NULL) {
+					Scsi_Cmnd *cmd;
+
+					cmd = &acmd_scsi_cmd(acmd);
+					TAILQ_REMOVE(busyq, acmd,
+						     acmd_links.tqe);
+					count++;
+					cmd->result = status << 16;
+					ahc_queue_cmd_complete(ahc, cmd);
+				}
+			}
+		}
+	}
+
+	return (count);
+}
+
+/*
+ * Sets the queue depth for each SCSI device hanging
+ * off the input host adapter.
+ */
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host * host,
+			   Scsi_Device * scsi_devs)
+{
+	Scsi_Device *device;
+	struct	ahc_softc *ahc;
+	u_long	flags;
+	int	scbnum;
+
+	ahc = *((struct ahc_softc **)host->hostdata);
+	ahc_lock(ahc, &flags);
+	scbnum = 0;
+	for (device = scsi_devs; device != NULL; device = device->next) {
+		if (device->host == host) {
+			aic7xxx_device_queue_depth(ahc, device);
+			scbnum += device->queue_depth;
+		}
+	}
+	ahc_unlock(ahc, &flags);
+}
+
+/*
+ * Determines the queue depth for a given device.
+ */
+static void
+aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
+{
+	struct	ahc_devinfo devinfo;
+	struct	ahc_initiator_tinfo *targ_info;
+	struct	tmode_tstate *tstate;
+	uint8_t tags;
+
+	ahc_compile_devinfo(&devinfo,
+			    device->channel == 0 ? ahc->our_id : ahc->our_id_b,
+			    device->id, device->lun,
+			    device->channel == 0 ? 'A' : 'B',
+			    ROLE_INITIATOR);
+	targ_info = ahc_fetch_transinfo(ahc, devinfo.channel,
+					devinfo.our_scsiid,
+					devinfo.target, &tstate);
+
+	tags = 0;
+	if (device->tagged_supported != 0
+	 && (tstate->discenable & devinfo.target_mask) != 0) {
+		if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {
+
+			printf("aic7xxx: WARNING, insufficient "
+			       "tag_info instances for installed "
+			       "controllers. Using defaults\n");
+			printf("aic7xxx: Please update the "
+			       "aic7xxx_tag_info array in the "
+			       "aic7xxx.c source file.\n");
+			tags = AHC_MAX_QUEUE;
+		} else {
+			adapter_tag_info_t *tag_info;
+
+			tag_info = &aic7xxx_tag_info[ahc->unit];
+			tags = tag_info->tag_commands[devinfo.target_offset];
+			if (tags > AHC_MAX_QUEUE)
+				tags = AHC_MAX_QUEUE;
+		}
+	}
+	if (tags != 0) {
+		device->queue_depth = tags;
+		ahc_set_tags(ahc, &devinfo, TRUE);
+		printf("scsi%d:%d:%d:%d: Tagged Queuing enabled.  Depth %d\n",
+	       	       ahc->platform_data->host->host_no, device->channel,
+		       device->id, device->lun, tags);
+	} else {
+		/*
+		 * We allow the OS to queue 2 untagged transactions to
+		 * us at any time even though we can only execute them
+		 * serially on the controller/device.  This should remove
+		 * some latency.
+		 */
+		device->queue_depth = 2;
+	}
+}
+
+/*
+ * Queue an SCB to the controller.
+ */
+int
+aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+{
+	struct	 ahc_softc *ahc;
+	struct	 ahc_linux_device *dev;
+	u_long	 flags;
+
+	ahc = *(struct ahc_softc **)cmd->host->hostdata;
+
+	/*
+	 * Save the callback on completion function.
+	 */
+	cmd->scsi_done = scsi_done;
+
+	ahc_lock(ahc, &flags);
+	dev = ahc_get_device(ahc, cmd->channel, cmd->target,
+			     cmd->lun, /*alloc*/TRUE);
+	if (dev == NULL) {
+		ahc_unlock(ahc, &flags);
+		printf("aic7xxx_queue: Unable to allocate device!\n");
+		return (-ENOMEM);
+	}
+	cmd->result = CAM_REQ_INPROG << 16;
+	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
+	ahc_run_device_queue(ahc, dev);
+	ahc_unlock(ahc, &flags);
+	return (0);
+}
+
+static void
+ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	struct	 ahc_cmd *acmd;
+	struct	 scsi_cmnd *cmd;
+	struct	 scb *scb;
+	struct	 hardware_scb *hscb;
+	struct	 ahc_initiator_tinfo *tinfo;
+	struct	 tmode_tstate *tstate;
+	uint16_t mask;
+
+	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
+	    && dev->openings > 0 && dev->qfrozen == 0) {
+
+		/*
+		 * Schedule us to run later.  The only reason we are not
+		 * running is because the whole controller Q is frozen.
+		 */
+		if (ahc->platform_data->qfrozen != 0) {
+			if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0)
+				return;
+
+			LIST_INSERT_HEAD(&ahc->platform_data->device_runq,
+					 dev, links);
+			dev->flags |= AHC_DEV_ON_RUN_LIST;
+			return;
+		}
+		/*
+		 * Get an scb to use.
+		 */
+		if ((scb = ahc_get_scb(ahc)) == NULL) {
+			if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0)
+				panic("running device on run list");
+			LIST_INSERT_HEAD(&ahc->platform_data->device_runq,
+					 dev, links);
+			dev->flags |= AHC_DEV_ON_RUN_LIST;
+			ahc->flags |= AHC_RESOURCE_SHORTAGE;
+			printf("%s: Temporary Resource Shortage\n",
+			       ahc_name(ahc));
+			return;
+		}
+		TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe);
+		cmd = &acmd_scsi_cmd(acmd);
+		scb->io_ctx = cmd;
+		scb->platform_data->dev = dev;
+		hscb = scb->hscb;
+		cmd->host_scribble = (char *)scb;
+
+		/*
+		 * Fill out basics of the HSCB.
+		 */
+		hscb->control = 0;
+		hscb->scsiid = BUILD_SCSIID(ahc, cmd);
+		hscb->lun = cmd->lun;
+		mask = SCB_GET_TARGET_MASK(ahc, scb);
+		tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb),
+					    SCB_GET_OUR_ID(scb),
+					    SCB_GET_TARGET(ahc, scb), &tstate);
+		hscb->scsirate = tinfo->scsirate;
+		hscb->scsioffset = tinfo->current.offset;
+		if ((tstate->ultraenb & mask) != 0)
+			hscb->control |= ULTRAENB;
+
+		if ((tstate->discenable & mask) != 0)
+			hscb->control |= DISCENB;
+
+		if ((tstate->tagenable & mask) != 0) {
+			/* XXX What about devices that dislike ordered tags? */
+			if ((dev->num_commands % 256) == 0)
+				hscb->control |= MSG_ORDERED_Q_TAG;
+			else
+				hscb->control |= MSG_SIMPLE_Q_TAG;
+		}
+
+		hscb->cdb_len = cmd->cmd_len;
+		if (hscb->cdb_len <= 12) {
+			memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len);
+		} else {
+			memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len);
+			scb->flags |= SCB_CDB32_PTR;
+		}
+
+		scb->platform_data->xfer_len = 0;
+		if (cmd->use_sg != 0) {
+			struct	ahc_dma_seg *sg;
+			struct	scatterlist *cur_seg;
+			struct	scatterlist *end_seg;
+			int	nseg;
+
+			cur_seg = (struct scatterlist *)cmd->request_buffer;
+			nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
+				 scsi_to_pci_dma_dir(cmd ->sc_data_direction));
+			end_seg = cur_seg + nseg;
+			/* Copy the segments into the SG list. */
+			sg = scb->sg_list;
+			while(cur_seg < end_seg) {
+				sg->addr = ahc_htole32(sg_dma_address(cur_seg));
+/* XXX Add in the 5th byte of the address later.*/
+				sg->len = ahc_htole32(sg_dma_len(cur_seg));
+				scb->platform_data->xfer_len +=
+				    sg_dma_len(cur_seg);
+				sg++;
+				cur_seg++;
+			}
+			sg--;
+			sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
+
+			/*
+			 * Reset the sg list pointer.
+			 */
+			scb->hscb->sgptr =
+			    ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+
+			/*
+			 * Copy the first SG into the "current"
+			 * data pointer area.
+			 */
+			scb->hscb->dataptr = scb->sg_list->addr;
+			scb->hscb->datacnt = scb->sg_list->len;
+
+			/*
+			 * Remember the number of segments for later
+			 * residual calculations.
+			 */
+			scb->sg_count = nseg;
+		} else if (cmd->request_bufflen != 0) {
+			struct	 ahc_dma_seg *sg;
+			uint32_t baddr;
+
+			sg = scb->sg_list;
+			baddr = pci_map_single(ahc->dev_softc,
+			       cmd->request_buffer,
+			       cmd->request_bufflen,
+			       scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			sg->addr = ahc_htole32(baddr);
+			sg->len = ahc_htole32(cmd->request_bufflen
+					      | AHC_DMA_LAST_SEG);
+
+			/*
+			 * Reset the sg list pointer.
+			 */
+			scb->hscb->sgptr =
+			    ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+
+			/*
+			 * Copy the first SG into the "current"
+			 * data pointer area.
+			 */
+			scb->hscb->dataptr = sg->addr;
+			scb->hscb->datacnt = sg->len;
+			scb->platform_data->xfer_len = cmd->request_bufflen;
+
+			/*
+			 * Remember the number of segments for later
+			 * residual calculations.
+			 */
+			scb->sg_count = 1;
+		} else {
+			scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);
+			scb->hscb->dataptr = 0;
+			scb->hscb->datacnt = 0;
+			scb->sg_count = 0;
+		}
+
+		LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
+		dev->openings--;
+		dev->active++;
+		dev->num_commands++;
+
+		/*
+		 * We only allow one untagged transaction
+		 * per target in the initiator role unless
+		 * we are storing a full busy target *lun*
+		 * table in SCB space.
+		 */
+		if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
+		 && (ahc->features & AHC_SCB_BTT) == 0) {
+			struct scb_tailq *untagged_q;
+			int target_offset;
+
+			target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
+			untagged_q = &(ahc->untagged_queues[target_offset]);
+			TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
+			scb->flags |= SCB_UNTAGGEDQ;
+			if (TAILQ_FIRST(untagged_q) != scb)
+				continue;
+		}
+		scb->flags |= SCB_ACTIVE;
+		ahc_queue_scb(ahc, scb);
+	}
+}
+
+/*
+ * SCSI controller interrupt handler.
+ */
+void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct ahc_softc *ahc;
+	struct ahc_cmd *acmd;
+	u_long flags;
+
+	ahc = (struct ahc_softc *) dev_id;
+	ahc_lock(ahc, &flags); 
+	ahc_intr(ahc);
+	/*
+	 * It would be nice to run the device queues from a
+	 * bottom half handler, but as there is no way to
+	 * dynamically register one, we'll have to postpone
+	 * that until we get integrated into the kernel.
+	 */
+	ahc_run_device_queues(ahc);
+	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
+	TAILQ_INIT(&ahc->platform_data->completeq);
+	ahc_unlock(ahc, &flags);
+	if (acmd != NULL)
+		ahc_run_complete_queue(ahc, acmd);
+}
+
+void
+ahc_platform_flushwork(struct ahc_softc *ahc)
+{
+	struct ahc_cmd *acmd;
+
+	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
+	TAILQ_INIT(&ahc->platform_data->completeq);
+	if (acmd != NULL)
+		ahc_run_complete_queue(ahc, acmd);
+}
+
+static struct ahc_linux_target*
+ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
+{
+	struct ahc_linux_target *targ;
+	u_int target_offset;
+
+	targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT);
+	if (targ == NULL)
+		return (NULL);
+	memset(targ, 0, sizeof(*targ));
+	targ->channel = channel;
+	targ->target = target;
+	target_offset = target;
+	if (channel != 0)
+		target_offset += 8;
+	ahc->platform_data->targets[target_offset] = targ;
+	return (targ);
+}
+
+static void
+ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
+{
+	u_int target_offset;
+
+	target_offset = targ->target;
+	if (targ->channel != 0)
+		target_offset += 8;
+	ahc->platform_data->targets[target_offset] = NULL;
+	free(targ, M_DEVBUF);
+}
+
+static struct ahc_linux_device*
+ahc_alloc_device(struct ahc_softc *ahc,
+		 struct ahc_linux_target *targ, u_int lun)
+{
+	struct ahc_linux_device *dev;
+
+	dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);
+	if (dev == NULL)
+		return (NULL);
+	memset(dev, 0, sizeof(*dev));
+	TAILQ_INIT(&dev->busyq);
+	dev->flags = AHC_DEV_UNCONFIGURED;
+	dev->lun = lun;
+	dev->target = targ;
+
+	/*
+	 * We start out life using untagged
+	 * transactions of which we allow one.
+	 */
+	dev->openings = 1;
+
+	/*
+	 * Set maxtags to 0.  This will be changed if we
+	 * later determine that we are dealing with
+	 * a tagged queuing capable device.
+	 */
+	dev->maxtags = 0;
+	
+	targ->refcount++;
+	targ->devices[lun] = dev;
+	return (dev);
+}
+
+static void
+ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	struct ahc_linux_target *targ;
+
+	targ = dev->target;
+	targ->devices[dev->lun] = NULL;
+	free(dev, M_DEVBUF);
+	targ->refcount--;
+	if (targ->refcount == 0)
+		ahc_free_target(ahc, targ);
+}
+
+/*
+ * Return a string describing the driver.
+ */
+const char *
+aic7xxx_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+	char	ahc_info[256];
+	char   *bp;
+	struct ahc_softc *ahc;
+
+	bp = &buffer[0];
+	ahc = *(struct ahc_softc **)host->hostdata;
+	memset(bp, 0, sizeof(buffer));
+	strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
+	strcat(bp, AIC7XXX_DRIVER_VERSION);
+	strcat(bp, "\n");
+	strcat(bp, "        <");
+	strcat(bp, ahc->description);
+	strcat(bp, ">\n");
+	strcat(bp, "        ");
+	ahc_controller_info(ahc, ahc_info);
+	strcat(bp, ahc_info);
+	strcat(bp, "\n");
+
+	return (bp);
+}
+
+void
+ahc_send_async(struct ahc_softc *ahc, char channel,
+	       u_int target, u_int lun, ac_code code)
+{
+	switch (code) {
+	case AC_TRANSFER_NEG:
+	{
+		char	buf[80];
+		struct	ahc_linux_target *targ;
+		struct	info_str info;
+		struct	ahc_initiator_tinfo *tinfo;
+		struct	tmode_tstate *tstate;
+		int	target_offset;
+
+		info.buffer = buf;
+		info.length = sizeof(buf);
+		info.offset = 0;
+		info.pos = 0;
+		tinfo = ahc_fetch_transinfo(ahc, channel,
+						channel == 'A' ? ahc->our_id
+							       : ahc->our_id_b,
+						target, &tstate);
+
+		/*
+		 * Don't bother reporting results while
+		 * negotiations are still pending.
+		 */
+		if (tinfo->current.period != tinfo->goal.period
+		 || tinfo->current.width != tinfo->goal.width
+		 || tinfo->current.offset != tinfo->goal.offset
+		 || tinfo->current.ppr_options != tinfo->goal.ppr_options)
+			if (bootverbose == 0)
+				break;
+
+		/*
+		 * Don't bother reporting results that
+		 * are identical to those last reported.
+		 */
+		target_offset = target;
+		if (channel == 'B')
+			target_offset += 8;
+		targ = ahc->platform_data->targets[target_offset];
+		if (targ != NULL
+		 && tinfo->current.period == targ->last_tinfo.period
+		 && tinfo->current.width == targ->last_tinfo.width
+		 && tinfo->current.offset == targ->last_tinfo.offset
+		 && tinfo->current.ppr_options == targ->last_tinfo.ppr_options)
+			if (bootverbose == 0)
+				break;
+
+		targ->last_tinfo.period = tinfo->current.period;
+		targ->last_tinfo.width = tinfo->current.width;
+		targ->last_tinfo.offset = tinfo->current.offset;
+		targ->last_tinfo.ppr_options = tinfo->current.ppr_options;
+
+		printf("(%s:%c:", ahc_name(ahc), channel);
+		if (target == CAM_TARGET_WILDCARD)
+			printf("*): ");
+		else
+			printf("%d): ", target);
+		ahc_format_transinfo(&info, &tinfo->current);
+		if (info.pos < info.length)
+			*info.buffer = '\0';
+		else
+			buf[info.length - 1] = '\0';
+		printf("%s", buf);
+		break;
+	}
+        case AC_SENT_BDR:
+		break;
+        case AC_BUS_RESET:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+		scsi_report_bus_reset(ahc->platform_data->host, channel - 'A');
+#endif
+                break;
+        default:
+                panic("ahc_send_async: Unexpected async event");
+        }
+}
+
+/*
+ * Calls the higher level scsi done function and frees the scb.
+ */
+void
+ahc_done(struct ahc_softc *ahc, struct scb * scb)
+{
+	Scsi_Cmnd *cmd;
+	struct ahc_linux_device *dev;
+
+	LIST_REMOVE(scb, pending_links);
+	if ((scb->flags & SCB_UNTAGGEDQ) != 0) {
+		struct scb_tailq *untagged_q;
+		int target_offset;
+
+		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
+		untagged_q = &(ahc->untagged_queues[target_offset]);
+		TAILQ_REMOVE(untagged_q, scb, links.tqe);
+		ahc_run_untagged_queue(ahc, untagged_q);
+	}
+
+	if ((scb->flags & SCB_ACTIVE) == 0) {
+		printf("SCB %d done'd twice\n", scb->hscb->tag);
+		ahc_dump_card_state(ahc);
+		panic("Stopping for safety");
+	}
+	cmd = scb->io_ctx;
+	dev = scb->platform_data->dev;
+	dev->active--;
+	dev->openings++;
+	ahc_unmap_scb(ahc, scb);
+	if (scb->flags & SCB_SENSE) {
+		memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb),
+		       MIN(sizeof(struct scsi_sense_data),
+			   sizeof(cmd->sense_buffer)));
+	}
+	if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) {
+		uint32_t amount_xferred;
+
+		amount_xferred =
+		    ahc_get_transfer_length(scb) - ahc_get_residual(scb);
+		if (amount_xferred < scb->io_ctx->underflow) {
+			printf("Saw underflow (%ld of %ld bytes). "
+			       "Treated as error\n",
+				ahc_get_residual(scb),
+				ahc_get_transfer_length(scb));
+			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		} else {
+			ahc_set_transaction_status(scb, CAM_REQ_CMP);
+			ahc_sniff_command(ahc, cmd);
+		}
+	} else if (ahc_get_transaction_status(scb) == DID_OK) {
+		ahc_handle_scsi_status(ahc, dev, scb);
+	}
+
+	if (dev->openings == 1
+	 && ahc_get_transaction_status(scb) == CAM_REQ_CMP
+	 && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)
+		dev->tag_success_count++;
+	/*
+	 * Some devices deal with temporary internal resource
+	 * shortages by returning queue full.  When the queue
+	 * full occurrs, we throttle back.  Slowly try to get
+	 * back to our previous queue depth.
+	 */
+	if ((dev->openings + dev->active) < dev->maxtags
+	 && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) {
+		dev->tag_success_count = 0;
+		dev->openings++;
+	}
+
+	if (dev->active == 0
+	 && (dev->flags & AHC_DEV_UNCONFIGURED) != 0)
+		ahc_free_device(ahc, dev);
+	else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
+		LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links);
+		dev->flags |= AHC_DEV_ON_RUN_LIST;
+	}
+
+	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
+		printf("Recovery SCB completes\n");
+		up(&ahc->platform_data->eh_sem);
+	}
+
+	ahc_free_scb(ahc, scb);
+	ahc_queue_cmd_complete(ahc, cmd);
+}
+
+static void
+ahc_handle_scsi_status(struct ahc_softc *ahc,
+		       struct ahc_linux_device *dev, struct scb *scb)
+{
+	/*
+	 * We don't currently trust the mid-layer to
+	 * properly deal with queue full or busy.  So,
+	 * when one occurs, we tell the mid-layer to
+	 * unconditionally requeue the command to us
+	 * so that we can retry it ourselves.  We also
+	 * implement our own throttling mechanism so
+	 * we don't clobber the device with too many
+	 * commands.
+	 */
+	switch (ahc_get_scsi_status(scb)) {
+	default:
+		break;
+	case SCSI_STATUS_QUEUE_FULL:
+	{
+		/*
+		 * By the time the core driver has returned this
+		 * command, all other commands that were queued
+		 * to us but not the device have been returned.
+		 * This ensures that dev->active is equal to
+		 * the number of commands actually queued to
+		 * the device.
+		 */
+		dev->tag_success_count = 0;
+		if (dev->active != 0) {
+			/*
+			 * Drop our opening count to the number
+			 * of commands currently outstanding.
+			 */
+			dev->openings = 0;
+/*
+			ahc_print_path(ahc, scb);
+			printf("Dropping tag count to %d\n", dev->active);
+ */
+			if (dev->active == dev->tags_on_last_queuefull) {
+
+				dev->last_queuefull_same_count++;
+				/*
+				 * If we repeatedly see a queue full
+				 * at the same queue depth, this
+				 * device has a fixed number of tag
+				 * slots.  Lock in this tag depth
+				 * so we stop seeing queue fulls from
+				 * this device.
+				 */
+				if (dev->last_queuefull_same_count
+				 == AHC_LOCK_TAGS_COUNT) {
+					dev->maxtags = dev->active;
+					ahc_print_path(ahc, scb);
+					printf("Locking max tag count at %d\n",
+					       dev->active);
+				}
+			} else {
+				dev->tags_on_last_queuefull = dev->active;
+				dev->last_queuefull_same_count = 0;
+			}
+			ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);
+			ahc_set_scsi_status(scb, SCSI_STATUS_OK);
+			break;
+		}
+		/*
+		 * Drop down to a single opening, and treat this
+		 * as if the target return BUSY SCSI status.
+		 */
+		dev->openings = 1;
+		/* FALLTHROUGH */
+	}
+	case SCSI_STATUS_BUSY:
+		/*
+		 * XXX Set a timer and handle ourselves????
+		 * For now we pray that the mid-layer does something
+		 * sane for devices that are busy.
+		 */
+		ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);
+		break;
+	}
+}
+
+static void
+ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) {
+	case INQUIRY:
+	{
+		struct	ahc_devinfo devinfo;
+		struct	scsi_inquiry_data *sid;
+		struct	ahc_initiator_tinfo *targ_info;
+		struct	tmode_tstate *tstate;
+		struct	ahc_syncrate *syncrate;
+		u_int	scsiid;
+		u_int	maxsync;
+		int	minlen;
+		u_int	width;
+		u_int	period;
+		u_int	offset;
+		u_int	ppr_options;
+
+		if (cmd->use_sg != 0) {
+			printf("%s: SG Inquiry response ignored\n",
+			       ahc_name(ahc));
+			break;
+		}
+		sid = (struct scsi_inquiry_data *)cmd->request_buffer;
+
+		/*
+		 * Determine if this lun actually exists.  If so,
+		 * hold on to its corresponding device structure.
+		 */
+		if (cmd->request_bufflen >= 1
+		 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
+			struct ahc_linux_device *dev;
+
+			dev = ahc_get_device(ahc, cmd->channel,
+					     cmd->target, cmd->lun,
+					     /*alloc*/FALSE);
+			dev->flags &= ~AHC_DEV_UNCONFIGURED;
+		}
+
+		/*
+		 * Update our notion of this device's transfer
+		 * negotiation capabilities.
+		 */
+		scsiid = BUILD_SCSIID(ahc, cmd);
+		ahc_compile_devinfo(&devinfo, SCSIID_OUR_ID(scsiid),
+				    cmd->target, cmd->lun,
+				    SCSIID_CHANNEL(ahc, scsiid),
+				    ROLE_INITIATOR);
+		targ_info = ahc_fetch_transinfo(ahc, devinfo.channel,
+						devinfo.our_scsiid,
+						devinfo.target, &tstate);
+		/* Structure copy */
+		width = targ_info->user.width;
+		period = targ_info->user.period;
+		offset = targ_info->user.offset;
+		ppr_options = targ_info->user.ppr_options;
+		minlen = offsetof(struct scsi_inquiry_data, version) + 1;
+		if (cmd->request_bufflen >= minlen) {
+			targ_info->current.protocol_version = SID_ANSI_REV(sid);
+
+			/*
+			 * Only attempt SPI3 once we've verified that
+			 * the device claims to support SPI3 features.
+			 */
+			if (targ_info->current.protocol_version < SCSI_REV_2)
+				targ_info->current.transport_version =
+				    SID_ANSI_REV(sid);
+			else
+				targ_info->current.transport_version =
+				     SCSI_REV_2;
+		}
+
+		minlen = offsetof(struct scsi_inquiry_data, flags) + 1;
+		if (cmd->request_bufflen >= minlen
+		 && (sid->additional_length + 4) >= minlen) {
+			if ((sid->flags & SID_WBus16) == 0)
+				width = MSG_EXT_WDTR_BUS_8_BIT;
+			if ((sid->flags & SID_Sync) == 0) {
+				period = 0;
+				offset = 0;
+				ppr_options = 0;
+			}
+		} else {
+			/* Keep current settings */
+			break;
+		}
+		minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1;
+		if (cmd->request_bufflen >= minlen
+		 && (sid->additional_length + 4) >= minlen) {
+			if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
+				ppr_options = 0;
+
+			if ((sid->spi3data & SID_SPI_MASK) != 0
+			 && targ_info->current.protocol_version > SCSI_REV_2)
+				targ_info->current.transport_version = 3;
+		} else {
+			ppr_options = 0;
+		}
+
+		ahc_validate_width(ahc, /*tinfo limit*/NULL, &width,
+				   ROLE_UNKNOWN);
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			maxsync = AHC_SYNCRATE_DT;
+		else if ((ahc->features & AHC_ULTRA) != 0)
+			maxsync = AHC_SYNCRATE_ULTRA;
+		else
+			maxsync = AHC_SYNCRATE_FAST;
+
+		syncrate = ahc_find_syncrate(ahc, &period,
+					     &ppr_options, maxsync);
+		ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate,
+				    &offset, width, ROLE_UNKNOWN);
+		/* Apply our filtered user settings. */
+		ahc_set_width(ahc, &devinfo, width,
+			      AHC_TRANS_GOAL, /*paused*/FALSE);
+		ahc_set_syncrate(ahc, &devinfo, syncrate, period,
+				 offset, ppr_options, AHC_TRANS_GOAL,
+				 /*paused*/FALSE);
+		break;
+	}
+	default:
+		panic("ahc_filter_command: Unexpected Command type  %x\n",
+		      cmd->cmnd[0]);
+		break;
+	}
+}
+
+static void
+ahc_sem_timeout(u_long arg)
+{
+	struct semaphore *sem;
+
+	sem = (struct semaphore *)arg;
+	up(sem);
+}
+
+static void
+ahc_release_sim_queue(u_long arg)
+{
+	struct ahc_softc *ahc;
+	u_long s;
+
+	ahc = (struct ahc_softc *)arg;
+	ahc_lock(ahc, &s);
+	if (ahc->platform_data->qfrozen > 0)
+		ahc->platform_data->qfrozen--;
+	if (ahc->platform_data->qfrozen == 0)
+		ahc_run_device_queues(ahc);
+	ahc_unlock(ahc, &s);
+}
+
+static int
+aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
+{
+	struct ahc_softc *ahc;
+	struct ahc_cmd *acmd;
+	struct ahc_cmd *list_acmd;
+	struct ahc_linux_device *dev;
+	struct scb *pending_scb;
+	u_long s;
+	u_int  saved_scbptr;
+	u_int  active_scb_index;
+	u_int  last_phase;
+	int    retval;
+	int    paused;
+	int    wait;
+	int    disconnected;
+
+	paused = FALSE;
+	wait = FALSE;
+	ahc = *(struct ahc_softc **)cmd->host->hostdata;
+	acmd = (struct ahc_cmd *)cmd;
+
+	printf("%s:%d:%d:%d: Attempting to queue a%s message\n",
+	       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun,
+	       flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
+
+	/*
+	 * It is a bug that the upper layer takes
+	 * this lock just prior to calling us.
+	 */
+	spin_unlock_irq(&io_request_lock);
+
+	ahc_lock(ahc, &s);
+
+	/*
+	 * First determine if we currently own this command.
+	 * Start by searching the device queue.  If not found
+	 * there, check the pending_scb list.  If not found
+	 * at all, and the system wanted us to just abort the
+	 * command return success.
+	 */
+	dev = ahc_get_device(ahc, cmd->channel, cmd->target,
+			     cmd->lun, /*alloc*/FALSE);
+
+	if (dev == NULL) {
+		/*
+		 * No target device for this command exists,
+		 * so we must not still own the command.
+		 */
+		printf("%s:%d:%d:%d: Is not an active device\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		retval = SUCCESS;
+		goto no_cmd;
+	}
+
+	TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {
+		if (list_acmd == acmd)
+			break;
+	}
+
+	if (list_acmd != NULL) {
+		printf("%s:%d:%d:%d: Command found on device queue\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		if (flag == SCB_ABORT) {
+			TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
+			cmd->result = DID_ABORT << 16;
+			ahc_queue_cmd_complete(ahc, cmd);
+			retval = SUCCESS;
+			goto done;
+		}
+	}
+
+	/*
+	 * See if we can find a matching cmd in the pending list.
+	 */
+	LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
+		if (pending_scb->io_ctx == cmd)
+			break;
+	}
+
+	if (pending_scb == NULL && flag == SCB_DEVICE_RESET) {
+
+		/* Any SCB for this device will do for a target reset */
+		LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
+		  	if (ahc_match_scb(ahc, pending_scb, cmd->target,
+					  cmd->channel, CAM_LUN_WILDCARD,
+					  SCB_LIST_NULL, ROLE_INITIATOR) == 0)
+				break;
+		}
+	}
+
+	if (pending_scb == NULL) {
+		printf("%s:%d:%d:%d: Command not found\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		goto no_cmd;
+	}
+
+	if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) {
+		/*
+		 * We can't queue two recovery actions using the same SCB
+		 */
+		retval = FAILED;
+		goto  done;
+	}
+
+	/*
+	 * Ensure that the card doesn't do anything
+	 * behind our back.  Also make sure that we
+	 * didn't "just" miss an interrupt that would
+	 * affect this cmd.
+	 */
+	ahc->flags |= AHC_ALL_INTERRUPTS;
+	do {
+		ahc_intr(ahc);
+		pause_sequencer(ahc);
+		ahc_clear_critical_section(ahc);
+	} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
+	ahc->flags &= ~AHC_ALL_INTERRUPTS;
+	paused = TRUE;
+
+	if (bootverbose)
+		ahc_dump_card_state(ahc);
+
+	if ((pending_scb->flags & SCB_ACTIVE) == 0) {
+		printf("%s:%d:%d:%d: Command already completed\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		goto no_cmd;
+	}
+
+	disconnected = TRUE;
+	if (flag == SCB_ABORT) {
+		if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A',
+				       cmd->lun, pending_scb->hscb->tag,
+				       ROLE_INITIATOR, CAM_REQ_ABORTED,
+				       SEARCH_COMPLETE) > 0) {
+			printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+			       ahc_name(ahc), cmd->channel, cmd->target,
+					cmd->lun);
+			retval = SUCCESS;
+			goto done;
+		}
+	} else if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A',
+				      cmd->lun, pending_scb->hscb->tag,
+				      ROLE_INITIATOR, /*status*/0,
+				      SEARCH_COUNT) > 0) {
+		disconnected = FALSE;
+	}
+
+	/*
+	 * At this point, pending_scb is the scb associated with the
+	 * passed in command.  That command is currently active on the
+	 * bus, is in the disconnected state, or we're hoping to find
+	 * a command for the same target active on the bus to abuse to
+	 * send a BDR.  Queue the appropriate message based on which of
+	 * these states we are in.
+	 */
+	last_phase = ahc_inb(ahc, LASTPHASE);
+	saved_scbptr = ahc_inb(ahc, SCBPTR);
+	active_scb_index = ahc_inb(ahc, SCB_TAG);
+	if (last_phase != P_BUSFREE
+	 && (pending_scb->hscb->tag == active_scb_index
+	  || (flag == SCB_DEVICE_RESET
+	   && SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)) == cmd->target))) {
+
+		/*
+		 * We're active on the bus, so assert ATN
+		 * and hope that the target responds.
+		 */
+		pending_scb = ahc_lookup_scb(ahc, active_scb_index);
+		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
+		ahc_outb(ahc, MSG_OUT, HOST_MSG);
+		ahc_outb(ahc, SCSISIGO, last_phase|ATNO);
+		printf("%s:%d:%d:%d: Device is active, asserting ATN\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		wait = TRUE;
+	} else if (disconnected) {
+
+		/*
+		 * Actually re-queue this SCB in an attempt
+		 * to select the device before it reconnects.
+		 * In either case (selection or reselection),
+		 * we will now issue a the approprate message
+		 * to the timed-out device.
+		 *
+		 * Set the MK_MESSAGE control bit indicating
+		 * that we desire to send a message.  We
+		 * also set the disconnected flag since
+		 * in the paging case there is no guarantee
+		 * that our SCB control byte matches the
+		 * version on the card.  We don't want the
+		 * sequencer to abort the command thinking
+		 * an unsolicited reselection occurred.
+		 */
+		pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
+		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
+
+		/*
+		 * Remove any cached copy of this SCB in the
+		 * disconnected list in preparation for the
+		 * queuing of our abort SCB.  We use the
+		 * same element in the SCB, SCB_NEXT, for
+		 * both the qinfifo and the disconnected list.
+		 */
+		ahc_search_disc_list(ahc, cmd->target, cmd->channel + 'A',
+				     cmd->lun, pending_scb->hscb->tag,
+				     /*stop_on_first*/TRUE,
+				     /*remove*/TRUE,
+				     /*save_state*/FALSE);
+
+		/*
+		 * In the non-paging case, the sequencer will
+		 * never re-reference the in-core SCB.
+		 * To make sure we are notified during
+		 * reslection, set the MK_MESSAGE flag in
+		 * the card's copy of the SCB.
+		 */
+		if ((ahc->flags & AHC_PAGESCBS) == 0) {
+			ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag);
+			ahc_outb(ahc, SCB_CONTROL,
+				 ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE);
+		}
+
+		/*
+		 * Clear out any entries in the QINFIFO first
+		 * so we are the next SCB for this target
+		 * to run.
+		 */
+		ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A',
+				   cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR,
+				   CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+		ahc_print_path(ahc, pending_scb);
+		printf("Queuing a recovery SCB\n");
+		ahc_qinfifo_requeue_tail(ahc, pending_scb);
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+		printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		wait = TRUE;
+	} else {
+		printf("%s:%d:%d:%d: Unable to deliver message\n",
+		       ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+		retval = FAILED;
+		goto done;
+	}
+
+no_cmd:
+	/*
+	 * Our assumption is that if we don't have the command, no
+	 * recovery action was required, so we return success.  Again,
+	 * the semantics of the mid-layer recovery engine are not
+	 * well defined, so this may change in time.
+	 */
+	retval = SUCCESS;
+done:
+	if (paused)
+		unpause_sequencer(ahc);
+	if (wait) {
+    		struct timer_list timer;
+		int ret;
+
+		ahc_unlock(ahc, &s);
+		init_timer(&timer);
+		timer.data = (u_long)&ahc->platform_data->eh_sem;
+		timer.expires = jiffies + (5 * HZ);
+		timer.function = ahc_sem_timeout;
+		add_timer(&timer);
+		printf("Recovery code sleeping\n");
+		down(&ahc->platform_data->eh_sem);
+		printf("Recovery code awake\n");
+        	ret = del_timer(&timer);
+		if (ret == 0) {
+			printf("Timer Expired\n");
+			retval = FAILED;
+		}
+		ahc_lock(ahc, &s);
+	}
+	ahc_run_device_queues(ahc);
+	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
+	TAILQ_INIT(&ahc->platform_data->completeq);
+	ahc_unlock(ahc, &s);
+	if (acmd != NULL)
+		ahc_run_complete_queue(ahc, acmd);
+	spin_lock_irq(&io_request_lock);
+	return (retval);
+}
+
+/*
+ * Abort the current SCSI command(s).
+ */
+int
+aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+	int error;
+
+	error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT);
+	if (error != 0)
+		printf("aic7xxx_abort returns %d\n", error);
+	return (error);
+}
+
+/*
+ * Attempt to send a target reset message to the device that timed out.
+ */
+int
+aic7xxx_dev_reset(Scsi_Cmnd *cmd)
+{
+	int error;
+
+	error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
+	if (error != 0)
+		printf("aic7xxx_dev_reset returns %d\n", error);
+	return (error);
+}
+
+/*
+ * Reset the SCSI bus.
+ */
+int
+aic7xxx_bus_reset(Scsi_Cmnd *cmd)
+{
+	struct ahc_softc *ahc;
+	struct ahc_cmd *acmd;
+	u_long s;
+	int    found;
+
+	/*
+	 * It is a bug that the upper layer takes
+	 * this lock just prior to calling us.
+	 */
+	spin_unlock_irq(&io_request_lock);
+
+	ahc = *(struct ahc_softc **)cmd->host->hostdata;
+	ahc_lock(ahc, &s);
+	found = ahc_reset_channel(ahc, cmd->channel + 'A',
+				  /*initiate reset*/TRUE);
+	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
+	TAILQ_INIT(&ahc->platform_data->completeq);
+	ahc_unlock(ahc, &s);
+	if (bootverbose)
+		printf("%s: SCSI bus reset delivered. "
+		       "%d SCBs aborted.\n", ahc_name(ahc), found);
+
+	if (acmd != NULL)
+		ahc_run_complete_queue(ahc, acmd);
+
+	spin_lock_irq(&io_request_lock);
+	return SUCCESS;
+}
+
+/*
+ * Return the disk geometry for the given SCSI device.
+ */
+int
+aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
+{
+	int	heads;
+	int	sectors;
+	int	cylinders;
+	int	ret;
+	int	extended;
+	struct	ahc_softc *ahc;
+	struct	buffer_head *bh;
+
+	ahc = *((struct ahc_softc **)disk->device->host->hostdata);
+	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
+
+	if (bh) {
+		ret = scsi_partsize(bh, disk->capacity,
+				    &geom[2], &geom[0], &geom[1]);
+		brelse(bh);
+		if (ret != -1)
+			return (ret);
+	}
+	heads = 64;
+	sectors = 32;
+	cylinders = disk->capacity / (heads * sectors);
+
+	if (disk->device->channel == 0)
+		extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0;
+	else
+		extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0;
+	if (extended && cylinders >= 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = disk->capacity / (heads * sectors);
+	}
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	return (0);
+}
+
+/*
+ * Free the passed in Scsi_Host memory structures prior to unloading the
+ * module.
+ */
+int
+aic7xxx_release(struct Scsi_Host * host)
+{
+	struct ahc_softc *ahc;
+
+	if (host != NULL) {
+		ahc = *(struct ahc_softc **)host->hostdata;
+		ahc_free(ahc);
+	}
+	return (0);
+}
+
+void
+ahc_platform_dump_card_state(struct ahc_softc *ahc)
+{
+	struct ahc_linux_device *dev;
+	int channel;
+	int maxchannel;
+	int target;
+	int maxtarget;
+	int lun;
+	int i;
+
+	maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0;
+	maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7;
+	for (channel = 0; channel <= maxchannel; channel++) {
+		for (target = 0; target <=maxtarget; target++) {
+			for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+				struct ahc_cmd *acmd;
+
+				dev = ahc_get_device(ahc, channel, target,
+						     lun, /*alloc*/FALSE);
+				if (dev == NULL)
+					continue;
+
+				printf("DevQ(%d:%d:%d): ",
+				       channel, target, lun);
+				i = 0;
+				TAILQ_FOREACH(acmd, &dev->busyq,
+					      acmd_links.tqe) {
+					if (i++ > 256)
+						break;
+				}
+				printf("%d waiting\n", i);
+			}
+		}
+	}
+}
+
+#if defined(MODULE) || LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+static Scsi_Host_Template driver_template = AIC7XXX;
+Scsi_Host_Template *aic7xxx_driver_template = &driver_template;
+#include "../scsi_module.c"
+#endif
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,87 @@
+/*
+ * Adaptec AIC7xxx device driver host template for Linux.
+ *
+ * Copyright (c) 2000 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $
+ */
+
+#ifndef _AIC7XXX_LINUX_HOST_H_
+#define _AIC7XXX_LINUX_HOST_H_
+
+int		 aic7xxx_proc_info(char *, char **, off_t, int, int, int);
+int		 aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+int		 aic7xxx_detect(Scsi_Host_Template *);
+int		 aic7xxx_release(struct Scsi_Host *);
+const char	*aic7xxx_info(struct Scsi_Host *);
+int		 aic7xxx_biosparam(Disk *, kdev_t, int[]);
+int		 aic7xxx_bus_reset(Scsi_Cmnd *);
+int		 aic7xxx_dev_reset(Scsi_Cmnd *);
+int		 aic7xxx_abort(Scsi_Cmnd *);
+
+#if defined(__i386__)
+#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+#else
+#  define AIC7XXX_BIOSPARAM NULL
+#endif
+
+/*
+ * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
+ * to do with card config are filled in after the card is detected.
+ */
+#define AIC7XXX	{						\
+	next: NULL,						\
+	module: NULL,						\
+	proc_dir: NULL,						\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: aic7xxx_release,				\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	eh_strategy_handler: NULL,				\
+	eh_abort_handler: aic7xxx_abort,			\
+	eh_device_reset_handler: aic7xxx_dev_reset,		\
+	eh_bus_reset_handler: aic7xxx_bus_reset,		\
+	eh_host_reset_handler: NULL,				\
+	abort: NULL,						\
+	reset: NULL,						\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 254,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 2,		/* cmds per lun		      */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING,			\
+	use_new_eh_code: 1					\
+}
+
+#endif /* _AIC7XXX_LINUX_HOST_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,316 @@
+/*
+ * Linux driver attachment glue for PCI based controllers.
+ *
+ * Copyright (c) 2000 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $
+ */
+
+#include "aic7xxx_osm.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+struct pci_device_id
+{
+};
+#endif
+
+static int	ahc_linux_pci_dev_probe(struct pci_dev *pdev,
+					const struct pci_device_id *ent);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
+
+/* We do our own ID filtering.  So, grab all SCSI storage class devices. */
+static struct pci_device_id ahc_linux_pci_id_table[] = {
+	{
+		0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
+	},
+	{
+		0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
+	},
+	{ 0 }
+};
+
+static struct pci_driver aic7xxx_pci_driver = {
+	name:		"aic7xxx",
+	probe:		ahc_linux_pci_dev_probe,
+	remove:		ahc_linux_pci_dev_remove,
+	id_table:	ahc_linux_pci_id_table
+};
+
+static void
+ahc_linux_pci_dev_remove(struct pci_dev *pdev)
+{
+	struct ahc_softc *ahc;
+	struct ahc_softc *list_ahc;
+
+	/*
+	 * We should be able to just perform
+	 * the free directly, but check our
+	 * list for extra sanity.
+	 */
+	ahc = (struct ahc_softc *)pdev->driver_data;
+	TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
+		if (list_ahc == ahc) {
+			ahc_free(ahc);
+			break;
+		}
+	}
+}
+#endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
+
+static int
+ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	char	 buf[80];
+	struct	 ahc_softc *ahc;
+	ahc_dev_softc_t pci;
+	struct	 ahc_pci_identity *entry;
+	char	*name;
+	int	 error;
+
+	pci = pdev;
+	entry = ahc_find_pci_device(pci);
+	if (entry == NULL)
+		return (-ENODEV);
+
+	/*
+	 * Allocate a softc for this card and
+	 * set it up for attachment by our
+	 * common detect routine.
+	 */
+	sprintf(buf, "ahc_pci:%d:%d:%d",
+		ahc_get_pci_bus(pci),
+		ahc_get_pci_slot(pci),
+		ahc_get_pci_function(pci));
+	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (name == NULL)
+		return (-ENOMEM);
+	strcpy(name, buf);
+	ahc = ahc_alloc(NULL, name);
+	if (ahc == NULL)
+		return (-ENOMEM);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	if (pci_enable_device(pdev)) {
+		ahc_free(ahc);
+		return (-ENODEV);
+	}
+	pci_set_master(pdev);
+#endif
+	ahc->dev_softc = pci;
+	ahc->platform_data->irq = pdev->irq;
+	error = ahc_pci_config(ahc, entry);
+	if (error != 0) {
+		ahc_free(ahc);
+		return (-error);
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pdev->driver_data = ahc;
+	if (aic7xxx_detect_complete)
+		aic7xxx_register_host(ahc, aic7xxx_driver_template);
+#endif
+	return (0);
+}
+
+int
+ahc_linux_pci_probe(Scsi_Host_Template *template)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	return (pci_module_init(&aic7xxx_pci_driver));
+#else
+	struct pci_dev *pdev;
+	u_int class;
+	int found;
+
+	/* If we don't have a PCI bus, we can't find any adapters. */
+	if (pci_present() == 0)
+		return (0);
+
+	found = 0;
+	pdev = NULL;
+	class = PCI_CLASS_STORAGE_SCSI << 8;
+	while ((pdev = pci_find_class(class, pdev)) != NULL) {
+		struct ahc_softc *ahc;
+		ahc_dev_softc_t pci;
+		int error;
+
+		pci = pdev;
+
+		/*
+		 * Some BIOSen report the same device multiple times.
+		 */
+		TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+			struct pci_dev *probed_pdev;
+
+			probed_pdev = ahc->dev_softc;
+			if (probed_pdev->bus->number == pdev->bus->number
+			 && probed_pdev->devfn == pdev->devfn)
+				break;
+		}
+		if (ahc != NULL) {
+			/* Skip duplicate. */
+			continue;
+		}
+
+		error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
+		if (error == 0)
+			found++;
+	}
+	return (found);
+#endif
+}
+
+int
+ahc_pci_map_registers(struct ahc_softc *ahc)
+{
+	uint32_t command;
+	u_long	 base;
+#ifdef MMAPIO
+	u_long	 start;
+	u_long	 base_page;
+	u_long	 base_offset;
+#endif
+	uint8_t *maddr;
+
+	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
+	base = 0;
+	maddr = NULL;
+#ifdef MMAPIO
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	start = pci_resource_start(ahc->dev_softc, 1);
+	base_page = start & PAGE_MASK;
+	base_offset = start - base_page;
+#else
+	start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4);
+	base_offset = start & PCI_BASE_ADDRESS_MEM_MASK;
+	base_page = base_offset & PAGE_MASK;
+	base_offset -= base_page;
+#endif
+	if (start != 0) {
+		ahc->platform_data->mem_busaddr = start;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		if (request_mem_region(start, 0x1000, "aic7xxx") == 0) {
+			printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
+			       "in use. Cannot map device.\n",
+			       ahc_get_pci_bus(ahc->dev_softc),
+			       ahc_get_pci_slot(ahc->dev_softc),
+			       ahc_get_pci_function(ahc->dev_softc),
+			       start);
+		} else
+#endif
+			maddr = ioremap_nocache(base_page, base_offset + 256);
+		if (maddr != NULL) {
+			ahc->tag = BUS_SPACE_MEMIO;
+			ahc->bsh.maddr = maddr + base_offset;
+			command |= PCIM_CMD_MEMEN;
+			ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+					     command, 4);
+
+			/*
+			 * Do a quick test to see if memory mapped
+			 * I/O is functioning correctly.
+			 */
+			if (ahc_inb(ahc, HCNTRL) == 0xFF) {
+				printf("aic7xxx: PCI Device %d:%d:%d "
+				       "failed memory mapped test\n",
+				       ahc_get_pci_bus(ahc->dev_softc),
+				       ahc_get_pci_slot(ahc->dev_softc),
+				       ahc_get_pci_function(ahc->dev_softc));
+				iounmap((void *)base_page);
+				maddr = NULL;
+			} else {
+				command &= ~PCIM_CMD_PORTEN;
+				ahc_pci_write_config(ahc->dev_softc,
+						    PCIR_COMMAND, command, 4);
+			}
+		}
+	}
+#endif
+
+	/*
+	 * We always prefer memory mapped access.  Only
+	 * complain about our ioport conflicting with
+	 * another device if we are going to use it.
+	 */
+	if (maddr == NULL) {
+		ahc->tag = BUS_SPACE_PIO;
+		command &= ~(PCIM_CMD_MEMEN|PCIM_CMD_PORTEN);
+		ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+		base = pci_resource_start(ahc->dev_softc, 0);
+#else
+		base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
+		base &= PCI_BASE_ADDRESS_IO_MASK;
+#endif
+		if (base == 0) {
+			printf("aic7xxx: PCI%d:%d:%d No mapping available. "
+			       "Cannot map device.\n",
+			       ahc_get_pci_bus(ahc->dev_softc),
+			       ahc_get_pci_slot(ahc->dev_softc),
+			       ahc_get_pci_function(ahc->dev_softc));
+			return (ENXIO);
+		}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+		if (check_region(base, 256) != 0) {
+#else
+		if (request_region(base, 256, "aic7xxx") == 0) {
+#endif
+			printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
+			       "in use. Cannot map device.\n",
+			       ahc_get_pci_bus(ahc->dev_softc),
+			       ahc_get_pci_slot(ahc->dev_softc),
+			       ahc_get_pci_function(ahc->dev_softc),
+			       base);
+			base = 0;
+			return (EBUSY);
+		}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+		request_region(base, 256, "aic7xxx");
+#endif
+		ahc->bsh.ioport = base;
+		command |= PCIM_CMD_PORTEN;
+		ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
+	}
+	return (0);
+}
+
+int
+ahc_pci_map_int(struct ahc_softc *ahc)
+{
+	int error;
+
+	ahc->platform_data->irq = ahc->dev_softc->irq;
+	error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
+			    SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc);
+	if (error < 0)
+		error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
+				    SA_SHIRQ, "aic7xxx", ahc);
+	
+	return (-error);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,1074 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $
+ *
+ * Copyright (c) 2000, 2001 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $
+ *
+ */
+#ifndef _AIC7XXX_LINUX_H_
+#define _AIC7XXX_LINUX_H_
+
+#include <linux/types.h>
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/config.h>
+#endif
+
+/* Core SCSI definitions */
+#include "../scsi.h"
+#include "../hosts.h"
+
+/* Name space conflict with BSD queue macros */
+#ifdef LIST_HEAD
+#undef LIST_HEAD
+#endif
+
+#include "cam.h"
+#include "queue.h"
+#include "scsi_message.h"
+
+/*
+ * We never have to reference the current task, and the driver core
+ * makes ample use of this "name".
+ */
+#ifdef current
+#undef current
+#endif
+
+/************************* Forward Declarations *******************************/
+struct ahc_softc;
+typedef struct pci_dev *ahc_dev_softc_t;
+typedef Scsi_Cmnd      *ahc_io_ctx_t;
+
+/******************************* Byte Order ***********************************/
+#define ahc_htobe16(x)	cpu_to_be16(x)
+#define ahc_htobe32(x)	cpu_to_be32(x)
+#define ahc_htobe64(x)	cpu_to_be64(x)
+#define ahc_htole16(x)	cpu_to_le16(x)
+#define ahc_htole32(x)	cpu_to_le32(x)
+#define ahc_htole64(x)	cpu_to_le64(x)
+
+#define ahc_be16toh(x)	be16_to_cpu(x)
+#define ahc_be32toh(x)	be32_to_cpu(x)
+#define ahc_be64toh(x)	be64_to_cpu(x)
+#define ahc_le16toh(x)	le16_to_cpu(x)
+#define ahc_le32toh(x)	le32_to_cpu(x)
+#define ahc_le64toh(x)	le64_to_cpu(x)
+
+/************************* Configuration Data *********************************/
+extern int aic7xxx_no_probe;
+extern int aic7xxx_detect_complete;
+extern Scsi_Host_Template* aic7xxx_driver_template;
+
+/***************************** Bus Space/DMA **********************************/
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16)
+typedef dma_addr_t bus_addr_t;
+#else
+typedef uint32_t bus_addr_t;
+#endif
+typedef uint32_t bus_size_t;
+
+typedef enum {
+	BUS_SPACE_MEMIO,
+	BUS_SPACE_PIO
+} bus_space_tag_t;
+
+typedef union {
+	u_long		  ioport;
+	volatile uint8_t *maddr;
+} bus_space_handle_t;
+
+typedef struct bus_dma_segment
+{
+	bus_addr_t	ds_addr;
+	bus_size_t	ds_len;
+} bus_dma_segment_t;
+
+struct ahc_linux_dma_tag
+{
+	bus_size_t	alignment;
+	bus_size_t	boundary;
+	bus_size_t	maxsize;
+};
+typedef struct ahc_linux_dma_tag* bus_dma_tag_t;
+
+struct ahc_linux_dmamap
+{
+	bus_addr_t	bus_addr;
+};
+typedef struct ahc_linux_dmamap* bus_dmamap_t;
+
+typedef int bus_dma_filter_t(void*, bus_addr_t);
+typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
+
+#define BUS_DMA_WAITOK		0x0
+#define BUS_DMA_NOWAIT		0x1
+#define BUS_DMA_ALLOCNOW	0x2
+#define BUS_DMA_LOAD_SEGS	0x4	/*
+					 * Argument is an S/G list not
+					 * a single buffer.
+					 */
+
+#define BUS_SPACE_MAXADDR	0xFFFFFFFF
+#define BUS_SPACE_MAXSIZE_32BIT	0xFFFFFFFF
+
+int	ahc_dma_tag_create(struct ahc_softc *, bus_dma_tag_t /*parent*/,
+			   bus_size_t /*alignment*/, bus_size_t /*boundary*/,
+			   bus_addr_t /*lowaddr*/, bus_addr_t /*highaddr*/,
+			   bus_dma_filter_t*/*filter*/, void */*filterarg*/,
+			   bus_size_t /*maxsize*/, int /*nsegments*/,
+			   bus_size_t /*maxsegsz*/, int /*flags*/,
+			   bus_dma_tag_t */*dma_tagp*/);
+
+void	ahc_dma_tag_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/);
+
+int	ahc_dmamem_alloc(struct ahc_softc *, bus_dma_tag_t /*dmat*/,
+			 void** /*vaddr*/, int /*flags*/,
+			 bus_dmamap_t* /*mapp*/);
+
+void	ahc_dmamem_free(struct ahc_softc *, bus_dma_tag_t /*dmat*/,
+			void* /*vaddr*/, bus_dmamap_t /*map*/);
+
+void	ahc_dmamap_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/,
+			   bus_dmamap_t /*map*/);
+
+int	ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t /*dmat*/,
+			bus_dmamap_t /*map*/, void * /*buf*/,
+			bus_size_t /*buflen*/, bus_dmamap_callback_t *,
+			void */*callback_arg*/, int /*flags*/);
+
+int	ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t);
+
+/* XXX May do selective memory barrier operations on certain platforms */
+#define ahc_dmamap_sync(ahc, dma_tag, dmamap, op)
+
+/************************** SCSI Constants/Structures *************************/
+#define SCSI_REV_2 2
+#define	SCSI_STATUS_OK			0x00
+#define	SCSI_STATUS_CHECK_COND		0x02
+#define	SCSI_STATUS_COND_MET		0x04
+#define	SCSI_STATUS_BUSY		0x08
+#define SCSI_STATUS_INTERMED		0x10
+#define SCSI_STATUS_INTERMED_COND_MET	0x14
+#define SCSI_STATUS_RESERV_CONFLICT	0x18
+#define SCSI_STATUS_CMD_TERMINATED	0x22
+#define SCSI_STATUS_QUEUE_FULL		0x28
+
+/*
+ * 6 byte request sense CDB format.
+ */
+struct scsi_sense
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[2];
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_sense_data
+{
+	uint8_t	error_code;
+	uint8_t	segment;
+	uint8_t	flags;
+	uint8_t	info[4];
+	uint8_t	extra_len;
+	uint8_t	cmd_spec_info[4];
+	uint8_t add_sense_code;
+	uint8_t add_sense_code_qual;
+	uint8_t	fru;
+	uint8_t	sense_key_spec[3];
+	uint8_t	extra_bytes[14];
+};
+
+struct scsi_inquiry_data
+{
+	uint8_t device;
+#define	SID_TYPE(inq_data) ((inq_data)->device & 0x1f)
+#define	SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5)
+#define	SID_QUAL_LU_CONNECTED	0x00	/*
+					 * The specified peripheral device
+					 * type is currently connected to
+					 * logical unit.  If the target cannot
+					 * determine whether or not a physical
+					 * device is currently connected, it
+					 * shall also use this peripheral
+					 * qualifier when returning the INQUIRY
+					 * data.  This peripheral qualifier
+					 * does not mean that the device is
+					 * ready for access by the initiator.
+					 */
+#define	SID_QUAL_LU_OFFLINE	0x01	/*
+					 * The target is capable of supporting
+					 * the specified peripheral device type
+					 * on this logical unit; however, the
+					 * physical device is not currently
+					 * connected to this logical unit.
+					 */
+#define SID_QUAL_RSVD		0x02
+#define	SID_QUAL_BAD_LU		0x03	/*
+					 * The target is not capable of
+					 * supporting a physical device on
+					 * this logical unit. For this
+					 * peripheral qualifier the peripheral
+					 * device type shall be set to 1Fh to
+					 * provide compatibility with previous
+					 * versions of SCSI. All other
+					 * peripheral device type values are
+					 * reserved for this peripheral
+					 * qualifier.
+					 */
+#define	SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0)
+	uint8_t dev_qual2;
+#define	SID_QUAL2	0x7F
+#define	SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0)
+	uint8_t version;
+#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07)
+#define		SCSI_REV_0		0
+#define		SCSI_REV_CCS		1
+#define		SCSI_REV_2		2
+#define		SCSI_REV_SPC		3
+#define		SCSI_REV_SPC2		4
+
+#define SID_ECMA	0x38
+#define SID_ISO		0xC0
+	uint8_t response_format;
+#define SID_AENC	0x80
+#define SID_TrmIOP	0x40
+	uint8_t additional_length;
+	uint8_t reserved[2];
+	uint8_t flags;
+#define	SID_SftRe	0x01
+#define	SID_CmdQue	0x02
+#define	SID_Linked	0x08
+#define	SID_Sync	0x10
+#define	SID_WBus16	0x20
+#define	SID_WBus32	0x40
+#define	SID_RelAdr	0x80
+#define SID_VENDOR_SIZE   8
+	char	 vendor[SID_VENDOR_SIZE];
+#define SID_PRODUCT_SIZE  16
+	char	 product[SID_PRODUCT_SIZE];
+#define SID_REVISION_SIZE 4
+	char	 revision[SID_REVISION_SIZE];
+	/*
+	 * The following fields were taken from SCSI Primary Commands - 2
+	 * (SPC-2) Revision 14, Dated 11 November 1999
+	 */
+#define	SID_VENDOR_SPECIFIC_0_SIZE	20
+	u_int8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE];
+	/*
+	 * An extension of SCSI Parallel Specific Values
+	 */
+#define	SID_SPI_IUS		0x01
+#define	SID_SPI_QAS		0x02
+#define	SID_SPI_CLOCK_ST	0x00
+#define	SID_SPI_CLOCK_DT	0x04
+#define	SID_SPI_CLOCK_DT_ST	0x0C
+#define	SID_SPI_MASK		0x0F
+	uint8_t spi3data;
+	uint8_t reserved2;
+	/*
+	 * Version Descriptors, stored 2 byte values.
+	 */
+	uint8_t version1[2];
+	uint8_t version2[2];
+	uint8_t version3[2];
+	uint8_t version4[2];
+	uint8_t version5[2];
+	uint8_t version6[2];
+	uint8_t version7[2];
+	uint8_t version8[2];
+
+	uint8_t reserved3[22];
+
+#define	SID_VENDOR_SPECIFIC_1_SIZE	160
+	uint8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE];
+};
+
+/********************************** Includes **********************************/
+/* Host template and function declarations referenced by the template. */
+#include "aic7xxx_linux_host.h"
+
+/* Core driver definitions */
+#include "aic7xxx.h"
+
+/* SMP support */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
+#include <linux/smp.h>
+#endif
+
+#define AIC7XXX_DRIVER_VERSION  "6.1.5"
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+/**************************** Front End Queues ********************************/
+/*
+ * Data structure used to cast the Linux struct scsi_cmnd to something
+ * that allows us to use the queue macros.  The linux structure has
+ * plenty of space to hold the links fields as required by the queue
+ * macros, but the queue macors require them to have the correct type.
+ */
+struct ahc_cmd_internal {
+	/* Area owned by the Linux scsi layer. */
+	uint8_t	private[offsetof(struct scsi_cmnd, SCp.Status)];
+	union {
+		STAILQ_ENTRY(ahc_cmd)	ste;
+		LIST_ENTRY(ahc_cmd)	le;
+		TAILQ_ENTRY(ahc_cmd)	tqe;
+	} links;
+	uint32_t			end;
+};
+
+struct ahc_cmd {
+	union {
+		struct ahc_cmd_internal	icmd;
+		struct scsi_cmnd	scsi_cmd;
+	} un;
+};
+
+#define acmd_icmd(cmd) ((cmd)->un.icmd)
+#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd)
+#define acmd_links un.icmd.links
+
+/*************************** Device Data Structures ***************************/
+/*
+ * A per probed device structure used to deal with some error recovery
+ * scenarios that the Linux mid-layer code just doesn't know how to
+ * handle.  The structure allocated for a device only becomes persistant
+ * after a successfully completed inquiry command to the target when
+ * that inquiry data indicates a lun is present.
+ */
+TAILQ_HEAD(ahc_busyq, ahc_cmd);
+typedef enum {
+	AHC_DEV_UNCONFIGURED	 = 0x01,
+	AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
+	AHC_DEV_TIMER_ACTIVE	 = 0x04, /* Our timer is active */
+	AHC_DEV_ON_RUN_LIST	 = 0x08	 /* Queued to be run later */
+} ahc_dev_flags;
+
+struct ahc_linux_target;
+struct ahc_linux_device {
+	LIST_ENTRY(ahc_linux_device) links;
+	struct		ahc_busyq busyq;
+
+	/*
+	 * The number of transactions currently
+	 * queued to the device.
+	 */
+	int		active;
+
+	/*
+	 * The currently allowed number of 
+	 * transactions that can be queued to
+	 * the device.  Must be signed for
+	 * conversion from tagged to untagged
+	 * mode where the device may have more
+	 * than one outstanding active transaction.
+	 */
+	int		openings;
+
+	/*
+	 * A positive count indicates that this
+	 * device's queue is halted.
+	 */
+	u_int		qfrozen;
+	
+	/*
+	 * Cumulative command counter.
+	 */
+	u_int		num_commands;
+
+	/*
+	 * The number of tagged transactions when
+	 * running at our current opening level
+	 * that have been successfully received by
+	 * this device since the last QUEUE FULL.
+	 */
+	u_int		tag_success_count;
+#define AHC_TAG_SUCCESS_INTERVAL 50
+
+	ahc_dev_flags	flags;
+
+	/*
+	 * The high limit for the tags variable.
+	 */
+	u_int		maxtags;
+
+	/*
+	 * The computed number of tags outstanding
+	 * at the time of the last QUEUE FULL event.
+	 */
+	u_int		tags_on_last_queuefull;
+
+	/*
+	 * How many times we have seen a queue full
+	 * with the same number of tags.  This is used
+	 * to stop our adaptive queue depth algorithm
+	 * on devices with a fixed number of tags.
+	 */
+	u_int		last_queuefull_same_count;
+
+#define AHC_LOCK_TAGS_COUNT 50
+	int		lun;
+	struct		ahc_linux_target *target;
+};
+
+struct ahc_linux_target {
+	struct	ahc_linux_device *devices[AHC_NUM_LUNS];
+	int	channel;
+	int	target;
+	int	refcount;
+	struct	ahc_transinfo last_tinfo;
+};
+
+/********************* Definitions Required by the Core ***********************/
+/*
+ * Number of SG segments we require.  So long as the S/G segments for
+ * a particular transaction are allocated in a physically contiguous
+ * manner and are allocated below 4GB, the number of S/G segments is
+ * unrestricted.
+ */
+#define        AHC_NSEG 128
+
+/*
+ * Per-SCB OSM storage.
+ */
+struct scb_platform_data {
+	struct ahc_linux_device	*dev;
+	uint32_t		 xfer_len;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+	uint32_t		 resid;		/* Transfer residual */
+#endif
+};
+
+/*
+ * Define a structure used for each host adapter.  All members are
+ * aligned on a boundary >= the size of the member to honor the
+ * alignment restrictions of the various platforms supported by
+ * this driver.
+ */
+TAILQ_HEAD(ahc_completeq, ahc_cmd);
+struct ahc_platform_data {
+	/*
+	 * Fields accessed from interrupt context.
+	 */
+	struct ahc_linux_target *targets[AHC_NUM_TARGETS]; 
+	LIST_HEAD(, ahc_linux_device) device_runq;
+	struct ahc_completeq	 completeq;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+	spinlock_t		 spin_lock;
+#endif
+	u_int			 qfrozen;
+	struct timer_list	 reset_timer;
+	struct semaphore	 eh_sem;
+	struct Scsi_Host        *host;		/* pointer to scsi host */
+	uint32_t		 irq;		/* IRQ for this adapter */
+	uint32_t		 bios_address;
+	uint32_t		 mem_busaddr;	/* Mem Base Addr */
+};
+
+/************************** OS Utility Wrappers *******************************/
+#define printf printk
+#define M_NOWAIT GFP_ATOMIC
+#define M_WAITOK 0
+#define malloc(size, type, flags) kmalloc(size, flags)
+#define free(ptr, type) kfree(ptr)
+
+static __inline void ahc_delay(long);
+static __inline void
+ahc_delay(long usec)
+{
+	/*
+	 * udelay on Linux can have problems for
+	 * multi-millisecond waits.  Wait at most
+	 * 1024us per call.
+	 */
+	while (usec > 0) {
+		udelay(usec % 1024);
+		usec -= 1024;
+	}
+}
+
+
+/***************************** Low Level I/O **********************************/
+#if defined(__powerpc__)
+#define MMAPIO
+#ifdef mb
+#undef mb
+#endif
+#define mb() \
+	__asm__ __volatile__("eieio" ::: "memory")
+#elif defined(__i386__)
+#define MMAPIO
+#ifdef mb
+#undef mb
+#endif
+#define mb() \
+	do { ; } while(0)
+#elif defined(__alpha__)
+#ifdef mb
+#undef mb
+#endif
+#define mb() \
+	__asm__ __volatile__("mb": : :"memory")
+#elif defined(__sparc__)
+#define MMAPIO
+/* The default mb() define does what this driver wants. -DaveM */
+#endif
+
+static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port);
+static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
+static __inline void ahc_outsb(struct ahc_softc * ahc, long port,
+			       uint8_t *, int count);
+static __inline void ahc_insb(struct ahc_softc * ahc, long port,
+			       uint8_t *, int count);
+
+static __inline uint8_t
+ahc_inb(struct ahc_softc * ahc, long port)
+{
+#ifdef MMAPIO
+	uint8_t x;
+
+	if (ahc->tag == BUS_SPACE_MEMIO) {
+		x = readb(ahc->bsh.maddr + port);
+	} else {
+		x = inb(ahc->bsh.ioport + port);
+	}
+	mb();
+	return (x);
+#else
+	return (inb(ahc->bsh.ioport + port));
+#endif
+}
+
+static __inline void
+ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
+{
+#ifdef MMAPIO
+	if (ahc->tag == BUS_SPACE_MEMIO) {
+		writeb(val, ahc->bsh.maddr + port);
+	} else {
+		outb(val, ahc->bsh.ioport + port);
+	}
+	mb();
+#else
+	outb(val, ahc->bsh.ioport + port);
+#endif
+}
+
+static __inline void
+ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+	int i;
+
+	/*
+	 * There is probably a more efficient way to do this on Linux
+	 * but we don't use this for anything speed critical and this
+	 * should work.
+	 */
+	for (i = 0; i < count; i++)
+		ahc_outb(ahc, port, *array++);
+}
+
+static __inline void
+ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+	int i;
+
+	/*
+	 * There is probably a more efficient way to do this on Linux
+	 * but we don't use this for anything speed critical and this
+	 * should work.
+	 */
+	for (i = 0; i < count; i++)
+		*array++ = ahc_inb(ahc, port);
+}
+
+/**************************** Initialization **********************************/
+int	aic7xxx_register_host(struct ahc_softc *ahc,
+			      Scsi_Host_Template *template);
+
+/*************************** Pretty Printing **********************************/
+struct info_str {
+	char *buffer;
+	int length;
+	off_t offset;
+	int pos;
+};
+
+void	ahc_format_transinfo(struct info_str *info,
+			     struct ahc_transinfo *tinfo);
+
+/******************************** Locking *************************************/
+/* Lock protecting internal data structures */
+static __inline void ahc_lockinit(struct ahc_softc *);
+static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags);
+static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags);
+
+/* Lock held during command compeletion to the upper layer */
+static __inline void ahc_done_lockinit(struct ahc_softc *);
+static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags);
+static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
+static __inline void
+ahc_lockinit(struct ahc_softc *ahc)
+{
+	spin_lock_init(&ahc->platform_data->spin_lock);
+}
+
+static __inline void
+ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	*flags = 0;
+	spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags);
+}
+
+static __inline void
+ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags);
+}
+
+static __inline void
+ahc_done_lockinit(struct ahc_softc *ahc)
+{
+	/* We don't own the iorequest lock, so we don't initialize it. */
+}
+
+static __inline void
+ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	*flags = 0;
+	spin_lock_irqsave(&io_request_lock, *flags);
+}
+
+static __inline void
+ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&io_request_lock, *flags);
+}
+
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
+
+ahc_lockinit(struct ahc_softc *ahc)
+{
+}
+
+static __inline void
+ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	*flags = 0;
+	save_flags(*flags);
+	cli();
+}
+
+static __inline void
+ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	restore_flags(*flags);
+}
+
+ahc_done_lockinit(struct ahc_softc *ahc)
+{
+}
+
+static __inline void
+ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	/*
+	 * The done lock is always held while
+	 * the ahc lock is held so blocking
+	 * interrupts again would have no effect.
+	 */
+}
+
+static __inline void
+ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
+
+/******************************* PCI Definitions ******************************/
+/*
+ * PCIM_xxx: mask to locate subfield in register
+ * PCIR_xxx: config register offset
+ * PCIC_xxx: device class
+ * PCIS_xxx: device subclass
+ * PCIP_xxx: device programming interface
+ * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices)
+ * PCID_xxx: device ID
+ */
+#define PCIR_DEVVENDOR		0x00
+#define PCIR_VENDOR		0x00
+#define PCIR_DEVICE		0x02
+#define PCIR_COMMAND		0x04
+#define PCIM_CMD_PORTEN		0x0001
+#define PCIM_CMD_MEMEN		0x0002
+#define PCIM_CMD_BUSMASTEREN	0x0004
+#define PCIM_CMD_MWRICEN	0x0010
+#define PCIM_CMD_PERRESPEN	0x0040
+#define PCIR_STATUS		0x06
+#define PCIR_REVID		0x08
+#define PCIR_PROGIF		0x09
+#define PCIR_SUBCLASS		0x0a
+#define PCIR_CLASS		0x0b
+#define PCIR_CACHELNSZ		0x0c
+#define PCIR_LATTIMER		0x0d
+#define PCIR_HEADERTYPE		0x0e
+#define PCIM_MFDEV		0x80
+#define PCIR_BIST		0x0f
+#define PCIR_CAP_PTR		0x34
+
+/* config registers for header type 0 devices */
+#define PCIR_MAPS	0x10
+#define PCIR_SUBVEND_0	0x2c
+#define PCIR_SUBDEV_0	0x2e
+
+/**************************** VL/EISA Routines ********************************/
+int			 aic7770_linux_probe(Scsi_Host_Template *);
+int			 aic7770_map_registers(struct ahc_softc *ahc);
+int			 aic7770_map_int(struct ahc_softc *ahc,
+					 u_int irq, int shared);
+
+/******************************* PCI Routines *********************************/
+/*
+ * We need to use the bios32.h routines if we are kernel version 2.1.92 or less.
+ */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92)
+#if defined(__sparc_v9__) || defined(__powerpc__)
+#error "PPC and Sparc platforms are only support under 2.1.92 and above"
+#endif
+#include <linux/bios32.h>
+#endif
+
+int			 ahc_linux_pci_probe(Scsi_Host_Template *);
+int			 ahc_pci_map_registers(struct ahc_softc *ahc);
+int			 ahc_pci_map_int(struct ahc_softc *ahc);
+
+static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
+					     int reg, int width);
+
+static __inline uint32_t
+ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
+{
+	switch (width) {
+	case 1:
+	{
+		uint8_t retval;
+
+		pci_read_config_byte(pci, reg, &retval);
+		return (retval);
+	}
+	case 2:
+	{
+		uint16_t retval;
+		pci_read_config_word(pci, reg, &retval);
+		return (retval);
+	}
+	case 4:
+	{
+		uint32_t retval;
+		pci_read_config_dword(pci, reg, &retval);
+		return (retval);
+	}
+	default:
+		panic("ahc_pci_read_config: Read size too big");
+		/* NOTREACHED */
+	}
+}
+
+static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
+					  int reg, uint32_t value,
+					  int width);
+
+static __inline void
+ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
+{
+	switch (width) {
+	case 1:
+		pci_write_config_byte(pci, reg, value);
+		break;
+	case 2:
+		pci_write_config_word(pci, reg, value);
+		break;
+	case 4:
+		pci_write_config_dword(pci, reg, value);
+		break;
+	default:
+		panic("ahc_pci_write_config: Write size too big");
+		/* NOTREACHED */
+	}
+}
+
+static __inline int ahc_get_pci_function(ahc_dev_softc_t);
+static __inline int
+ahc_get_pci_function(ahc_dev_softc_t pci)
+{
+	return (PCI_FUNC(pci->devfn));
+}
+
+static __inline int ahc_get_pci_slot(ahc_dev_softc_t);
+static __inline int
+ahc_get_pci_slot(ahc_dev_softc_t pci)
+{
+	return (PCI_SLOT(pci->devfn));
+}
+
+static __inline int ahc_get_pci_bus(ahc_dev_softc_t);
+static __inline int
+ahc_get_pci_bus(ahc_dev_softc_t pci)
+{
+	return (pci->bus->number);
+}
+
+static __inline void ahc_flush_device_writes(struct ahc_softc *);
+static __inline void
+ahc_flush_device_writes(struct ahc_softc *ahc)
+{
+	/* XXX Is this sufficient for all architectures??? */
+	ahc_inb(ahc, INTSTAT);
+}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0)
+#define pci_map_sg(pdev, sg_list, nseg, direction) (nseg)
+#define pci_unmap_sg(pdev, sg_list, nseg, direction)
+#define sg_dma_address(sg) (VIRT_TO_BUS((sg)->address))
+#define sg_dma_len(sg) ((sg)->length)
+#define pci_map_single(pdev, buffer, bufflen, direction) \
+	(VIRT_TO_BUS(buffer))
+#define pci_unmap_single(pdev, buffer, buflen, direction)
+#endif
+
+/*********************** Transaction Access Wrappers **************************/
+static __inline void ahc_set_transaction_status(struct scb *, uint32_t);
+static __inline
+void ahc_set_transaction_status(struct scb *scb, uint32_t status)
+{
+	scb->io_ctx->result &= ~(CAM_STATUS_MASK << 16);
+	scb->io_ctx->result |= status << 16;
+}
+
+static __inline void ahc_set_scsi_status(struct scb *, uint32_t);
+static __inline
+void ahc_set_scsi_status(struct scb *scb, uint32_t status)
+{
+	scb->io_ctx->result &= ~0xFFFF;
+	scb->io_ctx->result |= status;
+}
+
+static __inline uint32_t ahc_get_transaction_status(struct scb *);
+static __inline
+uint32_t ahc_get_transaction_status(struct scb *scb)
+{
+	return ((scb->io_ctx->result >> 16) & CAM_STATUS_MASK);
+}
+
+static __inline uint32_t ahc_get_scsi_status(struct scb *);
+static __inline
+uint32_t ahc_get_scsi_status(struct scb *scb)
+{
+	return (scb->io_ctx->result & 0xFFFF);
+}
+
+static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
+static __inline
+void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type)
+{
+	/*
+	 * Nothing to do for linux as the incoming transaction
+	 * has no concept of tag/non tagged, etc.
+	 */
+}
+
+static __inline u_long ahc_get_transfer_length(struct scb *);
+static __inline
+u_long ahc_get_transfer_length(struct scb *scb)
+{
+	return (scb->platform_data->xfer_len);
+}
+
+static __inline int ahc_get_transfer_dir(struct scb *);
+static __inline
+int ahc_get_transfer_dir(struct scb *scb)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,40)
+	return (scb->io_ctx->sc_data_direction);
+#else
+	if (scb->io_ctx->bufflen == 0)
+		return (CAM_DIR_NONE);
+
+	switch(scb->io_ctx->cmnd[0]) {
+	case 0x08:  /* READ(6)  */
+	case 0x28:  /* READ(10) */
+	case 0xA8:  /* READ(12) */
+		return (CAM_DIR_IN);
+        case 0x0A:  /* WRITE(6)  */
+        case 0x2A:  /* WRITE(10) */
+        case 0xAA:  /* WRITE(12) */
+		return (CAM_DIR_OUT);
+        default:
+		return (CAM_DIR_NONE);
+        }
+#endif
+}
+
+static __inline void ahc_set_residual(struct scb *, u_long);
+static __inline
+void ahc_set_residual(struct scb *scb, u_long resid)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	scb->io_ctx->resid = resid;
+#else
+	scb->platform_data->resid = resid;
+#endif
+}
+
+static __inline void ahc_set_sense_residual(struct scb *, u_long);
+static __inline
+void ahc_set_sense_residual(struct scb *scb, u_long resid)
+{
+	/* This can't be reported in Linux */
+}
+
+static __inline u_long ahc_get_residual(struct scb *);
+static __inline
+u_long ahc_get_residual(struct scb *scb)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	return (scb->io_ctx->resid);
+#else
+	return (scb->platform_data->resid);
+#endif
+}
+
+static __inline int ahc_perform_autosense(struct scb *);
+static __inline
+int ahc_perform_autosense(struct scb *scb)
+{
+	/*
+	 * We always perform autosense in Linux.
+	 * On other platforms this is set on a
+	 * per-transaction basis.
+	 */
+	return (1);
+}
+
+static __inline uint32_t
+ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb)
+{
+	return (sizeof(struct scsi_sense_data));
+}
+
+static __inline void ahc_notify_xfer_settings_change(struct ahc_softc *,
+						     struct ahc_devinfo *);
+static __inline void
+ahc_notify_xfer_settings_change(struct ahc_softc *ahc,
+				struct ahc_devinfo *devinfo)
+{
+	/* Nothing to do here for linux */
+}
+
+static __inline void ahc_platform_scb_free(struct ahc_softc *ahc,
+					   struct scb *scb);
+static __inline void
+ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb)
+{
+	ahc->flags &= ~AHC_RESOURCE_SHORTAGE;
+}
+
+int	ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
+void	ahc_platform_free(struct ahc_softc *ahc);
+void	ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
+static __inline void	ahc_freeze_scb(struct scb *scb);
+static __inline void
+ahc_freeze_scb(struct scb *scb)
+{
+	/* Noting to do here for linux */
+}
+
+void	ahc_platform_set_tags(struct ahc_softc *ahc,
+			      struct ahc_devinfo *devinfo, int enable);
+int	ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
+				char channel, int lun, u_int tag,
+				role_t role, uint32_t status);
+void	aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs);
+void	ahc_platform_flushwork(struct ahc_softc *ahc);
+int	ahc_softc_comp(struct ahc_softc *, struct ahc_softc *);
+void	ahc_done(struct ahc_softc*, struct scb*);
+void	ahc_send_async(struct ahc_softc *, char channel,
+		       u_int target, u_int lun, ac_code);
+void	ahc_print_path(struct ahc_softc *, struct scb *);
+void	ahc_platform_dump_card_state(struct ahc_softc *ahc);
+
+#ifdef CONFIG_PCI
+#define AHC_PCI_CONFIG 1
+#else
+#define AHC_PCI_CONFIG 0
+#endif
+#define bootverbose aic7xxx_verbose
+extern int aic7xxx_verbose;
+#endif /* _AIC7XXX_LINUX_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_pci.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,2137 @@
+/*
+ * Product specific probe and attach routines for:
+ *      3940, 2940, aic7895, aic7890, aic7880,
+ *	aic7870, aic7860 and aic7850 SCSI controllers
+ *
+ * Copyright (c) 1995-2000 Justin T. Gibbs
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $
+ */
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+
+#define AHC_PCI_IOADDR	PCIR_MAPS	/* I/O Address */
+#define AHC_PCI_MEMADDR	(PCIR_MAPS + 4)	/* Mem I/O Address */
+
+static __inline uint64_t
+ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
+{
+	uint64_t id;
+
+	id = subvendor
+	   | (subdevice << 16)
+	   | ((uint64_t)vendor << 32)
+	   | ((uint64_t)device << 48);
+
+	return (id);
+}
+
+#define ID_ALL_MASK			0xFFFFFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK		0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK		0xFFF0FFFF00000000ull
+#define ID_9005_SISL_MASK		0x000FFFFF00000000ull
+#define ID_9005_SISL_ID			0x0005900500000000ull
+#define ID_AIC7850			0x5078900400000000ull
+#define ID_AHA_2902_04_10_15_20_30C	0x5078900478509004ull
+#define ID_AIC7855			0x5578900400000000ull
+#define ID_AIC7859			0x3860900400000000ull
+#define ID_AHA_2930CU			0x3860900438699004ull
+#define ID_AIC7860			0x6078900400000000ull
+#define ID_AIC7860C			0x6078900478609004ull
+#define ID_AHA_1480A			0x6075900400000000ull
+#define ID_AHA_2940AU_0			0x6178900400000000ull
+#define ID_AHA_2940AU_1			0x6178900478619004ull
+#define ID_AHA_2940AU_CN		0x2178900478219004ull
+#define ID_AHA_2930C_VAR		0x6038900438689004ull
+
+#define ID_AIC7870			0x7078900400000000ull
+#define ID_AHA_2940			0x7178900400000000ull
+#define ID_AHA_3940			0x7278900400000000ull
+#define ID_AHA_398X			0x7378900400000000ull
+#define ID_AHA_2944			0x7478900400000000ull
+#define ID_AHA_3944			0x7578900400000000ull
+#define ID_AHA_4944			0x7678900400000000ull
+
+#define ID_AIC7880			0x8078900400000000ull
+#define ID_AIC7880_B			0x8078900478809004ull
+#define ID_AHA_2940U			0x8178900400000000ull
+#define ID_AHA_3940U			0x8278900400000000ull
+#define ID_AHA_2944U			0x8478900400000000ull
+#define ID_AHA_3944U			0x8578900400000000ull
+#define ID_AHA_398XU			0x8378900400000000ull
+#define ID_AHA_4944U			0x8678900400000000ull
+#define ID_AHA_2940UB			0x8178900478819004ull
+#define ID_AHA_2930U			0x8878900478889004ull
+#define ID_AHA_2940U_PRO		0x8778900478879004ull
+#define ID_AHA_2940U_CN			0x0078900478009004ull
+
+#define ID_AIC7895			0x7895900478959004ull
+#define ID_AIC7895_ARO			0x7890900478939004ull
+#define ID_AIC7895_ARO_MASK		0xFFF0FFFFFFFFFFFFull
+#define ID_AHA_2940U_DUAL		0x7895900478919004ull
+#define ID_AHA_3940AU			0x7895900478929004ull
+#define ID_AHA_3944AU			0x7895900478949004ull
+
+#define ID_AIC7890			0x001F9005000F9005ull
+#define ID_AIC7890_ARO			0x00139005000F9005ull
+#define ID_AAA_131U2			0x0013900500039005ull
+#define ID_AHA_2930U2			0x0011900501819005ull
+#define ID_AHA_2940U2B			0x00109005A1009005ull
+#define ID_AHA_2940U2_OEM		0x0010900521809005ull
+#define ID_AHA_2940U2			0x00109005A1809005ull
+#define ID_AHA_2950U2B			0x00109005E1009005ull
+
+#define ID_AIC7892			0x008F9005FFFF9005ull
+#define ID_AIC7892_ARO			0x00839005FFFF9005ull
+#define ID_AHA_29160			0x00809005E2A09005ull
+#define ID_AHA_29160_CPQ		0x00809005E2A00E11ull
+#define ID_AHA_29160N			0x0080900562A09005ull
+#define ID_AHA_29160C			0x0080900562209005ull
+#define ID_AHA_29160B			0x00809005E2209005ull
+#define ID_AHA_19160B			0x0081900562A19005ull
+
+#define ID_AIC7896			0x005F9005FFFF9005ull
+#define ID_AIC7896_ARO			0x00539005FFFF9005ull
+#define ID_AHA_3950U2B_0		0x00509005FFFF9005ull
+#define ID_AHA_3950U2B_1		0x00509005F5009005ull
+#define ID_AHA_3950U2D_0		0x00519005FFFF9005ull
+#define ID_AHA_3950U2D_1		0x00519005B5009005ull
+
+#define ID_AIC7899			0x00CF9005FFFF9005ull
+#define ID_AIC7899_ARO			0x00C39005FFFF9005ull
+#define ID_AHA_3960D			0x00C09005F6209005ull
+#define ID_AHA_3960D_CPQ		0x00C09005F6200E11ull
+
+#define ID_AIC7810			0x1078900400000000ull
+#define ID_AIC7815			0x7815900400000000ull
+
+#define DEVID_9005_TYPE(id) ((id) & 0xF)
+#define		DEVID_9005_TYPE_HBA		0x0	/* Standard Card */
+#define		DEVID_9005_TYPE_AAA		0x3	/* RAID Card */
+#define		DEVID_9005_TYPE_SISL		0x5	/* Low Cost Card */
+#define		DEVID_9005_TYPE_MB		0xF	/* On Motherboard */
+
+#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
+#define		DEVID_9005_MAXRATE_U160		0x0
+#define		DEVID_9005_MAXRATE_ULTRA2	0x1
+#define		DEVID_9005_MAXRATE_ULTRA	0x2
+#define		DEVID_9005_MAXRATE_FAST		0x3
+
+#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6)
+
+#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8)
+#define		DEVID_9005_CLASS_SPI		0x0	/* Parallel SCSI */
+
+#define SUBID_9005_TYPE(id) ((id) & 0xF)
+#define		SUBID_9005_TYPE_MB		0xF	/* On Motherboard */
+#define		SUBID_9005_TYPE_CARD		0x0	/* Standard Card */
+#define		SUBID_9005_TYPE_LCCARD		0x1	/* Low Cost Card */
+#define		SUBID_9005_TYPE_RAID		0x3	/* Combined with Raid */
+
+#define SUBID_9005_TYPE_KNOWN(id)			\
+	  ((((id) & 0xF) == SUBID_9005_TYPE_MB)		\
+	|| (((id) & 0xF) == SUBID_9005_TYPE_CARD)	\
+	|| (((id) & 0xF) == SUBID_9005_TYPE_LCCARD)	\
+	|| (((id) & 0xF) == SUBID_9005_TYPE_RAID))
+
+#define SUBID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
+#define		SUBID_9005_MAXRATE_ULTRA2	0x0
+#define		SUBID_9005_MAXRATE_ULTRA	0x1
+#define		SUBID_9005_MAXRATE_U160		0x2
+#define		SUBID_9005_MAXRATE_RESERVED	0x3
+
+#define SUBID_9005_SEEPTYPE(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? ((id) & 0xC0) >> 6						\
+	 : ((id) & 0x300) >> 8)
+#define		SUBID_9005_SEEPTYPE_NONE	0x0
+#define		SUBID_9005_SEEPTYPE_1K		0x1
+#define		SUBID_9005_SEEPTYPE_2K_4K	0x2
+#define		SUBID_9005_SEEPTYPE_RESERVED	0x3
+#define SUBID_9005_AUTOTERM(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? (((id) & 0x400) >> 10) == 0					\
+	 : (((id) & 0x40) >> 6) == 0)
+
+#define SUBID_9005_NUMCHAN(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? ((id) & 0x300) >> 8						\
+	 : ((id) & 0xC00) >> 10)
+
+#define SUBID_9005_LEGACYCONN(id)					\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? 0								\
+	 : ((id) & 0x80) >> 7)
+
+#define SUBID_9005_MFUNCENB(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? ((id) & 0x800) >> 11						\
+	 : ((id) & 0x1000) >> 12)
+/*
+ * Informational only. Should use chip register to be
+ * ceratian, but may be use in identification strings.
+ */
+#define SUBID_9005_CARD_SCSIWIDTH_MASK	0x2000
+#define SUBID_9005_CARD_PCIWIDTH_MASK	0x4000
+#define SUBID_9005_CARD_SEDIFF_MASK	0x8000
+
+static ahc_device_setup_t ahc_aic785X_setup;
+static ahc_device_setup_t ahc_aic7860_setup;
+static ahc_device_setup_t ahc_apa1480_setup;
+static ahc_device_setup_t ahc_aic7870_setup;
+static ahc_device_setup_t ahc_aha394X_setup;
+static ahc_device_setup_t ahc_aha494X_setup;
+static ahc_device_setup_t ahc_aha398X_setup;
+static ahc_device_setup_t ahc_aic7880_setup;
+static ahc_device_setup_t ahc_aha2940Pro_setup;
+static ahc_device_setup_t ahc_aha394XU_setup;
+static ahc_device_setup_t ahc_aha398XU_setup;
+static ahc_device_setup_t ahc_aic7890_setup;
+static ahc_device_setup_t ahc_aic7892_setup;
+static ahc_device_setup_t ahc_aic7895_setup;
+static ahc_device_setup_t ahc_aic7896_setup;
+static ahc_device_setup_t ahc_aic7899_setup;
+static ahc_device_setup_t ahc_aha29160C_setup;
+static ahc_device_setup_t ahc_raid_setup;
+static ahc_device_setup_t ahc_aha394XX_setup;
+static ahc_device_setup_t ahc_aha494XX_setup;
+static ahc_device_setup_t ahc_aha398XX_setup;
+
+struct ahc_pci_identity ahc_pci_ident_table [] =
+{
+	/* aic7850 based controllers */
+	{
+		ID_AHA_2902_04_10_15_20_30C,
+		ID_ALL_MASK,
+		"Adaptec 2902/04/10/15/20/30C SCSI adapter",
+		ahc_aic785X_setup
+	},
+	/* aic7860 based controllers */
+	{
+		ID_AHA_2930CU,
+		ID_ALL_MASK,
+		"Adaptec 2930CU SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AHA_1480A & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 1480A Ultra SCSI adapter",
+		ahc_apa1480_setup
+	},
+	{
+		ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940A Ultra SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940A/CN Ultra SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2930C SCSI adapter (VAR)",
+		ahc_aic7860_setup
+	},
+	/* aic7870 based controllers */
+	{
+		ID_AHA_2940,
+		ID_ALL_MASK,
+		"Adaptec 2940 SCSI adapter",
+		ahc_aic7870_setup
+	},
+	{
+		ID_AHA_3940,
+		ID_ALL_MASK,
+		"Adaptec 3940 SCSI adapter",
+		ahc_aha394X_setup
+	},
+	{
+		ID_AHA_398X,
+		ID_ALL_MASK,
+		"Adaptec 398X SCSI RAID adapter",
+		ahc_aha398X_setup
+	},
+	{
+		ID_AHA_2944,
+		ID_ALL_MASK,
+		"Adaptec 2944 SCSI adapter",
+		ahc_aic7870_setup
+	},
+	{
+		ID_AHA_3944,
+		ID_ALL_MASK,
+		"Adaptec 3944 SCSI adapter",
+		ahc_aha394X_setup
+	},
+	{
+		ID_AHA_4944,
+		ID_ALL_MASK,
+		"Adaptec 4944 SCSI adapter",
+		ahc_aha494X_setup
+	},
+	/* aic7880 based controllers */
+	{
+		ID_AHA_2940U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_3940U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 3940 Ultra SCSI adapter",
+		ahc_aha394XU_setup
+	},
+	{
+		ID_AHA_2944U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2944 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_3944U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 3944 Ultra SCSI adapter",
+		ahc_aha394XU_setup
+	},
+	{
+		ID_AHA_398XU & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 398X Ultra SCSI RAID adapter",
+		ahc_aha398XU_setup
+	},
+	{
+		/*
+		 * XXX Don't know the slot numbers
+		 * so we can't identify channels
+		 */
+		ID_AHA_4944U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 4944 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_2930U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2930 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940 Pro Ultra SCSI adapter",
+		ahc_aha2940Pro_setup
+	},
+	{
+		ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940/CN Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	/* Ignore all SISL (AAC on MB) based controllers. */
+	{
+		ID_9005_SISL_ID,
+		ID_9005_SISL_MASK,
+		NULL,
+		NULL
+	},
+	/* aic7890 based controllers */
+	{
+		ID_AHA_2930U2,
+		ID_ALL_MASK,
+		"Adaptec 2930 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2940U2B,
+		ID_ALL_MASK,
+		"Adaptec 2940B Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2940U2_OEM,
+		ID_ALL_MASK,
+		"Adaptec 2940 Ultra2 SCSI adapter (OEM)",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2940U2,
+		ID_ALL_MASK,
+		"Adaptec 2940 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2950U2B,
+		ID_ALL_MASK,
+		"Adaptec 2950 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AIC7890_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7890/91 Ultra2 SCSI adapter (ARO)",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AAA_131U2,
+		ID_ALL_MASK,
+		"Adaptec AAA-131 Ultra2 RAID adapter",
+		ahc_aic7890_setup
+	},
+	/* aic7892 based controllers */
+	{
+		ID_AHA_29160,
+		ID_ALL_MASK,
+		"Adaptec 29160 Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_29160_CPQ,
+		ID_ALL_MASK,
+		"Adaptec (Compaq OEM) 29160 Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_29160N,
+		ID_ALL_MASK,
+		"Adaptec 29160N Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_29160C,
+		ID_ALL_MASK,
+		"Adaptec 29160C Ultra160 SCSI adapter",
+		ahc_aha29160C_setup
+	},
+	{
+		ID_AHA_29160B,
+		ID_ALL_MASK,
+		"Adaptec 29160B Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_19160B,
+		ID_ALL_MASK,
+		"Adaptec 19160B Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AIC7892_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7892 Ultra2 SCSI adapter (ARO)",
+		ahc_aic7892_setup
+	},
+	/* aic7895 based controllers */	
+	{
+		ID_AHA_2940U_DUAL,
+		ID_ALL_MASK,
+		"Adaptec 2940/DUAL Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AHA_3940AU,
+		ID_ALL_MASK,
+		"Adaptec 3940A Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AHA_3944AU,
+		ID_ALL_MASK,
+		"Adaptec 3944A Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AIC7895_ARO,
+		ID_AIC7895_ARO_MASK,
+		"Adaptec aic7895 Ultra SCSI adapter (ARO)",
+		ahc_aic7895_setup
+	},
+	/* aic7896/97 based controllers */	
+	{
+		ID_AHA_3950U2B_0,
+		ID_ALL_MASK,
+		"Adaptec 3950B Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AHA_3950U2B_1,
+		ID_ALL_MASK,
+		"Adaptec 3950B Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AHA_3950U2D_0,
+		ID_ALL_MASK,
+		"Adaptec 3950D Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AHA_3950U2D_1,
+		ID_ALL_MASK,
+		"Adaptec 3950D Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AIC7896_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7896/97 Ultra2 SCSI adapter (ARO)",
+		ahc_aic7896_setup
+	},
+	/* aic7899 based controllers */	
+	{
+		ID_AHA_3960D,
+		ID_ALL_MASK,
+		"Adaptec 3960D Ultra160 SCSI adapter",
+		ahc_aic7899_setup
+	},
+	{
+		ID_AHA_3960D_CPQ,
+		ID_ALL_MASK,
+		"Adaptec (Compaq OEM) 3960D Ultra160 SCSI adapter",
+		ahc_aic7899_setup
+	},
+	{
+		ID_AIC7899_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7899 Ultra160 SCSI adapter (ARO)",
+		ahc_aic7899_setup
+	},
+	/* Generic chip probes for devices we don't know 'exactly' */
+	{
+		ID_AIC7850 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7850 SCSI adapter",
+		ahc_aic785X_setup
+	},
+	{
+		ID_AIC7855 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7855 SCSI adapter",
+		ahc_aic785X_setup
+	},
+	{
+		ID_AIC7859 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7859 Ultra SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AIC7860 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7860 SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AIC7870 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7870 SCSI adapter",
+		ahc_aic7870_setup
+	},
+	{
+		ID_AIC7880 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7880 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AIC7890 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7890/91 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AIC7892 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7892 Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AIC7895 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7895 Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AIC7896 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7896/97 Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AIC7899 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7899 Ultra160 SCSI adapter",
+		ahc_aic7899_setup
+	},
+	{
+		ID_AIC7810 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7810 RAID memory controller",
+		ahc_raid_setup
+	},
+	{
+		ID_AIC7815 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7815 RAID memory controller",
+		ahc_raid_setup
+	}
+};
+
+const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
+		
+#define AHC_394X_SLOT_CHANNEL_A	4
+#define AHC_394X_SLOT_CHANNEL_B	5
+
+#define AHC_398X_SLOT_CHANNEL_A	4
+#define AHC_398X_SLOT_CHANNEL_B	8
+#define AHC_398X_SLOT_CHANNEL_C	12
+
+#define AHC_494X_SLOT_CHANNEL_A	4
+#define AHC_494X_SLOT_CHANNEL_B	5
+#define AHC_494X_SLOT_CHANNEL_C	6
+#define AHC_494X_SLOT_CHANNEL_D	7
+
+#define	DEVCONFIG		0x40
+#define		SCBSIZE32	0x00010000ul	/* aic789X only */
+#define		REXTVALID	0x00001000ul	/* ultra cards only */
+#define		MPORTMODE	0x00000400ul	/* aic7870 only */
+#define		RAMPSM		0x00000200ul	/* aic7870 only */
+#define		VOLSENSE	0x00000100ul
+#define		SCBRAMSEL	0x00000080ul
+#define		MRDCEN		0x00000040ul
+#define		EXTSCBTIME	0x00000020ul	/* aic7870 only */
+#define		EXTSCBPEN	0x00000010ul	/* aic7870 only */
+#define		BERREN		0x00000008ul
+#define		DACEN		0x00000004ul
+#define		STPWLEVEL	0x00000002ul
+#define		DIFACTNEGEN	0x00000001ul	/* aic7870 only */
+
+#define	CSIZE_LATTIME		0x0c
+#define		CACHESIZE	0x0000003ful	/* only 5 bits */
+#define		LATTIME		0x0000ff00ul
+
+typedef enum
+{
+	AHC_POWER_STATE_D0,
+	AHC_POWER_STATE_D1,
+	AHC_POWER_STATE_D2,
+	AHC_POWER_STATE_D3
+} ahc_power_state;
+
+static void ahc_power_state_change(struct ahc_softc *ahc,
+				   ahc_power_state new_state);
+static int ahc_ext_scbram_present(struct ahc_softc *ahc);
+static void ahc_scbram_config(struct ahc_softc *ahc, int enable,
+				  int pcheck, int fast, int large);
+static void ahc_probe_ext_scbram(struct ahc_softc *ahc);
+static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1);
+static void configure_termination(struct ahc_softc *ahc,
+				  struct seeprom_descriptor *sd,
+				  u_int adapter_control,
+	 			  u_int *sxfrctl1);
+
+static void ahc_new_term_detect(struct ahc_softc *ahc,
+				int *enableSEC_low,
+				int *enableSEC_high,
+				int *enablePRI_low,
+				int *enablePRI_high,
+				int *eeprom_present);
+static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+				 int *internal68_present,
+				 int *externalcable_present,
+				 int *eeprom_present);
+static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+				 int *externalcable_present,
+				 int *eeprom_present);
+static int acquire_seeprom(struct ahc_softc *ahc,
+			   struct seeprom_descriptor *sd);
+static void release_seeprom(struct seeprom_descriptor *sd);
+static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
+static uint8_t read_brdctl(struct ahc_softc *ahc);
+
+struct ahc_pci_identity *
+ahc_find_pci_device(ahc_dev_softc_t pci)
+{
+	uint64_t  full_id;
+	uint16_t  device;
+	uint16_t  vendor;
+	uint16_t  subdevice;
+	uint16_t  subvendor;
+	struct	  ahc_pci_identity *entry;
+	u_int	  i;
+
+	vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
+	device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
+	subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
+	subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
+	full_id = ahc_compose_id(device,
+				 vendor,
+				 subdevice,
+				 subvendor);
+
+	/* If the second function is not hooked up, ignore it. */
+	if (ahc_get_pci_function(pci) > 0
+	 && subvendor == 0x9005
+	 && SUBID_9005_TYPE_KNOWN(subdevice) != 0
+	 && SUBID_9005_MFUNCENB(subdevice) == 0)
+		return (NULL);
+
+	for (i = 0; i < ahc_num_pci_devs; i++) {
+		entry = &ahc_pci_ident_table[i];
+		if (entry->full_id == (full_id & entry->id_mask)) {
+			/* Honor exclusion entries. */
+			if (entry->name == NULL)
+				return (NULL);
+			return (entry);
+		}
+	}
+	return (NULL);
+}
+
+int
+ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
+{
+	struct		 ahc_probe_config probe_config;
+	struct scb_data *shared_scb_data;
+	u_int		 command;
+	u_int		 our_id = 0;
+	u_int		 sxfrctl1;
+	u_int		 scsiseq;
+	u_int		 dscommand0;
+	int		 error;
+	uint8_t		 sblkctl;
+
+	shared_scb_data = NULL;
+	ahc_init_probe_config(&probe_config);
+	error = entry->setup(ahc->dev_softc, &probe_config);
+	if (error != 0)
+		return (error);
+	probe_config.chip |= AHC_PCI;
+	probe_config.description = entry->name;
+
+	error = ahc_pci_map_registers(ahc);
+	if (error != 0)
+		return (error);
+
+	ahc_power_state_change(ahc, AHC_POWER_STATE_D0);
+
+	/* Ensure busmastering is enabled */
+	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+	command |= PCIM_CMD_BUSMASTEREN;
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
+
+	/* On all PCI adapters, we allow SCB paging */
+	probe_config.flags |= AHC_PAGESCBS;
+
+	error = ahc_softc_init(ahc, &probe_config);
+	if (error != 0)
+		return (error);
+
+	/* Remeber how the card was setup in case there is no SEEPROM */
+	if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
+		pause_sequencer(ahc);
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
+		else
+			our_id = ahc_inb(ahc, SCSIID) & OID;
+		sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
+		scsiseq = ahc_inb(ahc, SCSISEQ);
+	} else {
+		sxfrctl1 = STPWEN;
+		our_id = 7;
+		scsiseq = 0;
+	}
+
+	error = ahc_reset(ahc);
+	if (error != 0)
+		return (ENXIO);
+
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		/* Perform ALT-Mode Setup */
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS);
+		ahc_outb(ahc, SFUNCT, sfunct);
+
+		/* Normal mode setup */
+		ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN
+					  |TARGCRCENDEN);
+	}
+
+	error = ahc_pci_map_int(ahc);
+	if (error != 0)
+		return (error);
+	dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+	dscommand0 |= MPARCKEN|CACHETHEN;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+
+		/*
+		 * DPARCKEN doesn't work correctly on
+		 * some MBs so don't use it.
+		 */
+		dscommand0 &= ~DPARCKEN;
+	}
+
+	/*
+	 * Handle chips that must have cache line
+	 * streaming (dis/en)abled.
+	 */
+	if ((ahc->bugs & AHC_CACHETHEN_DIS_BUG) != 0)
+		dscommand0 |= CACHETHEN;
+
+	if ((ahc->bugs & AHC_CACHETHEN_BUG) != 0)
+		dscommand0 &= ~CACHETHEN;
+
+	ahc_outb(ahc, DSCOMMAND0, dscommand0);
+
+	ahc->pci_cachesize =
+	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME,
+				/*bytes*/1) & CACHESIZE;
+	ahc->pci_cachesize *= 4;
+
+	/* See if we have a SEEPROM and perform auto-term */
+	check_extport(ahc, &sxfrctl1);
+
+	/*
+	 * Take the LED out of diagnostic mode
+	 */
+	sblkctl = ahc_inb(ahc, SBLKCTL);
+	ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON)));
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_MAX|WR_DFTHRSH_MAX);
+	} else {
+		ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100);
+	}
+
+	if (ahc->flags & AHC_USEDEFAULTS) {
+		/*
+		 * PCI Adapter default setup
+		 * Should only be used if the adapter does not have
+		 * a SEEPROM.
+		 */
+		/* See if someone else set us up already */
+		if (scsiseq != 0) {
+			printf("%s: Using left over BIOS settings\n",
+				ahc_name(ahc));
+			ahc->flags &= ~AHC_USEDEFAULTS;
+			ahc->flags |= AHC_BIOS_ENABLED;
+		} else {
+			/*
+			 * Assume only one connector and always turn
+			 * on termination.
+			 */
+ 			our_id = 0x07;
+			sxfrctl1 = STPWEN;
+		}
+		ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI);
+
+		ahc->our_id = our_id;
+	}
+
+	/*
+	 * Take a look to see if we have external SRAM.
+	 * We currently do not attempt to use SRAM that is
+	 * shared among multiple controllers.
+	 */
+	ahc_probe_ext_scbram(ahc);
+
+	/*
+	 * Record our termination setting for the
+	 * generic initialization routine.
+	 */
+	if ((sxfrctl1 & STPWEN) != 0)
+		ahc->flags |= AHC_TERM_ENB_A;
+
+	/*
+	 * We cannot perform ULTRA speeds without
+	 * the presense of the external precision
+	 * resistor.
+	 */
+	if ((ahc->features & AHC_ULTRA) != 0) {
+		uint32_t devconfig;
+
+		devconfig = ahc_pci_read_config(ahc->dev_softc,
+						DEVCONFIG, /*bytes*/4);
+		if ((devconfig & REXTVALID) == 0)
+			ahc->flags |= AHC_ULTRA_DISABLED;
+	}
+
+	/* Core initialization */
+	error = ahc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Link this softc in with all other ahc instances.
+	 */
+	ahc_softc_insert(ahc);
+
+	return (0);
+}
+
+static void
+ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
+{
+	uint32_t cap;
+	u_int cap_offset;
+
+	/*
+	 * Traverse the capability list looking for
+	 * the power management capability.
+	 */
+	cap = 0;
+	cap_offset = ahc_pci_read_config(ahc->dev_softc,
+					 PCIR_CAP_PTR, /*bytes*/1);
+	while (cap_offset != 0) {
+
+		cap = ahc_pci_read_config(ahc->dev_softc,
+					  cap_offset, /*bytes*/4);
+		if ((cap & 0xFF) == 1
+		 && ((cap >> 16) & 0x3) > 0) {
+			uint32_t pm_control;
+
+			pm_control = ahc_pci_read_config(ahc->dev_softc,
+							 cap_offset + 4,
+							 /*bytes*/4);
+			pm_control &= ~0x3;
+			pm_control |= new_state;
+			ahc_pci_write_config(ahc->dev_softc,
+					     cap_offset + 4,
+					     pm_control, /*bytes*/2);
+			break;
+		}
+		cap_offset = (cap >> 8) & 0xFF;
+	}
+}
+
+/*
+ * Test for the presense of external sram in an
+ * "unshared" configuration.
+ */
+static int
+ahc_ext_scbram_present(struct ahc_softc *ahc)
+{
+	u_int chip;
+	int ramps;
+	int single_user;
+	uint32_t devconfig;
+
+	chip = ahc->chip & AHC_CHIPID_MASK;
+	devconfig = ahc_pci_read_config(ahc->dev_softc,
+					DEVCONFIG, /*bytes*/4);
+	single_user = (devconfig & MPORTMODE) != 0;
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0;
+	else if (chip >= AHC_AIC7870)
+		ramps = (devconfig & RAMPSM) != 0;
+	else
+		ramps = 0;
+
+	if (ramps && single_user)
+		return (1);
+	return (0);
+}
+
+/*
+ * Enable external scbram.
+ */
+static void
+ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck,
+		  int fast, int large)
+{
+	uint32_t devconfig;
+
+	if (ahc->features & AHC_MULTI_FUNC) {
+		/*
+		 * Set the SCB Base addr (highest address bit)
+		 * depending on which channel we are.
+		 */
+		ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc));
+	}
+
+	devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		u_int dscommand0;
+
+		dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+		if (enable)
+			dscommand0 &= ~INTSCBRAMSEL;
+		else
+			dscommand0 |= INTSCBRAMSEL;
+		if (large)
+			dscommand0 &= ~USCBSIZE32;
+		else
+			dscommand0 |= USCBSIZE32;
+		ahc_outb(ahc, DSCOMMAND0, dscommand0);
+	} else {
+		if (fast)
+			devconfig &= ~EXTSCBTIME;
+		else
+			devconfig |= EXTSCBTIME;
+		if (enable)
+			devconfig &= ~SCBRAMSEL;
+		else
+			devconfig |= SCBRAMSEL;
+		if (large)
+			devconfig &= ~SCBSIZE32;
+		else
+			devconfig |= SCBSIZE32;
+	}
+	if (pcheck)
+		devconfig |= EXTSCBPEN;
+	else
+		devconfig &= ~EXTSCBPEN;
+
+	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
+}
+
+/*
+ * Take a look to see if we have external SRAM.
+ * We currently do not attempt to use SRAM that is
+ * shared among multiple controllers.
+ */
+static void
+ahc_probe_ext_scbram(struct ahc_softc *ahc)
+{
+	int num_scbs;
+	int test_num_scbs;
+	int enable;
+	int pcheck;
+	int fast;
+	int large;
+
+	enable = FALSE;
+	pcheck = FALSE;
+	fast = FALSE;
+	large = FALSE;
+	num_scbs = 0;
+	
+	if (ahc_ext_scbram_present(ahc) == 0)
+		goto done;
+
+	/*
+	 * Probe for the best parameters to use.
+	 */
+	ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large);
+	num_scbs = ahc_probe_scbs(ahc);
+	if (num_scbs == 0) {
+		/* The SRAM wasn't really present. */
+		goto done;
+	}
+	enable = TRUE;
+
+	/*
+	 * Clear any outstanding parity error
+	 * and ensure that parity error reporting
+	 * is enabled.
+	 */
+	ahc_outb(ahc, SEQCTL, 0);
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+
+	/* Now see if we can do parity */
+	ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large);
+	num_scbs = ahc_probe_scbs(ahc);
+	if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0
+	 || (ahc_inb(ahc, ERROR) & MPARERR) == 0)
+		pcheck = TRUE;
+
+	/* Clear any resulting parity error */
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+
+	/* Now see if we can do fast timing */
+	ahc_scbram_config(ahc, enable, pcheck, /*fast*/TRUE, large);
+	test_num_scbs = ahc_probe_scbs(ahc);
+	if (test_num_scbs == num_scbs
+	 && ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0
+	  || (ahc_inb(ahc, ERROR) & MPARERR) == 0))
+		fast = TRUE;
+
+	/*
+	 * See if we can use large SCBs and still maintain
+	 * the same overall count of SCBs.
+	 */
+	if ((ahc->features & AHC_LARGE_SCBS) != 0) {
+		ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/TRUE);
+		test_num_scbs = ahc_probe_scbs(ahc);
+		if (test_num_scbs >= num_scbs) {
+			large = TRUE;
+			num_scbs = test_num_scbs;
+	 		if (num_scbs >= 64) {
+				/*
+				 * We have enough space to move the
+				 * "busy targets table" into SCB space
+				 * and make it qualify all the way to the
+				 * lun level.
+				 */
+				ahc->flags |= AHC_SCB_BTT;
+			}
+		}
+	}
+done:
+	/*
+	 * Disable parity error reporting until we
+	 * can load instruction ram.
+	 */
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS);
+	/* Clear any latched parity error */
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+	if (bootverbose && enable) {
+		printf("%s: External SRAM, %s access%s, %dbytes/SCB\n",
+		       ahc_name(ahc), fast ? "fast" : "slow", 
+		       pcheck ? ", parity checking enabled" : "",
+		       large ? 64 : 32);
+	}
+	ahc_scbram_config(ahc, enable, pcheck, fast, large);
+}
+
+/*
+ * Check the external port logic for a serial eeprom
+ * and termination/cable detection contrls.
+ */
+static void
+check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
+{
+	struct	seeprom_descriptor sd;
+	struct	seeprom_config sc;
+	u_int	scsi_conf;
+	u_int	adapter_control;
+	int	have_seeprom;
+	int	have_autoterm;
+
+	sd.sd_ahc = ahc;
+	sd.sd_control_offset = SEECTL;		
+	sd.sd_status_offset = SEECTL;		
+	sd.sd_dataout_offset = SEECTL;		
+
+	/*
+	 * For some multi-channel devices, the c46 is simply too
+	 * small to work.  For the other controller types, we can
+	 * get our information from either SEEPROM type.  Set the
+	 * type to start our probe with accordingly.
+	 */
+	if (ahc->flags & AHC_LARGE_SEEPROM)
+		sd.sd_chip = C56_66;
+	else
+		sd.sd_chip = C46;
+
+	sd.sd_MS = SEEMS;
+	sd.sd_RDY = SEERDY;
+	sd.sd_CS = SEECS;
+	sd.sd_CK = SEECK;
+	sd.sd_DO = SEEDO;
+	sd.sd_DI = SEEDI;
+
+	have_seeprom = acquire_seeprom(ahc, &sd);
+	if (have_seeprom) {
+
+		if (bootverbose) 
+			printf("%s: Reading SEEPROM...", ahc_name(ahc));
+
+		for (;;) {
+			u_int start_addr;
+
+			start_addr = 32 * (ahc->channel - 'A');
+
+			have_seeprom = read_seeprom(&sd, (uint16_t *)&sc,
+						    start_addr, sizeof(sc)/2);
+
+			if (have_seeprom)
+				have_seeprom = verify_cksum(&sc);
+
+			if (have_seeprom != 0 || sd.sd_chip == C56_66) {
+				if (bootverbose) {
+					if (have_seeprom == 0)
+						printf ("checksum error\n");
+					else
+						printf ("done.\n");
+				}
+				break;
+			}
+			sd.sd_chip = C56_66;
+		}
+	}
+
+#if 0
+	if (!have_seeprom) {
+		/*
+		 * Pull scratch ram settings and treat them as
+		 * if they are the contents of an seeprom if
+		 * the 'ADPT' signature is found in SCB2.
+		 */
+		ahc_outb(ahc, SCBPTR, 2);
+		if (ahc_inb(ahc, SCB_BASE) == 'A'
+		 && ahc_inb(ahc, SCB_BASE + 1) == 'D'
+		 && ahc_inb(ahc, SCB_BASE + 2) == 'P'
+		 && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
+			uint8_t *sc_bytes;
+			int	  i;
+
+			sc_bytes = (uint8_t *)&sc;
+			for (i = 0; i < 64; i++)
+				sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i);
+			/* Byte 0x1c is stored in byte 4 of SCB2 */
+			sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4);
+			have_seeprom = verify_cksum(&sc);
+		}
+	}
+#endif
+
+	if (!have_seeprom) {
+		if (bootverbose)
+			printf("%s: No SEEPROM available.\n", ahc_name(ahc));
+		ahc->flags |= AHC_USEDEFAULTS;
+	} else {
+		/*
+		 * Put the data we've collected down into SRAM
+		 * where ahc_init will find it.
+		 */
+		int i;
+		int max_targ = sc.max_targets & CFMAXTARG;
+		uint16_t discenable;
+		uint16_t ultraenb;
+
+		discenable = 0;
+		ultraenb = 0;
+		if ((sc.adapter_control & CFULTRAEN) != 0) {
+			/*
+			 * Determine if this adapter has a "newstyle"
+			 * SEEPROM format.
+			 */
+			for (i = 0; i < max_targ; i++) {
+				if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0){
+					ahc->flags |= AHC_NEWEEPROM_FMT;
+					break;
+				}
+			}
+		}
+
+		for (i = 0; i < max_targ; i++) {
+			u_int     scsirate;
+			uint16_t target_mask;
+
+			target_mask = 0x01 << i;
+			if (sc.device_flags[i] & CFDISC)
+				discenable |= target_mask;
+			if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
+				if ((sc.device_flags[i] & CFSYNCHISULTRA) != 0)
+					ultraenb |= target_mask;
+			} else if ((sc.adapter_control & CFULTRAEN) != 0) {
+				ultraenb |= target_mask;
+			}
+			if ((sc.device_flags[i] & CFXFER) == 0x04
+			 && (ultraenb & target_mask) != 0) {
+				/* Treat 10MHz as a non-ultra speed */
+				sc.device_flags[i] &= ~CFXFER;
+			 	ultraenb &= ~target_mask;
+			}
+			if ((ahc->features & AHC_ULTRA2) != 0) {
+				u_int offset;
+
+				if (sc.device_flags[i] & CFSYNCH)
+					offset = MAX_OFFSET_ULTRA2;
+				else 
+					offset = 0;
+				ahc_outb(ahc, TARG_OFFSET + i, offset);
+
+				/*
+				 * The ultra enable bits contain the
+				 * high bit of the ultra2 sync rate
+				 * field.
+				 */
+				scsirate = (sc.device_flags[i] & CFXFER)
+					 | ((ultraenb & target_mask)
+					    ? 0x8 : 0x0);
+				if (sc.device_flags[i] & CFWIDEB)
+					scsirate |= WIDEXFER;
+			} else {
+				scsirate = (sc.device_flags[i] & CFXFER) << 4;
+				if (sc.device_flags[i] & CFSYNCH)
+					scsirate |= SOFS;
+				if (sc.device_flags[i] & CFWIDEB)
+					scsirate |= WIDEXFER;
+			}
+			ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
+		}
+		ahc->our_id = sc.brtime_id & CFSCSIID;
+
+		scsi_conf = (ahc->our_id & 0x7);
+		if (sc.adapter_control & CFSPARITY)
+			scsi_conf |= ENSPCHK;
+		if (sc.adapter_control & CFRESETB)
+			scsi_conf |= RESET_SCSI;
+
+		if ((sc.adapter_control & CFCHNLBPRIMARY) != 0
+		 && (ahc->features & AHC_MULTI_FUNC) != 0)
+			ahc->flags |= AHC_CHANNEL_B_PRIMARY;
+
+		if (sc.bios_control & CFEXTEND)
+			ahc->flags |= AHC_EXTENDED_TRANS_A;
+
+		if (sc.bios_control & CFBIOSEN)
+			ahc->flags |= AHC_BIOS_ENABLED;
+		if (ahc->features & AHC_ULTRA
+		 && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
+			/* Should we enable Ultra mode? */
+			if (!(sc.adapter_control & CFULTRAEN))
+				/* Treat us as a non-ultra card */
+				ultraenb = 0;
+		}
+
+		if (sc.signature == CFSIGNATURE) {
+			uint32_t devconfig;
+
+			/* Honor the STPWLEVEL settings */
+			devconfig = ahc_pci_read_config(ahc->dev_softc,
+							DEVCONFIG, /*bytes*/4);
+			devconfig &= ~STPWLEVEL;
+			if ((sc.bios_control & CFSTPWLEVEL) != 0)
+				devconfig |= STPWLEVEL;
+			ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+					     devconfig, /*bytes*/4);
+		}
+		/* Set SCSICONF info */
+		ahc_outb(ahc, SCSICONF, scsi_conf);
+		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+		ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
+		ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
+	}
+
+	/*
+	 * Cards that have the external logic necessary to talk to
+	 * a SEEPROM, are almost certain to have the remaining logic
+	 * necessary for auto-termination control.  This assumption
+	 * hasn't failed yet...
+	 */
+	have_autoterm = have_seeprom;
+	if (have_seeprom)
+		adapter_control = sc.adapter_control;
+	else
+		adapter_control = CFAUTOTERM;
+
+	/*
+	 * Some low-cost chips have SEEPROM and auto-term control built
+	 * in, instead of using a GAL.  They can tell us directly
+	 * if the termination logic is enabled.
+	 */
+	if ((ahc->features & AHC_SPIOCAP) != 0) {
+		if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0)
+			have_autoterm = TRUE;
+		else
+			have_autoterm = FALSE;
+	}
+
+	if (have_autoterm)
+		configure_termination(ahc, &sd, adapter_control, sxfrctl1);
+
+	release_seeprom(&sd);
+}
+
+static void
+configure_termination(struct ahc_softc *ahc,
+		      struct seeprom_descriptor *sd,
+		      u_int adapter_control,
+		      u_int *sxfrctl1)
+{
+	uint8_t brddat;
+	
+	brddat = 0;
+
+	/*
+	 * Update the settings in sxfrctl1 to match the
+	 * termination settings 
+	 */
+	*sxfrctl1 = 0;
+	
+	/*
+	 * SEECS must be on for the GALS to latch
+	 * the data properly.  Be sure to leave MS
+	 * on or we will release the seeprom.
+	 */
+	SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS);
+	if ((adapter_control & CFAUTOTERM) != 0
+	 || (ahc->features & AHC_NEW_TERMCTL) != 0) {
+		int internal50_present;
+		int internal68_present;
+		int externalcable_present;
+		int eeprom_present;
+		int enableSEC_low;
+		int enableSEC_high;
+		int enablePRI_low;
+		int enablePRI_high;
+		int sum;
+
+		enableSEC_low = 0;
+		enableSEC_high = 0;
+		enablePRI_low = 0;
+		enablePRI_high = 0;
+		if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
+			ahc_new_term_detect(ahc, &enableSEC_low,
+					       &enableSEC_high,
+					       &enablePRI_low,
+					       &enablePRI_high,
+					       &eeprom_present);
+			if ((adapter_control & CFSEAUTOTERM) == 0) {
+				if (bootverbose)
+					printf("%s: Manual SE Termination\n",
+					       ahc_name(ahc));
+				enableSEC_low = (adapter_control & CFSELOWTERM);
+				enableSEC_high =
+				    (adapter_control & CFSEHIGHTERM);
+			}
+			if ((adapter_control & CFAUTOTERM) == 0) {
+				if (bootverbose)
+					printf("%s: Manual LVD Termination\n",
+					       ahc_name(ahc));
+				enablePRI_low = (adapter_control & CFSTERM);
+				enablePRI_high = (adapter_control & CFWSTERM);
+			}
+			/* Make the table calculations below happy */
+			internal50_present = 0;
+			internal68_present = 1;
+			externalcable_present = 1;
+		} else if ((ahc->features & AHC_SPIOCAP) != 0) {
+			aic785X_cable_detect(ahc, &internal50_present,
+					     &externalcable_present,
+					     &eeprom_present);
+		} else {
+			aic787X_cable_detect(ahc, &internal50_present,
+					     &internal68_present,
+					     &externalcable_present,
+					     &eeprom_present);
+		}
+
+		if ((ahc->features & AHC_WIDE) == 0)
+			internal68_present = 0;
+
+		if (bootverbose
+		 && (ahc->features & AHC_ULTRA2) == 0) {
+			printf("%s: internal 50 cable %s present",
+			       ahc_name(ahc),
+			       internal50_present ? "is":"not");
+
+			if ((ahc->features & AHC_WIDE) != 0)
+				printf(", internal 68 cable %s present",
+				       internal68_present ? "is":"not");
+			printf("\n%s: external cable %s present\n",
+			       ahc_name(ahc),
+			       externalcable_present ? "is":"not");
+		}
+		if (bootverbose)
+			printf("%s: BIOS eeprom %s present\n",
+			       ahc_name(ahc), eeprom_present ? "is" : "not");
+
+		if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
+			/*
+			 * The 50 pin connector is a separate bus,
+			 * so force it to always be terminated.
+			 * In the future, perform current sensing
+			 * to determine if we are in the middle of
+			 * a properly terminated bus.
+			 */
+			internal50_present = 0;
+		}
+
+		/*
+		 * Now set the termination based on what
+		 * we found.
+		 * Flash Enable = BRDDAT7
+		 * Secondary High Term Enable = BRDDAT6
+		 * Secondary Low Term Enable = BRDDAT5 (7890)
+		 * Primary High Term Enable = BRDDAT4 (7890)
+		 */
+		if ((ahc->features & AHC_ULTRA2) == 0
+		 && (internal50_present != 0)
+		 && (internal68_present != 0)
+		 && (externalcable_present != 0)) {
+			printf("%s: Illegal cable configuration!!. "
+			       "Only two connectors on the "
+			       "adapter may be used at a "
+			       "time!\n", ahc_name(ahc));
+		}
+
+		if ((ahc->features & AHC_WIDE) != 0
+		 && ((externalcable_present == 0)
+		  || (internal68_present == 0)
+		  || (enableSEC_high != 0))) {
+			brddat |= BRDDAT6;
+			if (bootverbose) {
+				if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
+					printf("%s: 68 pin termination "
+					       "Enabled\n", ahc_name(ahc));
+				else
+					printf("%s: %sHigh byte termination "
+					       "Enabled\n", ahc_name(ahc),
+					       enableSEC_high ? "Secondary "
+							      : "");
+			}
+		}
+
+		sum = internal50_present + internal68_present
+		    + externalcable_present;
+		if (sum < 2 || (enableSEC_low != 0)) {
+			if ((ahc->features & AHC_ULTRA2) != 0)
+				brddat |= BRDDAT5;
+			else
+				*sxfrctl1 |= STPWEN;
+			if (bootverbose) {
+				if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
+					printf("%s: 50 pin termination "
+					       "Enabled\n", ahc_name(ahc));
+				else
+					printf("%s: %sLow byte termination "
+					       "Enabled\n", ahc_name(ahc),
+					       enableSEC_low ? "Secondary "
+							     : "");
+			}
+		}
+
+		if (enablePRI_low != 0) {
+			*sxfrctl1 |= STPWEN;
+			if (bootverbose)
+				printf("%s: Primary Low Byte termination "
+				       "Enabled\n", ahc_name(ahc));
+		}
+
+		/*
+		 * Setup STPWEN before setting up the rest of
+		 * the termination per the tech note on the U160 cards.
+		 */
+		ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+
+		if (enablePRI_high != 0) {
+			brddat |= BRDDAT4;
+			if (bootverbose)
+				printf("%s: Primary High Byte "
+				       "termination Enabled\n",
+				       ahc_name(ahc));
+		}
+		
+		write_brdctl(ahc, brddat);
+
+	} else {
+		if ((adapter_control & CFSTERM) != 0) {
+			*sxfrctl1 |= STPWEN;
+
+			if (bootverbose)
+				printf("%s: %sLow byte termination Enabled\n",
+				       ahc_name(ahc),
+				       (ahc->features & AHC_ULTRA2) ? "Primary "
+								    : "");
+		}
+
+		if ((adapter_control & CFWSTERM) != 0
+		 && (ahc->features & AHC_WIDE) != 0) {
+			brddat |= BRDDAT6;
+			if (bootverbose)
+				printf("%s: %sHigh byte termination Enabled\n",
+				       ahc_name(ahc),
+				       (ahc->features & AHC_ULTRA2)
+				     ? "Secondary " : "");
+		}
+
+		/*
+		 * Setup STPWEN before setting up the rest of
+		 * the termination per the tech note on the U160 cards.
+		 */
+		ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+
+		if ((ahc->features & AHC_WIDE) != 0)
+			write_brdctl(ahc, brddat);
+	}
+	SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */
+}
+
+static void
+ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low,
+		    int *enableSEC_high, int *enablePRI_low,
+		    int *enablePRI_high, int *eeprom_present)
+{
+	uint8_t brdctl;
+
+	/*
+	 * BRDDAT7 = Eeprom
+	 * BRDDAT6 = Enable Secondary High Byte termination
+	 * BRDDAT5 = Enable Secondary Low Byte termination
+	 * BRDDAT4 = Enable Primary high byte termination
+	 * BRDDAT3 = Enable Primary low byte termination
+	 */
+	brdctl = read_brdctl(ahc);
+	*eeprom_present = brdctl & BRDDAT7;
+	*enableSEC_high = (brdctl & BRDDAT6);
+	*enableSEC_low = (brdctl & BRDDAT5);
+	*enablePRI_high = (brdctl & BRDDAT4);
+	*enablePRI_low = (brdctl & BRDDAT3);
+}
+
+static void
+aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+		     int *internal68_present, int *externalcable_present,
+		     int *eeprom_present)
+{
+	uint8_t brdctl;
+
+	/*
+	 * First read the status of our cables.
+	 * Set the rom bank to 0 since the
+	 * bank setting serves as a multiplexor
+	 * for the cable detection logic.
+	 * BRDDAT5 controls the bank switch.
+	 */
+	write_brdctl(ahc, 0);
+
+	/*
+	 * Now read the state of the internal
+	 * connectors.  BRDDAT6 is INT50 and
+	 * BRDDAT7 is INT68.
+	 */
+	brdctl = read_brdctl(ahc);
+	*internal50_present = (brdctl & BRDDAT6) ? 0 : 1;
+	*internal68_present = (brdctl & BRDDAT7) ? 0 : 1;
+
+	/*
+	 * Set the rom bank to 1 and determine
+	 * the other signals.
+	 */
+	write_brdctl(ahc, BRDDAT5);
+
+	/*
+	 * Now read the state of the external
+	 * connectors.  BRDDAT6 is EXT68 and
+	 * BRDDAT7 is EPROMPS.
+	 */
+	brdctl = read_brdctl(ahc);
+	*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
+	*eeprom_present = (brdctl & BRDDAT7) ? 1 : 0;
+}
+
+static void
+aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+		     int *externalcable_present, int *eeprom_present)
+{
+	uint8_t brdctl;
+
+	ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
+	ahc_outb(ahc, BRDCTL, 0);
+	brdctl = ahc_inb(ahc, BRDCTL);
+	*internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
+	*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
+
+	*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
+}
+	
+static int
+acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
+{
+	int wait;
+
+	if ((ahc->features & AHC_SPIOCAP) != 0
+	 && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
+		return (0);
+
+	/*
+	 * Request access of the memory port.  When access is
+	 * granted, SEERDY will go high.  We use a 1 second
+	 * timeout which should be near 1 second more than
+	 * is needed.  Reason: after the chip reset, there
+	 * should be no contention.
+	 */
+	SEEPROM_OUTB(sd, sd->sd_MS);
+	wait = 1000;  /* 1 second timeout in msec */
+	while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
+		ahc_delay(1000);  /* delay 1 msec */
+	}
+	if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
+		SEEPROM_OUTB(sd, 0); 
+		return (0);
+	}
+	return(1);
+}
+
+static void
+release_seeprom(struct seeprom_descriptor *sd)
+{
+	/* Release access to the memory port and the serial EEPROM. */
+	SEEPROM_OUTB(sd, 0);
+}
+
+static void
+write_brdctl(struct ahc_softc *ahc, uint8_t value)
+{
+	uint8_t brdctl;
+
+	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		brdctl = BRDSTB;
+	 	if (ahc->channel == 'B')
+			brdctl |= BRDCS;
+	} else if ((ahc->features & AHC_ULTRA2) != 0) {
+		brdctl = 0;
+	} else {
+		brdctl = BRDSTB|BRDCS;
+	}
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	brdctl |= value;
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		brdctl |= BRDSTB_ULTRA2;
+	else
+		brdctl &= ~BRDSTB;
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		brdctl = 0;
+	else
+		brdctl &= ~BRDCS;
+	ahc_outb(ahc, BRDCTL, brdctl);
+}
+
+static uint8_t
+read_brdctl(ahc)
+	struct 	ahc_softc *ahc;
+{
+	uint8_t brdctl;
+	uint8_t value;
+
+	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		brdctl = BRDRW;
+	 	if (ahc->channel == 'B')
+			brdctl |= BRDCS;
+	} else if ((ahc->features & AHC_ULTRA2) != 0) {
+		brdctl = BRDRW_ULTRA2;
+	} else {
+		brdctl = BRDRW|BRDCS;
+	}
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	value = ahc_inb(ahc, BRDCTL);
+	ahc_outb(ahc, BRDCTL, 0);
+	return (value);
+}
+
+#define	DPE	0x80
+#define SSE	0x40
+#define	RMA	0x20
+#define	RTA	0x10
+#define STA	0x08
+#define DPR	0x01
+
+void
+ahc_pci_intr(struct ahc_softc *ahc)
+{
+	u_int error;
+	u_int status1;
+
+	error = ahc_inb(ahc, ERROR);
+	if ((error & PCIERRSTAT) == 0)
+		return;
+
+	status1 = ahc_pci_read_config(ahc->dev_softc,
+				      PCIR_STATUS + 1, /*bytes*/1);
+
+	printf("%s: PCI error Interrupt at seqaddr = 0x%x\n",
+	      ahc_name(ahc),
+	      ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+
+	if (status1 & DPE) {
+		printf("%s: Data Parity Error Detected during address "
+		       "or write data phase\n", ahc_name(ahc));
+	}
+	if (status1 & SSE) {
+		printf("%s: Signal System Error Detected\n", ahc_name(ahc));
+	}
+	if (status1 & RMA) {
+		printf("%s: Received a Master Abort\n", ahc_name(ahc));
+	}
+	if (status1 & RTA) {
+		printf("%s: Received a Target Abort\n", ahc_name(ahc));
+	}
+	if (status1 & STA) {
+		printf("%s: Signaled a Target Abort\n", ahc_name(ahc));
+	}
+	if (status1 & DPR) {
+		printf("%s: Data Parity Error has been reported via PERR#\n",
+		       ahc_name(ahc));
+	}
+	if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
+		printf("%s: Latched PCIERR interrupt with "
+		       "no status bits set\n", ahc_name(ahc)); 
+	}
+	ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,
+			     status1, /*bytes*/1);
+
+	if (status1 & (DPR|RMA|RTA)) {
+		ahc_outb(ahc, CLRINT, CLRPARERR);
+	}
+
+	unpause_sequencer(ahc);
+}
+
+static int
+ahc_aic785X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	uint8_t rev;
+
+	probe_config->channel = 'A';
+	probe_config->chip = AHC_AIC7850;
+	probe_config->features = AHC_AIC7850_FE;
+	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
+			   |  AHC_PCI_MWI_BUG;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 1)
+		probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	return (0);
+}
+
+static int
+ahc_aic7860_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	uint8_t rev;
+
+	probe_config->channel = 'A';
+	probe_config->chip = AHC_AIC7860;
+	probe_config->features = AHC_AIC7860_FE;
+	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
+			   |  AHC_PCI_MWI_BUG;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 1)
+		probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	return (0);
+}
+
+static int
+ahc_apa1480_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7860_setup(pci, probe_config);
+	if (error != 0)
+		return (error);
+	probe_config->features |= AHC_REMOVABLE;
+	return (0);
+}
+
+static int
+ahc_aic7870_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	probe_config->channel = 'A';
+	probe_config->chip = AHC_AIC7870;
+	probe_config->features = AHC_AIC7870_FE;
+	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG
+			   |  AHC_PCI_MWI_BUG;
+	return (0);
+}
+
+static int
+ahc_aha394X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7870_setup(pci, probe_config);
+	if (error == 0)
+		error = ahc_aha394XX_setup(pci, probe_config);
+	return (error);
+}
+
+static int
+ahc_aha398X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7870_setup(pci, probe_config);
+	if (error == 0)
+		error = ahc_aha398XX_setup(pci, probe_config);
+	return (error);
+}
+
+static int
+ahc_aha494X_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7870_setup(pci, probe_config);
+	if (error == 0)
+		error = ahc_aha494XX_setup(pci, probe_config);
+	return (error);
+}
+
+static int
+ahc_aic7880_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	uint8_t rev;
+
+	probe_config->channel = 'A';
+	probe_config->chip = AHC_AIC7880;
+	probe_config->features = AHC_AIC7880_FE;
+	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 1) {
+		probe_config->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	} else {
+		probe_config->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+	}
+	return (0);
+}
+
+static int
+ahc_aha2940Pro_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	probe_config->flags |= AHC_INT50_SPEEDFLEX;
+	error = ahc_aic7880_setup(pci, probe_config);
+	return (0);
+}
+
+static int
+ahc_aha394XU_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7880_setup(pci, probe_config);
+	if (error == 0)
+		error = ahc_aha394XX_setup(pci, probe_config);
+	return (error);
+}
+
+static int
+ahc_aha398XU_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7880_setup(pci, probe_config);
+	if (error == 0)
+		error = ahc_aha398XX_setup(pci, probe_config);
+	return (error);
+}
+
+static int
+ahc_aic7890_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	uint8_t rev;
+
+	probe_config->channel = 'A';
+	probe_config->chip = AHC_AIC7890;
+	probe_config->features = AHC_AIC7890_FE;
+	probe_config->flags |= AHC_NEWEEPROM_FMT;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev == 0)
+		probe_config->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
+	return (0);
+}
+
+static int
+ahc_aic7892_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	probe_config->channel = 'A';
+	probe_config->chip = AHC_AIC7892;
+	probe_config->features = AHC_AIC7892_FE;
+	probe_config->flags |= AHC_NEWEEPROM_FMT;
+	probe_config->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+	return (0);
+}
+
+static int
+ahc_aic7895_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	uint8_t rev;
+
+	probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+	/*
+	 * The 'C' revision of the aic7895 has a few additional features.
+	 */
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 4) {
+		probe_config->chip = AHC_AIC7895C;
+		probe_config->features = AHC_AIC7895C_FE;
+	} else  {
+		u_int command;
+
+		probe_config->chip = AHC_AIC7895;
+		probe_config->features = AHC_AIC7895_FE;
+
+		/*
+		 * The BIOS disables the use of MWI transactions
+		 * since it does not have the MWI bug work around
+		 * we have.  Disabling MWI reduces performance, so
+		 * turn it on again.
+		 */
+		command = ahc_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1);
+		command |= PCIM_CMD_MWRICEN;
+		ahc_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1);
+		probe_config->bugs |= AHC_PCI_MWI_BUG;
+	}
+	/*
+	 * XXX Does CACHETHEN really not work???  What about PCI retry?
+	 * on C level chips.  Need to test, but for now, play it safe.
+	 */
+	probe_config->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
+			   |  AHC_CACHETHEN_BUG;
+
+#if 0
+	uint32_t devconfig;
+
+	/*
+	 * Cachesize must also be zero due to stray DAC
+	 * problem when sitting behind some bridges.
+	 */
+	ahc_pci_write_config(pci, CSIZE_LATTIME, 0, /*bytes*/1);
+	devconfig = ahc_pci_read_config(pci, DEVCONFIG, /*bytes*/1);
+	devconfig |= MRDCEN;
+	ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1);
+#endif
+	probe_config->flags |= AHC_NEWEEPROM_FMT;
+	return (0);
+}
+
+static int
+ahc_aic7896_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+	probe_config->chip = AHC_AIC7896;
+	probe_config->features = AHC_AIC7896_FE;
+	probe_config->flags |= AHC_NEWEEPROM_FMT;
+	probe_config->bugs |= AHC_CACHETHEN_DIS_BUG;
+	return (0);
+}
+
+static int
+ahc_aic7899_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	probe_config->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+	probe_config->chip = AHC_AIC7899;
+	probe_config->features = AHC_AIC7899_FE;
+	probe_config->flags |= AHC_NEWEEPROM_FMT;
+	probe_config->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+	return (0);
+}
+
+static int
+ahc_aha29160C_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	int error;
+
+	error = ahc_aic7899_setup(pci, probe_config);
+	if (error != 0)
+		return (error);
+	probe_config->features |= AHC_REMOVABLE;
+	return (0);
+}
+
+static int
+ahc_raid_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	printf("RAID functionality unsupported\n");
+	return (ENXIO);
+}
+
+static int
+ahc_aha394XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	switch (ahc_get_pci_slot(pci)) {
+	case AHC_394X_SLOT_CHANNEL_A:
+		probe_config->channel = 'A';
+		break;
+	case AHC_394X_SLOT_CHANNEL_B:
+		probe_config->channel = 'B';
+		break;
+	default:
+		printf("adapter at unexpected slot %d\n"
+		       "unable to map to a channel\n",
+		       ahc_get_pci_slot(pci));
+		probe_config->channel = 'A';
+	}
+	return (0);
+}
+
+static int
+ahc_aha398XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	switch (ahc_get_pci_slot(pci)) {
+	case AHC_398X_SLOT_CHANNEL_A:
+		probe_config->channel = 'A';
+		break;
+	case AHC_398X_SLOT_CHANNEL_B:
+		probe_config->channel = 'B';
+		break;
+	case AHC_398X_SLOT_CHANNEL_C:
+		probe_config->channel = 'C';
+		break;
+	default:
+		printf("adapter at unexpected slot %d\n"
+		       "unable to map to a channel\n",
+		       ahc_get_pci_slot(pci));
+		probe_config->channel = 'A';
+		break;
+	}
+	probe_config->flags |= AHC_LARGE_SEEPROM;
+	return (0);
+}
+
+static int
+ahc_aha494XX_setup(ahc_dev_softc_t pci, struct ahc_probe_config *probe_config)
+{
+	switch (ahc_get_pci_slot(pci)) {
+	case AHC_494X_SLOT_CHANNEL_A:
+		probe_config->channel = 'A';
+		break;
+	case AHC_494X_SLOT_CHANNEL_B:
+		probe_config->channel = 'B';
+		break;
+	case AHC_494X_SLOT_CHANNEL_C:
+		probe_config->channel = 'C';
+		break;
+	case AHC_494X_SLOT_CHANNEL_D:
+		probe_config->channel = 'D';
+		break;
+	default:
+		printf("adapter at unexpected slot %d\n"
+		       "unable to map to a channel\n",
+		       ahc_get_pci_slot(pci));
+		probe_config->channel = 'A';
+	}
+	probe_config->flags |= AHC_LARGE_SEEPROM;
+	return (0);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2000, 2001 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
+ * sym driver.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $
+ */
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+
+static void	copy_mem_info(struct info_str *info, char *data, int len);
+static int	copy_info(struct info_str *info, char *fmt, ...);
+static u_int	scsi_calc_syncsrate(u_int period_factor);
+static void	ahc_dump_target_state(struct ahc_softc *ahc,
+				      struct info_str *info,
+				      u_int our_id, char channel,
+				      u_int target_id, u_int target_offset);
+static void	ahc_dump_device_state(struct info_str *info,
+				      struct ahc_linux_device *dev);
+
+static void
+copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->offset + info->length)
+		len = info->offset + info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+
+	if (info->pos < info->offset) {
+		off_t partial;
+
+		partial = info->offset - info->pos;
+		data += partial;
+		info->pos += partial;
+		len  -= partial;
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer, data, len);
+		info->pos += len;
+		info->buffer += len;
+	}
+}
+
+static int
+copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[256];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return (len);
+}
+
+/*
+ * Table of syncrates that don't follow the "divisible by 4"
+ * rule. This table will be expanded in future SCSI specs.
+ */
+static struct {
+	u_int period_factor;
+	u_int period;	/* in 10ths of ns */
+} scsi_syncrates[] = {
+	{ 0x09, 125 },	/* FAST-80 */
+	{ 0x0a, 250 },	/* FAST-40 40MHz */
+	{ 0x0b, 303 },	/* FAST-40 33MHz */
+	{ 0x0c, 500 }	/* FAST-20 */
+};
+ 
+/*
+ * Return the frequency in kHz corresponding to the given
+ * sync period factor.
+ */
+static u_int
+scsi_calc_syncsrate(u_int period_factor)
+{
+	int i; 
+	int num_syncrates;
+ 
+	num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
+	/* See if the period is in the "exception" table */
+	for (i = 0; i < num_syncrates; i++) {
+
+		if (period_factor == scsi_syncrates[i].period_factor) {
+       			/* Period in kHz */
+			return (10000000 / scsi_syncrates[i].period);
+		}
+	}
+
+	/*
+	 * Wasn't in the table, so use the standard
+	 * 4 times conversion.
+	 */
+	return (10000000 / (period_factor * 4 * 10));
+}
+
+void
+ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
+{
+	u_int speed;
+	u_int freq;
+	u_int mb;
+
+        speed = 3300;
+        freq = 0;
+	if (tinfo->offset != 0) {
+		freq = scsi_calc_syncsrate(tinfo->period);
+		speed = freq;
+	}
+	speed *= (0x01 << tinfo->width);
+        mb = speed / 1000;
+        if (mb > 0)
+		copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
+        else
+		copy_info(info, "%dKB/s transfers", speed);
+
+	if (freq != 0) {
+		copy_info(info, " (%d.%03dMHz%s, offset %d",
+			 freq / 1000, freq % 1000,
+			 (tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
+			 ? " DT" : "", tinfo->offset);
+	}
+
+	if (tinfo->width > 0) {
+		if (freq != 0) {
+			copy_info(info, ", ");
+		} else {
+			copy_info(info, " (");
+		}
+		copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
+	} else if (freq != 0) {
+		copy_info(info, ")");
+	}
+	copy_info(info, "\n");
+}
+
+static void
+ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
+		      u_int our_id, char channel, u_int target_id,
+		      u_int target_offset)
+{
+	struct	ahc_linux_target *targ;
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	tmode_tstate *tstate;
+	int	lun;
+
+	tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+				    target_id, &tstate);
+	copy_info(info, "Channel %c Target %d Negotiation Settings\n",
+		  channel, target_id);
+	copy_info(info, "\tUser: ");
+	ahc_format_transinfo(info, &tinfo->user);
+	targ = ahc->platform_data->targets[target_offset];
+	if (targ == NULL)
+		return;
+
+	copy_info(info, "\tGoal: ");
+	ahc_format_transinfo(info, &tinfo->goal);
+	copy_info(info, "\tCurr: ");
+	ahc_format_transinfo(info, &tinfo->current);
+
+	for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+		struct ahc_linux_device *dev;
+
+		dev = targ->devices[lun];
+
+		if (dev == NULL)
+			continue;
+
+		ahc_dump_device_state(info, dev);
+	}
+}
+
+static void
+ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev)
+{
+	copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
+		  dev->target->channel + 'A', dev->target->target, dev->lun);
+
+	copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands);
+	copy_info(info, "\t\tCommands Active %d\n", dev->active);
+	copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
+	copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
+	copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
+}
+
+/*
+ * Return information to handle /proc support for the driver.
+ */
+int
+aic7xxx_proc_info(char *buffer, char **start, off_t offset,
+		  int length, int hostno, int inout)
+{
+	struct	ahc_softc *ahc;
+	struct	info_str info;
+	char	ahc_info[256];
+	u_int	max_targ;
+	u_int	i;
+
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		if (ahc->platform_data->host->host_no == hostno)
+			break;
+	}
+
+	if (ahc == NULL)
+		return (-EINVAL);
+
+	 /* Has data been written to the file? */ 
+	if (inout == TRUE)
+		return (-ENOSYS);
+
+	if (start)
+		*start = buffer;
+
+	info.buffer	= buffer;
+	info.length	= length;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
+		  AIC7XXX_DRIVER_VERSION);
+	ahc_controller_info(ahc, ahc_info);
+	copy_info(&info, "%s\n", ahc_info);
+
+	max_targ = 15;
+	if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
+		max_targ = 7;
+
+	for (i = 0; i <= max_targ; i++) {
+		u_int our_id;
+		u_int target_id;
+		char channel;
+
+		channel = 'A';
+		our_id = ahc->our_id;
+		target_id = i;
+		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 'B';
+			our_id = ahc->our_id_b;
+			target_id = i % 8;
+		}
+
+		ahc_dump_target_state(ahc, &info, our_id,
+				      channel, target_id, i);
+	}
+	return (info.pos > info.offset ? info.pos - info.offset : 0);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_reg.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h	Tue Mar  6 19:18:16 2001
@@ -0,0 +1,706 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+
+#define	SCSISEQ         		0x00
+#define		TEMODE          	0x80
+#define		SCSIRSTO        	0x01
+
+#define	SXFRCTL0        		0x01
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		FAST20          	0x20
+#define		CLRSTCNT        	0x10
+#define		SPIOEN          	0x08
+#define		SCAMEN          	0x04
+#define		CLRCHN          	0x02
+
+#define	SXFRCTL1        		0x02
+#define		BITBUCKET       	0x80
+#define		SWRAPEN         	0x40
+#define		STIMESEL        	0x18
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	SCSISIGO        		0x03
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	SCSISIGI        		0x03
+#define		P_DATAIN_DT     	0x60
+#define		P_DATAOUT_DT    	0x20
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIRATE        		0x04
+#define		WIDEXFER        	0x80
+#define		SXFR            	0x70
+#define		ENABLE_CRC      	0x40
+#define		SINGLE_EDGE     	0x10
+#define		SOFS            	0x0f
+#define		SXFR_ULTRA2     	0x0f
+
+#define	SCSIID          		0x05
+#define	SCSIOFFSET      		0x05
+#define		SOFS_ULTRA2     	0x7f
+
+#define	SCSIDATL        		0x06
+
+#define	SCSIDATH        		0x07
+
+#define	STCNT           		0x08
+
+#define	OPTIONMODE      		0x08
+#define		AUTORATEEN      	0x80
+#define		AUTOACKEN       	0x40
+#define		ATNMGMNTEN      	0x20
+#define		BUSFREEREV      	0x10
+#define		EXPPHASEDIS     	0x08
+#define		SCSIDATL_IMGEN  	0x04
+#define		OPTIONMODE_DEFAULTS	0x03
+#define		AUTO_MSGOUT_DE  	0x02
+#define		DIS_MSGIN_DUALEDGE	0x01
+
+#define	TARGCRCCNT      		0x0a
+
+#define	CLRSINT0        		0x0b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRIOERR        	0x08
+#define		CLRSWRAP        	0x08
+#define		CLRSPIORDY      	0x02
+
+#define	SSTAT0          		0x0b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		IOERR           	0x08
+#define		SWRAP           	0x08
+#define		SDONE           	0x04
+#define		SPIORDY         	0x02
+#define		DMADONE         	0x01
+
+#define	CLRSINT1        		0x0c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRPHASECHG     	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x0c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		PHASECHG        	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x0d
+#define		OVERRUN         	0x80
+#define		SHVALID         	0x40
+#define		SFCNT           	0x1f
+#define		EXP_ACTIVE      	0x10
+#define		CRCVALERR       	0x08
+#define		CRCENDERR       	0x04
+#define		CRCREQERR       	0x02
+#define		DUAL_EDGE_ERR   	0x01
+
+#define	SSTAT3          		0x0e
+#define		SCSICNT         	0xf0
+#define		OFFCNT          	0x0f
+
+#define	SCSIID_ULTRA2   		0x0f
+
+#define	SIMODE0         		0x10
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENIOERR         	0x08
+#define		ENSWRAP         	0x08
+#define		ENSDONE         	0x04
+#define		ENSPIORDY       	0x02
+#define		ENDMADONE       	0x01
+
+#define	SIMODE1         		0x11
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENPHASECHG      	0x02
+#define		ENREQINIT       	0x01
+
+#define	SCSIBUSL        		0x12
+
+#define	SCSIBUSH        		0x13
+
+#define	SHADDR          		0x14
+
+#define	SELTIMER        		0x18
+#define	TARGIDIN        		0x18
+#define		STAGE6          	0x20
+#define		STAGE5          	0x10
+#define		STAGE4          	0x08
+#define		STAGE3          	0x04
+#define		STAGE2          	0x02
+#define		STAGE1          	0x01
+
+#define	SELID           		0x19
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	SCAMCTL         		0x1a
+#define		ENSCAMSELO      	0x80
+#define		CLRSCAMSELID    	0x40
+#define		ALTSTIM         	0x20
+#define		DFLTTID         	0x10
+#define		SCAMLVL         	0x03
+
+#define	TARGID          		0x1b
+
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		HAS_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
+#define	BRDCTL          		0x1d
+#define		BRDDAT7         	0x80
+#define		BRDDAT6         	0x40
+#define		BRDDAT5         	0x20
+#define		BRDDAT4         	0x10
+#define		BRDSTB          	0x10
+#define		BRDCS           	0x08
+#define		BRDDAT3         	0x08
+#define		BRDDAT2         	0x04
+#define		BRDRW           	0x04
+#define		BRDRW_ULTRA2    	0x02
+#define		BRDCTL1         	0x02
+#define		BRDCTL0         	0x01
+#define		BRDSTB_ULTRA2   	0x01
+
+#define	SEECTL          		0x1e
+#define		EXTARBACK       	0x80
+#define		EXTARBREQ       	0x40
+#define		SEEMS           	0x20
+#define		SEERDY          	0x10
+#define		SEECS           	0x08
+#define		SEECK           	0x04
+#define		SEEDO           	0x02
+#define		SEEDI           	0x01
+
+#define	SBLKCTL         		0x1f
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		AUTOFLUSHDIS    	0x20
+#define		ENAB40          	0x08
+#define		SELBUSB         	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+#define		XCVR            	0x01
+
+#define	BUSY_TARGETS    		0x20
+#define	TARG_SCSIRATE   		0x20
+
+#define	SRAM_BASE       		0x20
+
+#define	ULTRA_ENB       		0x30
+#define	CMDSIZE_TABLE   		0x30
+
+#define	DISC_DSB        		0x32
+
+#define	CMDSIZE_TABLE_TAIL		0x34
+
+#define	MWI_RESIDUAL    		0x38
+
+#define	NEXT_QUEUED_SCB 		0x39
+
+#define	MSG_OUT         		0x3a
+
+#define	DMAPARAMS       		0x3b
+#define		PRELOADEN       	0x80
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAENACK       	0x10
+#define		SDMAEN          	0x10
+#define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SEQ_FLAGS       		0x3c
+#define		IDENTIFY_SEEN   	0x80
+#define		TARGET_CMD_IS_TAGGED	0x40
+#define		DPHASE          	0x20
+#define		TARG_CMD_PENDING	0x10
+#define		CMDPHASE_PENDING	0x08
+#define		DPHASE_PENDING  	0x04
+#define		SPHASE_PENDING  	0x02
+#define		NO_DISCONNECT   	0x01
+
+#define	SAVED_SCSIID    		0x3d
+
+#define	SAVED_LUN       		0x3e
+
+#define	LASTPHASE       		0x3f
+#define		P_MESGIN        	0xe0
+#define		PHASE_MASK      	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		P_DATAIN        	0x40
+#define		MSGI            	0x20
+#define		P_BUSFREE       	0x01
+#define		P_DATAOUT       	0x00
+
+#define	WAITING_SCBH    		0x40
+
+#define	DISCONNECTED_SCBH		0x41
+
+#define	FREE_SCBH       		0x42
+
+#define	COMPLETE_SCBH   		0x43
+
+#define	HSCB_ADDR       		0x44
+
+#define	SHARED_DATA_ADDR		0x48
+
+#define	KERNEL_QINPOS   		0x4c
+
+#define	QINPOS          		0x4d
+
+#define	QOUTPOS         		0x4e
+
+#define	KERNEL_TQINPOS  		0x4f
+
+#define	TQINPOS         		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
+#define		EXIT_MSG_LOOP   	0x08
+#define		CONT_MSG_LOOP   	0x04
+#define		CONT_TARG_SESSION	0x02
+
+#define	ARG_2           		0x52
+#define	RETURN_2        		0x52
+
+#define	LAST_MSG        		0x53
+
+#define	TARGET_MSG_REQUEST		0x54
+
+#define	SCSISEQ_TEMPLATE		0x56
+#define		ENSELO          	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		ENAUTOATNO      	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNP      	0x02
+
+#define	DATA_COUNT_ODD  		0x57
+
+#define	INITIATOR_TAG   		0x58
+
+#define	SEQ_FLAGS2      		0x59
+#define		SCB_DMA         	0x01
+
+#define	SCSICONF        		0x5a
+#define		TERM_ENB        	0x80
+#define		RESET_SCSI      	0x40
+#define		ENSPCHK         	0x20
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
+
+#define	INTDEF          		0x5c
+#define		EDGE_TRIG       	0x80
+#define		VECTOR          	0x0f
+
+#define	HOSTCONF        		0x5d
+
+#define	HA_274_BIOSCTRL 		0x5f
+#define		BIOSMODE        	0x30
+#define		BIOSDISABLED    	0x30
+#define		CHANNEL_B_PRIMARY	0x08
+
+#define	SEQCTL          		0x60
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQRAM          		0x61
+
+#define	SEQADDR0        		0x62
+
+#define	SEQADDR1        		0x63
+#define		SEQADDR1_MASK   	0x01
+
+#define	ACCUM           		0x64
+
+#define	SINDEX          		0x65
+
+#define	DINDEX          		0x66
+
+#define	ALLONES         		0x69
+
+#define	ALLZEROS        		0x6a
+
+#define	NONE            		0x6a
+
+#define	FLAGS           		0x6b
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SINDIR          		0x6c
+
+#define	DINDIR          		0x6d
+
+#define	FUNCTION1       		0x6e
+
+#define	STACK           		0x6f
+
+#define	TARG_OFFSET     		0x70
+
+#define	BCTL            		0x84
+#define		ACE             	0x08
+#define		ENABLE          	0x01
+
+#define	DSCOMMAND0      		0x84
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+#define		INTSCBRAMSEL    	0x08
+#define		RAMPS           	0x04
+#define		USCBSIZE32      	0x02
+#define		CIOPARCKEN      	0x01
+
+#define	BUSTIME         		0x85
+#define		BOFF            	0xf0
+#define		BON             	0x0f
+
+#define	BUSSPD          		0x86
+#define		DFTHRSH         	0xc0
+#define		DFTHRSH_75      	0x80
+#define		STBOFF          	0x38
+#define		STBON           	0x07
+
+#define	HS_MAILBOX      		0x86
+#define		HOST_MAILBOX    	0xf0
+#define		HOST_TQINPOS    	0x80
+#define		SEQ_MAILBOX     	0x0f
+
+#define	DSPCISTATUS     		0x86
+#define		DFTHRSH_100     	0xc0
+
+#define	HCNTRL          		0x87
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		IRQMS           	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HADDR           		0x88
+
+#define	HCNT            		0x8c
+
+#define	SCBPTR          		0x90
+
+#define	INTSTAT         		0x91
+#define		SEQINT_MASK     	0xf1
+#define		OUT_OF_RANGE    	0xe1
+#define		NO_FREE_SCB     	0xd1
+#define		SCB_MISMATCH    	0xc1
+#define		MISSED_BUSFREE  	0xb1
+#define		MKMSG_FAILED    	0xa1
+#define		DATA_OVERRUN    	0x91
+#define		PERR_DETECTED   	0x81
+#define		BAD_STATUS      	0x71
+#define		HOST_MSG_LOOP   	0x61
+#define		RESIDUAL        	0x51
+#define		IGN_WIDE_RES    	0x41
+#define		NO_MATCH        	0x31
+#define		NO_IDENT        	0x21
+#define		SEND_REJECT     	0x11
+#define		INT_PEND        	0x0f
+#define		BRKADRINT       	0x08
+#define		SCSIINT         	0x04
+#define		CMDCMPLT        	0x02
+#define		BAD_PHASE       	0x01
+#define		SEQINT          	0x01
+
+#define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
+#define		CLRBRKADRINT    	0x08
+#define		CLRSCSIINT      	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSEQINT       	0x01
+
+#define	ERROR           		0x92
+#define		CIOPARERR       	0x80
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
+#define	DFCNTRL         		0x93
+
+#define	DFSTATUS        		0x94
+#define		PRELOAD_AVAIL   	0x80
+#define		DWORDEMP        	0x20
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	DFWADDR         		0x95
+
+#define	DFRADDR         		0x97
+
+#define	DFDAT           		0x99
+
+#define	SCBCNT          		0x9a
+#define		SCBAUTO         	0x80
+#define		SCBCNT_MASK     	0x1f
+
+#define	QINFIFO         		0x9b
+
+#define	QINCNT          		0x9c
+
+#define	QOUTFIFO        		0x9d
+
+#define	CRCCONTROL1     		0x9d
+#define		CRCONSEEN       	0x80
+#define		CRCVALCHKEN     	0x40
+#define		CRCENDCHKEN     	0x20
+#define		CRCREQCHKEN     	0x10
+#define		TARGCRCENDEN    	0x08
+#define		TARGCRCCNTEN    	0x04
+
+#define	QOUTCNT         		0x9e
+
+#define	SCSIPHASE       		0x9e
+#define		STATUS_PHASE    	0x20
+#define		COMMAND_PHASE   	0x10
+#define		MSG_IN_PHASE    	0x08
+#define		MSG_OUT_PHASE   	0x04
+#define		DATA_IN_PHASE   	0x02
+#define		DATA_OUT_PHASE  	0x01
+
+#define	SFUNCT          		0x9f
+#define		ALT_MODE        	0x80
+
+#define	SCB_CDB_PTR     		0xa0
+#define	SCB_CDB_STORE   		0xa0
+#define	SCB_TARGET_INFO 		0xa0
+#define	SCB_RESIDUAL_DATACNT		0xa0
+
+#define	SCB_BASE        		0xa0
+
+#define	SCB_RESIDUAL_SGPTR		0xa4
+
+#define	SCB_SCSI_STATUS 		0xa8
+
+#define	SCB_CDB_STORE_PAD		0xa9
+
+#define	SCB_DATAPTR     		0xac
+
+#define	SCB_DATACNT     		0xb0
+#define		SG_LAST_SEG     	0x80
+#define		SG_HIGH_ADDR_BITS	0x7f
+
+#define	SCB_SGPTR       		0xb4
+#define		SG_RESID_VALID  	0x04
+#define		SG_FULL_RESID   	0x02
+#define		SG_LIST_NULL    	0x01
+
+#define	SCB_CONTROL     		0xb8
+#define		TARGET_SCB      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		MK_MESSAGE      	0x10
+#define		ULTRAENB        	0x08
+#define		DISCONNECTED    	0x04
+#define		SCB_TAG_TYPE    	0x03
+
+#define	SCB_SCSIID      		0xb9
+#define		TID             	0xf0
+#define		TWIN_CHNLB      	0x80
+#define		TWIN_TID        	0x70
+#define		OID             	0x0f
+
+#define	SCB_LUN         		0xba
+#define		LID             	0xff
+
+#define	SCB_TAG         		0xbb
+
+#define	SCB_CDB_LEN     		0xbc
+
+#define	SCB_SCSIRATE    		0xbd
+
+#define	SCB_SCSIOFFSET  		0xbe
+
+#define	SCB_NEXT        		0xbf
+
+#define	SEECTL_2840     		0xc0
+#define		CS_2840         	0x04
+#define		CK_2840         	0x02
+#define		DO_2840         	0x01
+
+#define	SCB_64_SPARE    		0xc0
+
+#define	STATUS_2840     		0xc1
+#define		EEPROM_TF       	0x80
+#define		BIOS_SEL        	0x60
+#define		ADSEL           	0x1e
+#define		DI_2840         	0x01
+
+#define	SCB_64_BTT      		0xd0
+
+#define	CCHADDR         		0xe0
+
+#define	CCHCNT          		0xe8
+
+#define	CCSGRAM         		0xe9
+
+#define	CCSGADDR        		0xea
+
+#define	CCSGCTL         		0xeb
+#define		CCSGDONE        	0x80
+#define		CCSGEN          	0x08
+#define		SG_FETCH_NEEDED 	0x02
+#define		CCSGRESET       	0x01
+
+#define	CCSCBRAM        		0xec
+
+#define	CCSCBADDR       		0xed
+
+#define	CCSCBCTL        		0xee
+#define		CCSCBDONE       	0x80
+#define		ARRDONE         	0x40
+#define		CCARREN         	0x10
+#define		CCSCBEN         	0x08
+#define		CCSCBDIR        	0x04
+#define		CCSCBRESET      	0x01
+
+#define	CCSCBCNT        		0xef
+
+#define	SCBBADDR        		0xf0
+
+#define	CCSCBPTR        		0xf1
+
+#define	HNSCB_QOFF      		0xf4
+
+#define	SNSCB_QOFF      		0xf6
+
+#define	SDSCB_QOFF      		0xf8
+
+#define	QOFF_CTLSTA     		0xfa
+#define		SCB_AVAIL       	0x40
+#define		SNSCB_ROLLOVER  	0x20
+#define		SDSCB_ROLLOVER  	0x10
+#define		SCB_QSIZE       	0x07
+#define		SCB_QSIZE_256   	0x06
+
+#define	DFF_THRSH       		0xfb
+#define		WR_DFTHRSH      	0x70
+#define		WR_DFTHRSH_MAX  	0x70
+#define		WR_DFTHRSH_90   	0x60
+#define		WR_DFTHRSH_85   	0x50
+#define		WR_DFTHRSH_75   	0x40
+#define		WR_DFTHRSH_63   	0x30
+#define		WR_DFTHRSH_50   	0x20
+#define		WR_DFTHRSH_25   	0x10
+#define		RD_DFTHRSH_MAX  	0x07
+#define		RD_DFTHRSH      	0x07
+#define		RD_DFTHRSH_90   	0x06
+#define		RD_DFTHRSH_85   	0x05
+#define		RD_DFTHRSH_75   	0x04
+#define		RD_DFTHRSH_63   	0x03
+#define		RD_DFTHRSH_50   	0x02
+#define		RD_DFTHRSH_25   	0x01
+#define		RD_DFTHRSH_MIN  	0x00
+#define		WR_DFTHRSH_MIN  	0x00
+
+#define	SG_CACHE_SHADOW 		0xfc
+#define		SG_ADDR_MASK    	0xf8
+#define		ODD_SEG         	0x04
+#define		LAST_SEG        	0x02
+#define		LAST_SEG_DONE   	0x01
+
+#define	SG_CACHE_PRE    		0xfc
+
+
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	BUS_8_BIT	0x00
+#define	CCSGRAM_MAXSEGS	0x10
+#define	TARGET_DATA_IN	0x01
+#define	STATUS_QUEUE_FULL	0x28
+#define	STATUS_BUSY	0x08
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_16_BIT	0x01
+#define	TID_SHIFT	0x04
+#define	SCB_DOWNLOAD_SIZE_64	0x30
+#define	SCB_UPLOAD_SIZE	0x20
+#define	HOST_MAILBOX_SHIFT	0x04
+#define	SCB_INITIATOR_TAG	0x03
+#define	SCB_TARGET_STATUS	0x02
+#define	SCB_TARGET_DATA_DIR	0x01
+#define	SCB_TARGET_PHASES	0x00
+#define	MAX_OFFSET_ULTRA2	0x7f
+#define	MAX_OFFSET_16BIT	0x08
+#define	TARGET_CMD_CMPLT	0xfe
+#define	SCB_LIST_NULL	0xff
+#define	SG_SIZEOF	0x08
+#define	SCB_DOWNLOAD_SIZE	0x20
+#define	SEQ_MAILBOX_SHIFT	0x00
+#define	HOST_MSG	0xff
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
+
+
+/* Downloaded Constant Definitions */
+#define	SG_PREFETCH_ADDR_MASK	0x06
+#define	SG_PREFETCH_ALIGN_MASK	0x05
+#define	QOUTFIFO_OFFSET	0x00
+#define	SG_PREFETCH_CNT	0x04
+#define	INVERTED_CACHESIZE_MASK	0x03
+#define	CACHESIZE_MASK	0x02
+#define	QINFIFO_OFFSET	0x01
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h linux/drivers/scsi/aic7xxx/aic7xxx_seq.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aic7xxx_seq.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.h	Tue Mar  6 19:18:16 2001
@@ -0,0 +1,1239 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+static uint8_t seqprog[] = {
+	0xb2, 0x00, 0x00, 0x08,
+	0xf7, 0x11, 0x22, 0x08,
+	0x00, 0x65, 0xde, 0x59,
+	0xf7, 0x01, 0x02, 0x08,
+	0xff, 0x6a, 0x24, 0x08,
+	0x40, 0x00, 0x40, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x40, 0x00, 0x40, 0x68,
+	0xff, 0x40, 0x3c, 0x60,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x60, 0x0b, 0x42, 0x68,
+	0x40, 0xfa, 0x12, 0x78,
+	0x01, 0x4d, 0xc8, 0x30,
+	0x00, 0x4c, 0x12, 0x70,
+	0x01, 0x39, 0xa2, 0x30,
+	0x00, 0x6a, 0x7e, 0x5e,
+	0x01, 0x51, 0x20, 0x31,
+	0x01, 0x59, 0xb2, 0x00,
+	0x0d, 0x6a, 0x76, 0x00,
+	0x00, 0x51, 0xda, 0x5d,
+	0x01, 0x51, 0xc8, 0x30,
+	0x00, 0x39, 0xde, 0x60,
+	0x00, 0xbb, 0x30, 0x70,
+	0xc1, 0x6a, 0x96, 0x5e,
+	0x01, 0xbf, 0x72, 0x30,
+	0x01, 0x40, 0x7e, 0x31,
+	0x01, 0x90, 0x80, 0x30,
+	0x01, 0xf6, 0xd4, 0x30,
+	0x01, 0x4d, 0x9a, 0x18,
+	0xfe, 0x59, 0xb2, 0x08,
+	0x01, 0x40, 0x20, 0x31,
+	0x00, 0x65, 0xe2, 0x58,
+	0x60, 0x0b, 0x40, 0x78,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x60, 0x0b, 0x00, 0x78,
+	0x40, 0x0b, 0x12, 0x69,
+	0x80, 0x0b, 0xcc, 0x78,
+	0x20, 0x6a, 0x16, 0x00,
+	0x20, 0x11, 0x54, 0x68,
+	0x20, 0x6a, 0x18, 0x00,
+	0x20, 0x11, 0x22, 0x00,
+	0xa4, 0x6a, 0x06, 0x00,
+	0x08, 0x3c, 0x78, 0x00,
+	0x01, 0x50, 0xc8, 0x30,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0xc4, 0x5d,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0xc4, 0x5d,
+	0x01, 0x6a, 0x26, 0x01,
+	0xf0, 0x19, 0x7a, 0x08,
+	0x0f, 0x18, 0xc8, 0x08,
+	0x0f, 0x0f, 0xc8, 0x08,
+	0x0f, 0x05, 0xc8, 0x08,
+	0x00, 0x3d, 0x7a, 0x00,
+	0x08, 0x1f, 0x74, 0x78,
+	0x80, 0x3d, 0x7a, 0x00,
+	0x01, 0x3d, 0xd8, 0x31,
+	0x01, 0x3d, 0x32, 0x31,
+	0x10, 0x03, 0x56, 0x79,
+	0x00, 0x65, 0x0a, 0x59,
+	0x80, 0x66, 0xa8, 0x78,
+	0x01, 0x66, 0xd8, 0x31,
+	0x01, 0x66, 0x32, 0x31,
+	0x40, 0x66, 0x86, 0x68,
+	0x01, 0x3c, 0x78, 0x00,
+	0x10, 0x03, 0xb0, 0x78,
+	0x00, 0x65, 0x0a, 0x59,
+	0xe0, 0x66, 0xc8, 0x18,
+	0x00, 0x65, 0xb0, 0x50,
+	0xdd, 0x66, 0xc8, 0x18,
+	0x00, 0x65, 0xb0, 0x48,
+	0x01, 0x66, 0xd8, 0x31,
+	0x01, 0x66, 0x32, 0x31,
+	0x10, 0x03, 0x56, 0x79,
+	0x00, 0x65, 0x0a, 0x59,
+	0x01, 0x66, 0xd8, 0x31,
+	0x01, 0x66, 0x32, 0x31,
+	0x01, 0x66, 0xb0, 0x30,
+	0x40, 0x3c, 0x78, 0x00,
+	0x10, 0x03, 0xa6, 0x78,
+	0x00, 0x65, 0x0a, 0x59,
+	0x00, 0x65, 0xb0, 0x40,
+	0x61, 0x6a, 0x96, 0x5e,
+	0x08, 0x51, 0x2e, 0x71,
+	0x02, 0x0b, 0xac, 0x78,
+	0x00, 0x65, 0xa8, 0x40,
+	0x80, 0x86, 0xc8, 0x08,
+	0x01, 0x4f, 0xc8, 0x30,
+	0x00, 0x50, 0xc2, 0x60,
+	0xc4, 0x6a, 0x32, 0x5d,
+	0x40, 0x3c, 0xbe, 0x78,
+	0x28, 0x6a, 0x48, 0x5d,
+	0x00, 0x65, 0x54, 0x41,
+	0x08, 0x6a, 0x48, 0x5d,
+	0x00, 0x65, 0x54, 0x41,
+	0xff, 0x6a, 0xd8, 0x01,
+	0xff, 0x6a, 0x32, 0x01,
+	0x90, 0x3c, 0x78, 0x00,
+	0x10, 0x03, 0x4a, 0x69,
+	0x00, 0x65, 0x2e, 0x41,
+	0x1a, 0x01, 0x02, 0x00,
+	0xf0, 0x19, 0x7a, 0x08,
+	0x0f, 0x0f, 0xc8, 0x08,
+	0x0f, 0x05, 0xc8, 0x08,
+	0x00, 0x3d, 0x7a, 0x00,
+	0x08, 0x1f, 0xda, 0x78,
+	0x80, 0x3d, 0x7a, 0x00,
+	0x20, 0x6a, 0x16, 0x00,
+	0x00, 0x65, 0xbe, 0x41,
+	0x00, 0x65, 0x76, 0x5e,
+	0x00, 0x65, 0x12, 0x40,
+	0x20, 0x11, 0xe8, 0x68,
+	0x20, 0x6a, 0x18, 0x00,
+	0x20, 0x11, 0x22, 0x00,
+	0xf7, 0x1f, 0xca, 0x08,
+	0x80, 0xb9, 0xee, 0x78,
+	0x08, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0x3e, 0x30,
+	0x01, 0xb9, 0x1e, 0x30,
+	0x7f, 0xb9, 0x0a, 0x08,
+	0x01, 0xb9, 0x0a, 0x30,
+	0x01, 0x56, 0xca, 0x30,
+	0x80, 0xb8, 0xfc, 0x78,
+	0x80, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0x00, 0x34,
+	0x01, 0x56, 0x00, 0x34,
+	0x1a, 0x01, 0x02, 0x00,
+	0x08, 0xb8, 0x06, 0x79,
+	0x20, 0x01, 0x02, 0x00,
+	0x02, 0xbd, 0x08, 0x34,
+	0x01, 0xbd, 0x08, 0x34,
+	0x08, 0x01, 0x02, 0x00,
+	0x02, 0x0b, 0x0c, 0x79,
+	0xf7, 0x01, 0x02, 0x08,
+	0x01, 0x06, 0xcc, 0x34,
+	0xb2, 0x00, 0x00, 0x08,
+	0x40, 0x6a, 0x16, 0x00,
+	0x01, 0x40, 0x20, 0x31,
+	0x01, 0xbf, 0x80, 0x30,
+	0x01, 0xb9, 0x7a, 0x30,
+	0x01, 0xba, 0x7c, 0x30,
+	0x00, 0x65, 0x00, 0x59,
+	0x80, 0x0b, 0xba, 0x79,
+	0xe4, 0x6a, 0x32, 0x5d,
+	0x80, 0xba, 0x48, 0x5d,
+	0x20, 0xb8, 0x2c, 0x79,
+	0x20, 0x6a, 0x48, 0x5d,
+	0x00, 0xa3, 0x48, 0x5d,
+	0x01, 0xa0, 0x78, 0x30,
+	0x10, 0x03, 0x46, 0x69,
+	0x08, 0x3c, 0x62, 0x69,
+	0x04, 0x3c, 0x88, 0x69,
+	0x02, 0x3c, 0x8e, 0x69,
+	0x01, 0x3c, 0x4c, 0x79,
+	0x00, 0x6a, 0x7e, 0x5e,
+	0x01, 0x6a, 0xa2, 0x30,
+	0x00, 0x65, 0x9a, 0x59,
+	0x04, 0x51, 0x3e, 0x61,
+	0x0d, 0x6a, 0x76, 0x00,
+	0x00, 0xbb, 0xda, 0x5d,
+	0x00, 0x65, 0x2c, 0x41,
+	0xa4, 0x6a, 0x06, 0x00,
+	0x00, 0x65, 0x0a, 0x59,
+	0x00, 0x65, 0xa8, 0x40,
+	0xe4, 0x6a, 0x32, 0x5d,
+	0x20, 0x3c, 0x52, 0x79,
+	0x02, 0x6a, 0x48, 0x5d,
+	0x04, 0x6a, 0x48, 0x5d,
+	0x01, 0x03, 0x54, 0x69,
+	0xf7, 0x11, 0x22, 0x08,
+	0xff, 0x6a, 0x24, 0x08,
+	0xff, 0x6a, 0x06, 0x08,
+	0x01, 0x6a, 0x7e, 0x00,
+	0x00, 0x65, 0x9a, 0x59,
+	0x00, 0x65, 0x04, 0x40,
+	0x84, 0x6a, 0x32, 0x5d,
+	0x00, 0x65, 0x0a, 0x59,
+	0x01, 0x66, 0xc8, 0x30,
+	0x01, 0x64, 0xd8, 0x31,
+	0x01, 0x64, 0x32, 0x31,
+	0x5b, 0x64, 0xc8, 0x28,
+	0x30, 0x64, 0xca, 0x18,
+	0x01, 0x6c, 0xc8, 0x30,
+	0xff, 0x64, 0x84, 0x79,
+	0x08, 0x01, 0x02, 0x00,
+	0x02, 0x0b, 0x76, 0x79,
+	0x01, 0x64, 0x7c, 0x61,
+	0xf7, 0x01, 0x02, 0x08,
+	0x01, 0x06, 0xd8, 0x31,
+	0x01, 0x06, 0x32, 0x31,
+	0xff, 0x64, 0xc8, 0x18,
+	0xff, 0x64, 0x76, 0x69,
+	0xf7, 0x3c, 0x78, 0x08,
+	0x00, 0x65, 0x2e, 0x41,
+	0x40, 0xa1, 0x7e, 0x10,
+	0x04, 0xa1, 0x32, 0x5d,
+	0x00, 0x65, 0x62, 0x42,
+	0xc4, 0x6a, 0x32, 0x5d,
+	0xc0, 0x6a, 0x7e, 0x00,
+	0x00, 0xa2, 0x48, 0x5d,
+	0xe4, 0x6a, 0x06, 0x00,
+	0x00, 0x6a, 0x48, 0x5d,
+	0x00, 0x65, 0x54, 0x41,
+	0x10, 0x3c, 0x9e, 0x69,
+	0x00, 0xbb, 0x64, 0x44,
+	0x18, 0x6a, 0xda, 0x01,
+	0x01, 0x69, 0xd8, 0x31,
+	0x1c, 0x6a, 0xd0, 0x01,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xa6, 0x79,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x01, 0x93, 0x26, 0x01,
+	0x03, 0x6a, 0x2a, 0x01,
+	0x01, 0x69, 0x32, 0x31,
+	0x1c, 0x6a, 0xa8, 0x5d,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x6c, 0x5e,
+	0x01, 0x50, 0xa0, 0x18,
+	0x02, 0x6a, 0x22, 0x05,
+	0x80, 0x6a, 0x74, 0x00,
+	0x80, 0x3c, 0x78, 0x00,
+	0x00, 0x65, 0xa0, 0x5d,
+	0x01, 0x3f, 0xc8, 0x30,
+	0xbf, 0x64, 0x62, 0x7a,
+	0x80, 0x64, 0x82, 0x73,
+	0xa0, 0x64, 0xd8, 0x73,
+	0xc0, 0x64, 0xd0, 0x73,
+	0xe0, 0x64, 0x18, 0x74,
+	0x01, 0x6a, 0x96, 0x5e,
+	0x00, 0x65, 0xbe, 0x41,
+	0xf7, 0x11, 0x22, 0x08,
+	0x01, 0x06, 0xd4, 0x30,
+	0xff, 0x6a, 0x24, 0x08,
+	0xf7, 0x01, 0x02, 0x08,
+	0x09, 0x0c, 0xd8, 0x79,
+	0x08, 0x0c, 0x04, 0x68,
+	0xb1, 0x6a, 0x96, 0x5e,
+	0xff, 0x6a, 0x26, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0x02, 0x6a, 0x08, 0x30,
+	0xff, 0x6a, 0x08, 0x08,
+	0xdf, 0x01, 0x02, 0x08,
+	0x01, 0x6a, 0x7e, 0x00,
+	0xff, 0x6a, 0x78, 0x0c,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x08, 0xa4, 0x48, 0x19,
+	0x00, 0xa5, 0x4a, 0x21,
+	0x00, 0xa6, 0x4c, 0x21,
+	0x00, 0xa7, 0x4e, 0x25,
+	0x08, 0xeb, 0x9a, 0x7e,
+	0x80, 0xeb, 0xf8, 0x79,
+	0xff, 0x6a, 0xd6, 0x09,
+	0x08, 0xeb, 0xfc, 0x69,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x88, 0xeb, 0x12, 0x72,
+	0x08, 0xeb, 0x9a, 0x6e,
+	0x80, 0xa3, 0x9a, 0x6e,
+	0x04, 0xea, 0x16, 0xe2,
+	0x08, 0xee, 0x9a, 0x6e,
+	0x04, 0x6a, 0xd0, 0x81,
+	0x05, 0xa4, 0xc0, 0x89,
+	0x03, 0xa5, 0xc2, 0x31,
+	0x09, 0x6a, 0xd6, 0x05,
+	0x00, 0x65, 0xfa, 0x59,
+	0x06, 0xa4, 0xd4, 0x89,
+	0x80, 0x94, 0x9a, 0x7e,
+	0x04, 0xe9, 0x10, 0x31,
+	0x01, 0xe9, 0xca, 0x30,
+	0x01, 0x65, 0x20, 0x7a,
+	0x01, 0x57, 0xae, 0x10,
+	0x01, 0x65, 0x18, 0x31,
+	0x02, 0xe9, 0x1a, 0x31,
+	0x01, 0xe9, 0x46, 0x31,
+	0x00, 0x65, 0xec, 0x59,
+	0x01, 0xa4, 0xca, 0x30,
+	0x01, 0x57, 0x2e, 0x7a,
+	0x04, 0x65, 0xca, 0x00,
+	0x80, 0xa3, 0x32, 0x7a,
+	0x02, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0xf8, 0x31,
+	0x01, 0x3b, 0x26, 0x31,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x01, 0x8c, 0xc8, 0x30,
+	0x00, 0x88, 0xc8, 0x18,
+	0x02, 0x64, 0xc8, 0x88,
+	0xff, 0x64, 0x9a, 0x7e,
+	0xff, 0x8d, 0x48, 0x6a,
+	0xff, 0x8e, 0x48, 0x6a,
+	0x03, 0x8c, 0xd4, 0x98,
+	0x00, 0x65, 0x9a, 0x56,
+	0x01, 0x64, 0x70, 0x30,
+	0xff, 0x64, 0xc8, 0x10,
+	0x01, 0x64, 0xc8, 0x18,
+	0x00, 0x8c, 0x18, 0x19,
+	0xff, 0x8d, 0x1a, 0x21,
+	0xff, 0x8e, 0x1c, 0x25,
+	0x04, 0x14, 0x10, 0x31,
+	0x03, 0xa0, 0x18, 0x31,
+	0x03, 0xa0, 0x10, 0x30,
+	0x08, 0x6a, 0xcc, 0x00,
+	0xa0, 0x6a, 0xbe, 0x5d,
+	0x01, 0xa0, 0xae, 0x08,
+	0x00, 0x65, 0x88, 0x42,
+	0xa8, 0x6a, 0x76, 0x00,
+	0x79, 0x6a, 0x76, 0x00,
+	0x40, 0x3f, 0x6a, 0x6a,
+	0x04, 0x3b, 0x76, 0x00,
+	0x00, 0x65, 0x52, 0x5d,
+	0x04, 0x6a, 0xd4, 0x81,
+	0x20, 0x3c, 0x54, 0x6a,
+	0x20, 0x3c, 0x78, 0x00,
+	0x07, 0xac, 0x10, 0x31,
+	0x05, 0xb3, 0x46, 0x31,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xac, 0x6a, 0xb6, 0x5d,
+	0xa3, 0x6a, 0xcc, 0x00,
+	0xb3, 0x6a, 0xba, 0x5d,
+	0x00, 0x65, 0x38, 0x5a,
+	0xfd, 0xa4, 0x48, 0x09,
+	0x01, 0x8c, 0xae, 0x08,
+	0x03, 0x8c, 0x10, 0x30,
+	0x00, 0x65, 0xae, 0x5d,
+	0x01, 0xa4, 0x98, 0x7a,
+	0x04, 0x3b, 0x76, 0x08,
+	0x01, 0x3b, 0x26, 0x31,
+	0x80, 0x02, 0x04, 0x00,
+	0x10, 0x0c, 0x90, 0x7a,
+	0x7f, 0x02, 0x04, 0x08,
+	0x91, 0x6a, 0x96, 0x5e,
+	0x00, 0x65, 0xbe, 0x41,
+	0x01, 0xa4, 0xca, 0x30,
+	0x80, 0xa3, 0x9e, 0x7a,
+	0x02, 0x65, 0xca, 0x00,
+	0x01, 0x57, 0xa2, 0x7a,
+	0x04, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0xf8, 0x31,
+	0x01, 0x3b, 0x26, 0x31,
+	0x00, 0x65, 0x00, 0x5a,
+	0x01, 0xfc, 0xae, 0x6a,
+	0x80, 0x0b, 0xa6, 0x6a,
+	0x10, 0x0c, 0xa6, 0x7a,
+	0x04, 0x93, 0xc0, 0x6a,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0xb2, 0x6a,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0xb4, 0x7a,
+	0x01, 0x94, 0xb4, 0x7a,
+	0x01, 0x94, 0xb4, 0x7a,
+	0x01, 0x94, 0xb4, 0x7a,
+	0x01, 0x94, 0xb4, 0x7a,
+	0x10, 0x94, 0xc0, 0x6a,
+	0xd7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0xc4, 0x6a,
+	0x02, 0xfc, 0xce, 0x7a,
+	0x01, 0xfc, 0x4e, 0x7b,
+	0x01, 0xa4, 0x48, 0x01,
+	0x00, 0x65, 0x4e, 0x43,
+	0x40, 0x0d, 0xd4, 0x6a,
+	0x00, 0x65, 0x00, 0x5a,
+	0x00, 0x65, 0xc6, 0x42,
+	0x80, 0xfc, 0xde, 0x7a,
+	0x80, 0xa4, 0xde, 0x6a,
+	0xff, 0xa5, 0x4a, 0x19,
+	0xff, 0xa6, 0x4c, 0x21,
+	0xff, 0xa7, 0x4e, 0x21,
+	0xf8, 0xfc, 0x48, 0x09,
+	0xff, 0x6a, 0xae, 0x08,
+	0x04, 0xfc, 0xe6, 0x7a,
+	0x01, 0x57, 0xae, 0x00,
+	0xff, 0x6a, 0x46, 0x09,
+	0xff, 0x38, 0xf2, 0x6a,
+	0x80, 0xa3, 0xf2, 0x7a,
+	0x80, 0x0b, 0xf0, 0x7a,
+	0x04, 0x3b, 0xf2, 0x7a,
+	0xbf, 0x3b, 0x76, 0x08,
+	0x01, 0x3b, 0x26, 0x31,
+	0x00, 0x65, 0x00, 0x5a,
+	0x01, 0x0b, 0x00, 0x6b,
+	0x10, 0x0c, 0xf4, 0x7a,
+	0x04, 0x93, 0xfe, 0x6a,
+	0x01, 0x94, 0xfc, 0x7a,
+	0x10, 0x94, 0xfe, 0x6a,
+	0xc7, 0x93, 0x26, 0x09,
+	0x01, 0x99, 0xd4, 0x30,
+	0x38, 0x93, 0x02, 0x6b,
+	0xff, 0x08, 0x4e, 0x6b,
+	0xff, 0x09, 0x4e, 0x6b,
+	0xff, 0x0a, 0x4e, 0x6b,
+	0xff, 0x38, 0x1e, 0x7b,
+	0x04, 0x14, 0x10, 0x31,
+	0x01, 0x38, 0x18, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xbc, 0x5d,
+	0x00, 0x38, 0xa8, 0x5d,
+	0xff, 0x6a, 0x70, 0x08,
+	0x00, 0x65, 0x44, 0x43,
+	0x80, 0xa3, 0x24, 0x7b,
+	0x01, 0xa4, 0x48, 0x01,
+	0x00, 0x65, 0x4e, 0x43,
+	0x08, 0xeb, 0x2a, 0x7b,
+	0x00, 0x65, 0x00, 0x5a,
+	0x08, 0xeb, 0x26, 0x6b,
+	0x07, 0xe9, 0x10, 0x31,
+	0x80, 0xe9, 0x30, 0x7b,
+	0x80, 0xa3, 0x46, 0x01,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xa4, 0x6a, 0xbc, 0x5d,
+	0x08, 0x6a, 0xa8, 0x5d,
+	0x0d, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x6c, 0x5e,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x00, 0x65, 0x4e, 0x5e,
+	0x01, 0x99, 0x46, 0x31,
+	0x00, 0x65, 0x38, 0x5a,
+	0x00, 0x65, 0xec, 0x59,
+	0x03, 0x8c, 0x10, 0x30,
+	0x00, 0x65, 0xae, 0x5d,
+	0x01, 0x8c, 0x4c, 0x7b,
+	0x01, 0x57, 0xae, 0x10,
+	0x80, 0x0b, 0x88, 0x6a,
+	0x80, 0x0b, 0x54, 0x6b,
+	0x01, 0x0c, 0x50, 0x7b,
+	0x10, 0x0c, 0x88, 0x7a,
+	0x00, 0x65, 0xf6, 0x59,
+	0xff, 0x38, 0x66, 0x7b,
+	0x01, 0x38, 0xc8, 0x30,
+	0x00, 0x08, 0x40, 0x19,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x09, 0x42, 0x21,
+	0x00, 0x0a, 0x44, 0x21,
+	0xff, 0x6a, 0x70, 0x08,
+	0x00, 0x65, 0x68, 0x43,
+	0x03, 0x08, 0x40, 0x31,
+	0x03, 0x08, 0x40, 0x31,
+	0x01, 0x08, 0x40, 0x31,
+	0x01, 0x09, 0x42, 0x31,
+	0x01, 0x0a, 0x44, 0x31,
+	0xfd, 0xb4, 0x68, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0x12, 0x01, 0x02, 0x00,
+	0x04, 0x3c, 0xbe, 0x79,
+	0xfb, 0x3c, 0x78, 0x08,
+	0x04, 0x93, 0x2e, 0x79,
+	0x01, 0x0c, 0x7c, 0x6b,
+	0x00, 0x65, 0x2e, 0x41,
+	0x00, 0x65, 0xbe, 0x41,
+	0x00, 0x65, 0x52, 0x5d,
+	0x01, 0xbc, 0x18, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x02, 0x6a, 0xf8, 0x01,
+	0x01, 0xbc, 0x10, 0x30,
+	0x02, 0x6a, 0x12, 0x30,
+	0x01, 0xbc, 0x10, 0x30,
+	0xff, 0x6a, 0x12, 0x08,
+	0xff, 0x6a, 0x14, 0x08,
+	0xf3, 0xbc, 0xd4, 0x18,
+	0xa0, 0x6a, 0xaa, 0x53,
+	0x04, 0xa0, 0x10, 0x31,
+	0xac, 0x6a, 0x26, 0x01,
+	0x04, 0xa0, 0x10, 0x31,
+	0x03, 0x08, 0x18, 0x31,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xa0, 0x6a, 0xbc, 0x5d,
+	0x00, 0xbc, 0xa8, 0x5d,
+	0x3d, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0xc2, 0x43,
+	0xff, 0x6a, 0x10, 0x09,
+	0xa4, 0x6a, 0x26, 0x01,
+	0x0c, 0xa0, 0x32, 0x31,
+	0x05, 0x6a, 0x26, 0x01,
+	0x35, 0x6a, 0x26, 0x01,
+	0x0c, 0xa0, 0x32, 0x31,
+	0x36, 0x6a, 0x26, 0x01,
+	0x02, 0x93, 0x26, 0x01,
+	0x35, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0x60, 0x5e,
+	0x00, 0x65, 0x60, 0x5e,
+	0x02, 0x93, 0x26, 0x01,
+	0x04, 0x0b, 0xc6, 0x6b,
+	0x10, 0x0c, 0xc2, 0x7b,
+	0x01, 0x03, 0xc6, 0x6b,
+	0xc7, 0x93, 0x26, 0x09,
+	0x38, 0x93, 0xca, 0x6b,
+	0x10, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0xbe, 0x41,
+	0x00, 0x65, 0x52, 0x5d,
+	0x01, 0x06, 0x50, 0x31,
+	0x00, 0x65, 0xbe, 0x41,
+	0x10, 0x3f, 0x06, 0x00,
+	0x01, 0x3a, 0xca, 0x30,
+	0x80, 0x65, 0x04, 0x64,
+	0x10, 0xb8, 0x28, 0x6c,
+	0x01, 0xb9, 0xdc, 0x30,
+	0x01, 0x6e, 0xc8, 0x30,
+	0x01, 0x54, 0xca, 0x30,
+	0x80, 0xb9, 0xe8, 0x7b,
+	0x01, 0x55, 0xca, 0x30,
+	0x80, 0xb9, 0xec, 0x7b,
+	0x01, 0x55, 0xca, 0x30,
+	0x00, 0x65, 0x28, 0x6c,
+	0xc0, 0xba, 0xca, 0x00,
+	0x40, 0xb8, 0xf4, 0x6b,
+	0xbf, 0x65, 0xca, 0x08,
+	0x20, 0xb8, 0x08, 0x7c,
+	0x01, 0x65, 0x0c, 0x30,
+	0x00, 0x65, 0xa0, 0x5d,
+	0xa0, 0x3f, 0x10, 0x64,
+	0x23, 0xb8, 0x0c, 0x08,
+	0x00, 0x65, 0xa0, 0x5d,
+	0xa0, 0x3f, 0x10, 0x64,
+	0x00, 0xbb, 0x08, 0x44,
+	0xff, 0x65, 0x08, 0x64,
+	0x00, 0x65, 0x28, 0x44,
+	0x40, 0x6a, 0x18, 0x00,
+	0x01, 0x65, 0x0c, 0x30,
+	0x00, 0x65, 0xa0, 0x5d,
+	0xa0, 0x3f, 0xd6, 0x73,
+	0x40, 0x6a, 0x18, 0x00,
+	0x01, 0x3a, 0xa6, 0x30,
+	0x08, 0x6a, 0x74, 0x00,
+	0x00, 0x65, 0xbe, 0x41,
+	0x64, 0x6a, 0x2c, 0x5d,
+	0x80, 0x64, 0x9e, 0x6c,
+	0x04, 0x64, 0x74, 0x74,
+	0x02, 0x64, 0x82, 0x74,
+	0x00, 0x6a, 0x44, 0x74,
+	0x03, 0x64, 0x90, 0x74,
+	0x23, 0x64, 0x30, 0x74,
+	0x08, 0x64, 0x40, 0x74,
+	0x61, 0x6a, 0x96, 0x5e,
+	0x00, 0x65, 0xa0, 0x5d,
+	0x08, 0x51, 0xc0, 0x71,
+	0x00, 0x65, 0x28, 0x44,
+	0x80, 0x04, 0x3e, 0x7c,
+	0x51, 0x6a, 0x22, 0x5d,
+	0x01, 0x51, 0x3e, 0x64,
+	0x01, 0xa4, 0x3a, 0x7c,
+	0x01, 0x57, 0x40, 0x7c,
+	0x41, 0x6a, 0x96, 0x5e,
+	0x00, 0x65, 0x40, 0x44,
+	0x07, 0x6a, 0x1a, 0x5d,
+	0x01, 0x06, 0xd4, 0x30,
+	0x00, 0x65, 0xbe, 0x41,
+	0x10, 0xb8, 0x48, 0x7c,
+	0xa1, 0x6a, 0x96, 0x5e,
+	0x01, 0xb4, 0x4e, 0x6c,
+	0x02, 0xb4, 0x50, 0x6c,
+	0x01, 0xa4, 0x50, 0x7c,
+	0xff, 0xa8, 0x60, 0x7c,
+	0x04, 0xb4, 0x68, 0x01,
+	0x01, 0x6a, 0x76, 0x00,
+	0x00, 0xbb, 0xda, 0x5d,
+	0xff, 0xa8, 0x60, 0x7c,
+	0x71, 0x6a, 0x96, 0x5e,
+	0x40, 0x51, 0x60, 0x64,
+	0x00, 0x65, 0x76, 0x5e,
+	0x00, 0x65, 0xd0, 0x41,
+	0x00, 0xbb, 0x64, 0x5c,
+	0x00, 0x65, 0xd0, 0x41,
+	0x00, 0x65, 0x76, 0x5e,
+	0x01, 0x65, 0xa2, 0x30,
+	0x01, 0xf8, 0xc8, 0x30,
+	0x01, 0x4e, 0xc8, 0x30,
+	0x00, 0x6a, 0x7e, 0xdd,
+	0x00, 0x51, 0x90, 0x5d,
+	0x01, 0x4e, 0x9c, 0x18,
+	0x02, 0x6a, 0x22, 0x05,
+	0x04, 0xb8, 0x70, 0x01,
+	0x00, 0x65, 0x92, 0x5e,
+	0x20, 0xb8, 0xd0, 0x69,
+	0x01, 0xbb, 0xa2, 0x30,
+	0x01, 0xba, 0x7c, 0x30,
+	0x00, 0xb9, 0x94, 0x5c,
+	0x00, 0x65, 0xd0, 0x41,
+	0x20, 0x3c, 0x40, 0x7c,
+	0x04, 0x14, 0x58, 0x31,
+	0x08, 0xa0, 0x60, 0x31,
+	0xac, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xbc, 0x5d,
+	0xa0, 0x6a, 0xb4, 0x5d,
+	0x00, 0x65, 0x40, 0x44,
+	0xdf, 0x3c, 0x78, 0x08,
+	0x00, 0x65, 0x40, 0x44,
+	0x4c, 0x65, 0xcc, 0x28,
+	0x01, 0x3e, 0x20, 0x31,
+	0xd0, 0x66, 0xcc, 0x18,
+	0x20, 0x66, 0xcc, 0x18,
+	0x01, 0x51, 0xda, 0x34,
+	0x4c, 0x3d, 0xca, 0x28,
+	0x3f, 0x64, 0x7c, 0x08,
+	0xd0, 0x65, 0xca, 0x18,
+	0x01, 0x3e, 0x20, 0x31,
+	0x30, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xac, 0x4c,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x20, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xb4, 0x54,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x20, 0x65, 0xca, 0x18,
+	0xe0, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xbe, 0x4c,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xd0, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xc6, 0x54,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x01, 0x6c, 0xa2, 0x30,
+	0xff, 0x51, 0xd8, 0x74,
+	0x00, 0x51, 0x56, 0x5d,
+	0x01, 0x51, 0x20, 0x31,
+	0x00, 0x65, 0xfa, 0x44,
+	0x01, 0xba, 0xc8, 0x30,
+	0x00, 0x3e, 0xfa, 0x74,
+	0x00, 0x65, 0x74, 0x5e,
+	0x80, 0x3c, 0x78, 0x00,
+	0x01, 0x06, 0xd4, 0x30,
+	0x00, 0x65, 0xa0, 0x5d,
+	0x01, 0x3c, 0x78, 0x00,
+	0xe0, 0x3f, 0x16, 0x65,
+	0x02, 0x3c, 0x78, 0x00,
+	0x20, 0x12, 0x16, 0x65,
+	0x51, 0x6a, 0x22, 0x5d,
+	0x00, 0x51, 0x56, 0x5d,
+	0x51, 0x6a, 0x22, 0x5d,
+	0x01, 0x51, 0x20, 0x31,
+	0x04, 0x3c, 0x78, 0x00,
+	0x01, 0xb9, 0xc8, 0x30,
+	0x00, 0x3d, 0x14, 0x65,
+	0x08, 0x3c, 0x78, 0x00,
+	0x01, 0xba, 0xc8, 0x30,
+	0x00, 0x3e, 0x14, 0x65,
+	0x10, 0x3c, 0x78, 0x00,
+	0x04, 0xb8, 0x14, 0x7d,
+	0xfb, 0xb8, 0x70, 0x09,
+	0x20, 0xb8, 0x0a, 0x6d,
+	0x01, 0x90, 0xc8, 0x30,
+	0xff, 0x6a, 0xa2, 0x00,
+	0x00, 0x3d, 0x94, 0x5c,
+	0x01, 0x64, 0x20, 0x31,
+	0x80, 0x6a, 0x78, 0x00,
+	0x00, 0x65, 0x02, 0x59,
+	0x10, 0xb8, 0x40, 0x7c,
+	0xff, 0x6a, 0x1a, 0x5d,
+	0x00, 0x65, 0x40, 0x44,
+	0x00, 0x65, 0x74, 0x5e,
+	0x31, 0x6a, 0x96, 0x5e,
+	0x00, 0x65, 0x40, 0x44,
+	0x10, 0x3f, 0x06, 0x00,
+	0x01, 0x65, 0x74, 0x34,
+	0x81, 0x6a, 0x96, 0x5e,
+	0x00, 0x65, 0x24, 0x45,
+	0x01, 0x06, 0xd4, 0x30,
+	0x01, 0x0c, 0x24, 0x7d,
+	0x04, 0x0c, 0x1e, 0x6d,
+	0xe0, 0x03, 0x7e, 0x08,
+	0xe0, 0x3f, 0xbe, 0x61,
+	0x01, 0x65, 0xcc, 0x30,
+	0x01, 0x12, 0xda, 0x34,
+	0x01, 0x06, 0xd4, 0x34,
+	0x01, 0x03, 0x32, 0x6d,
+	0x40, 0x03, 0xcc, 0x08,
+	0x01, 0x65, 0x06, 0x30,
+	0x40, 0x65, 0xc8, 0x08,
+	0x00, 0x66, 0x40, 0x75,
+	0x40, 0x65, 0x40, 0x7d,
+	0x00, 0x65, 0x40, 0x5d,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x08, 0x01, 0x02, 0x00,
+	0x02, 0x0b, 0x4a, 0x7d,
+	0x01, 0x65, 0x0c, 0x30,
+	0x02, 0x0b, 0x4e, 0x7d,
+	0xf7, 0x01, 0x02, 0x0c,
+	0x80, 0x3c, 0x9a, 0x6e,
+	0x21, 0x6a, 0x96, 0x46,
+	0x01, 0x65, 0xc8, 0x30,
+	0xff, 0x41, 0x76, 0x75,
+	0x01, 0x41, 0x20, 0x31,
+	0xff, 0x6a, 0xa4, 0x00,
+	0x00, 0x65, 0x66, 0x45,
+	0xff, 0xbf, 0x76, 0x75,
+	0x01, 0x90, 0xa4, 0x30,
+	0x01, 0xbf, 0x20, 0x31,
+	0x00, 0xbb, 0x60, 0x65,
+	0xff, 0x52, 0x74, 0x75,
+	0x01, 0xbf, 0xcc, 0x30,
+	0x01, 0x90, 0xca, 0x30,
+	0x01, 0x52, 0x20, 0x31,
+	0x01, 0x66, 0x7e, 0x31,
+	0x01, 0x65, 0x20, 0x35,
+	0x01, 0xbf, 0x82, 0x34,
+	0x01, 0x64, 0xa2, 0x30,
+	0x00, 0x6a, 0x7e, 0x5e,
+	0x0d, 0x6a, 0x76, 0x00,
+	0x00, 0x51, 0xda, 0x45,
+	0x01, 0x65, 0xa4, 0x30,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0xce, 0x5d,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x05,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0xce, 0x5d,
+	0x01, 0x6a, 0xa8, 0x5d,
+	0x01, 0x6a, 0x26, 0x05,
+	0x01, 0x65, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0x94, 0x7d,
+	0xff, 0x6a, 0xdc, 0x0d,
+	0x01, 0x65, 0x32, 0x31,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x6c, 0x46,
+	0x81, 0x6a, 0x96, 0x5e,
+	0x01, 0x0c, 0xa0, 0x7d,
+	0x04, 0x0c, 0x9e, 0x6d,
+	0xe0, 0x03, 0x06, 0x08,
+	0xe0, 0x03, 0x7e, 0x0c,
+	0x01, 0x65, 0x18, 0x31,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x0d,
+	0x01, 0x8c, 0x10, 0x30,
+	0x01, 0x8d, 0x12, 0x30,
+	0x01, 0x8e, 0x14, 0x34,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x34,
+	0x3d, 0x64, 0xa4, 0x28,
+	0x55, 0x64, 0xc8, 0x28,
+	0x00, 0x65, 0xce, 0x45,
+	0x2e, 0x64, 0xa4, 0x28,
+	0x66, 0x64, 0xc8, 0x28,
+	0x00, 0x6c, 0xda, 0x18,
+	0x01, 0x52, 0xc8, 0x30,
+	0x00, 0x6c, 0xda, 0x20,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0x00, 0x6c, 0xda, 0x24,
+	0x01, 0x65, 0xc8, 0x30,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x44, 0x6a, 0xca, 0x5d,
+	0x01, 0x90, 0xe2, 0x31,
+	0x04, 0x3b, 0xee, 0x7d,
+	0x30, 0x6a, 0xd0, 0x01,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x1d, 0x6a, 0xdc, 0x01,
+	0xdc, 0xee, 0xea, 0x65,
+	0x00, 0x65, 0x06, 0x46,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x20, 0xa0, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xf6, 0x7d,
+	0x11, 0x6a, 0xdc, 0x01,
+	0x50, 0xee, 0xfa, 0x65,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xdc, 0x01,
+	0x88, 0xee, 0x00, 0x66,
+	0x19, 0x6a, 0xdc, 0x01,
+	0xd8, 0xee, 0x04, 0x66,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x18, 0xee, 0x08, 0x6e,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x44, 0x6a, 0xca, 0x5d,
+	0x20, 0x6a, 0xa8, 0x5d,
+	0x01, 0x3b, 0x26, 0x31,
+	0x04, 0x3b, 0x22, 0x6e,
+	0xa0, 0x6a, 0xca, 0x00,
+	0x20, 0x65, 0xc8, 0x18,
+	0x00, 0x65, 0x5c, 0x5e,
+	0x00, 0x65, 0x1a, 0x66,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x6c, 0x46,
+	0xa0, 0x6a, 0xcc, 0x00,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x01, 0x94, 0x26, 0x6e,
+	0x10, 0x94, 0x28, 0x6e,
+	0x08, 0x94, 0x3e, 0x6e,
+	0x08, 0x94, 0x3e, 0x6e,
+	0x08, 0x94, 0x3e, 0x6e,
+	0x07, 0x8c, 0xca, 0x18,
+	0x3d, 0x65, 0xca, 0x28,
+	0x00, 0x65, 0xc8, 0x18,
+	0x00, 0x65, 0x42, 0x5e,
+	0xff, 0x65, 0xca, 0x10,
+	0x05, 0x65, 0xc8, 0x18,
+	0x00, 0x65, 0x26, 0x46,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x40, 0x6e,
+	0x00, 0x62, 0xc4, 0x18,
+	0x00, 0x65, 0x6c, 0x5e,
+	0x00, 0x65, 0x4c, 0x5e,
+	0x00, 0x65, 0x4c, 0x5e,
+	0x00, 0x65, 0x4c, 0x5e,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x34,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x35,
+	0x08, 0x94, 0x6c, 0x7e,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x70, 0x6e,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x04, 0xb8, 0x92, 0x6e,
+	0x01, 0x42, 0x7e, 0x31,
+	0xff, 0x6a, 0x76, 0x01,
+	0x01, 0x90, 0x84, 0x34,
+	0xff, 0x6a, 0x76, 0x05,
+	0xff, 0x42, 0x8e, 0x66,
+	0xff, 0x41, 0x86, 0x66,
+	0xd1, 0x6a, 0x96, 0x5e,
+	0xff, 0x6a, 0xca, 0x04,
+	0x01, 0x41, 0x20, 0x31,
+	0x01, 0xbf, 0x82, 0x30,
+	0x01, 0x6a, 0x76, 0x00,
+	0x00, 0xbb, 0xda, 0x45,
+	0x01, 0x42, 0x20, 0x31,
+	0x01, 0xbf, 0x84, 0x34,
+	0x01, 0x41, 0x7e, 0x31,
+	0x01, 0x90, 0x82, 0x34,
+	0x01, 0x65, 0x22, 0x31,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x0c
+};
+
+static int ahc_patch22_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch22_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0);
+}
+
+static int ahc_patch21_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch21_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_CMD_CHAN) == 0);
+}
+
+static int ahc_patch20_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch20_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_QUEUE_REGS) == 0);
+}
+
+static int ahc_patch19_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch19_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_WIDE) != 0);
+}
+
+static int ahc_patch18_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch18_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_SCB_BTT) != 0);
+}
+
+static int ahc_patch17_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch17_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0);
+}
+
+static int ahc_patch16_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch16_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0);
+}
+
+static int ahc_patch15_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch15_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0);
+}
+
+static int ahc_patch14_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch14_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_DT) == 0);
+}
+
+static int ahc_patch13_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch13_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_ULTRA2) == 0);
+}
+
+static int ahc_patch12_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch12_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0);
+}
+
+static int ahc_patch11_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch11_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_ULTRA) != 0);
+}
+
+static int ahc_patch10_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch10_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_HS_MAILBOX) != 0);
+}
+
+static int ahc_patch9_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch9_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_MULTI_TID) != 0);
+}
+
+static int ahc_patch8_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch8_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_CMD_CHAN) != 0);
+}
+
+static int ahc_patch7_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch7_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_INITIATORROLE) != 0);
+}
+
+static int ahc_patch6_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch6_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_TARGETROLE) != 0);
+}
+
+static int ahc_patch5_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch5_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0);
+}
+
+static int ahc_patch4_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch4_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_PAGESCBS) != 0);
+}
+
+static int ahc_patch3_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch3_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_QUEUE_REGS) != 0);
+}
+
+static int ahc_patch2_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch2_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_TWIN) != 0);
+}
+
+static int ahc_patch1_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch1_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_ULTRA2) != 0);
+}
+
+static int ahc_patch0_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch0_func(struct ahc_softc *ahc)
+{
+	return (0);
+}
+
+typedef int patch_func_t (struct ahc_softc *);
+struct patch {
+	patch_func_t	*patch_func;
+	uint32_t	begin	   :10,
+			skip_instr :10,
+			skip_patch :12;
+} patches[] = {
+	{ ahc_patch1_func, 4, 1, 1 },
+	{ ahc_patch2_func, 6, 2, 1 },
+	{ ahc_patch2_func, 9, 1, 1 },
+	{ ahc_patch3_func, 11, 1, 2 },
+	{ ahc_patch0_func, 12, 2, 1 },
+	{ ahc_patch4_func, 15, 1, 2 },
+	{ ahc_patch0_func, 16, 1, 1 },
+	{ ahc_patch5_func, 22, 2, 1 },
+	{ ahc_patch3_func, 27, 1, 2 },
+	{ ahc_patch0_func, 28, 1, 1 },
+	{ ahc_patch6_func, 37, 65, 21 },
+	{ ahc_patch7_func, 37, 1, 1 },
+	{ ahc_patch8_func, 45, 3, 2 },
+	{ ahc_patch0_func, 48, 3, 1 },
+	{ ahc_patch9_func, 52, 1, 2 },
+	{ ahc_patch0_func, 53, 2, 3 },
+	{ ahc_patch1_func, 53, 1, 2 },
+	{ ahc_patch0_func, 54, 1, 1 },
+	{ ahc_patch2_func, 56, 2, 1 },
+	{ ahc_patch8_func, 58, 1, 2 },
+	{ ahc_patch0_func, 59, 1, 1 },
+	{ ahc_patch8_func, 63, 1, 2 },
+	{ ahc_patch0_func, 64, 1, 1 },
+	{ ahc_patch8_func, 73, 1, 2 },
+	{ ahc_patch0_func, 74, 1, 1 },
+	{ ahc_patch8_func, 77, 1, 2 },
+	{ ahc_patch0_func, 78, 1, 1 },
+	{ ahc_patch10_func, 88, 1, 2 },
+	{ ahc_patch0_func, 89, 1, 1 },
+	{ ahc_patch8_func, 97, 1, 2 },
+	{ ahc_patch0_func, 98, 1, 1 },
+	{ ahc_patch7_func, 102, 9, 4 },
+	{ ahc_patch1_func, 104, 1, 2 },
+	{ ahc_patch0_func, 105, 1, 1 },
+	{ ahc_patch2_func, 107, 2, 1 },
+	{ ahc_patch2_func, 116, 4, 1 },
+	{ ahc_patch1_func, 120, 1, 2 },
+	{ ahc_patch0_func, 121, 2, 3 },
+	{ ahc_patch2_func, 121, 1, 2 },
+	{ ahc_patch0_func, 122, 1, 1 },
+	{ ahc_patch6_func, 123, 4, 2 },
+	{ ahc_patch0_func, 127, 1, 1 },
+	{ ahc_patch11_func, 129, 2, 1 },
+	{ ahc_patch1_func, 131, 1, 2 },
+	{ ahc_patch0_func, 132, 1, 1 },
+	{ ahc_patch6_func, 133, 4, 1 },
+	{ ahc_patch6_func, 144, 77, 9 },
+	{ ahc_patch4_func, 156, 1, 1 },
+	{ ahc_patch1_func, 172, 1, 1 },
+	{ ahc_patch8_func, 180, 1, 2 },
+	{ ahc_patch0_func, 181, 1, 1 },
+	{ ahc_patch8_func, 190, 1, 2 },
+	{ ahc_patch0_func, 191, 1, 1 },
+	{ ahc_patch8_func, 207, 6, 2 },
+	{ ahc_patch0_func, 213, 6, 1 },
+	{ ahc_patch7_func, 221, 18, 2 },
+	{ ahc_patch1_func, 234, 1, 1 },
+	{ ahc_patch1_func, 241, 1, 2 },
+	{ ahc_patch0_func, 242, 2, 2 },
+	{ ahc_patch11_func, 243, 1, 1 },
+	{ ahc_patch8_func, 251, 33, 2 },
+	{ ahc_patch1_func, 267, 16, 1 },
+	{ ahc_patch12_func, 284, 14, 1 },
+	{ ahc_patch1_func, 298, 2, 2 },
+	{ ahc_patch0_func, 300, 3, 3 },
+	{ ahc_patch8_func, 300, 1, 2 },
+	{ ahc_patch0_func, 301, 2, 1 },
+	{ ahc_patch1_func, 305, 1, 2 },
+	{ ahc_patch0_func, 306, 1, 1 },
+	{ ahc_patch8_func, 310, 1, 1 },
+	{ ahc_patch8_func, 313, 2, 2 },
+	{ ahc_patch0_func, 315, 4, 1 },
+	{ ahc_patch12_func, 319, 1, 1 },
+	{ ahc_patch13_func, 322, 2, 3 },
+	{ ahc_patch8_func, 322, 1, 2 },
+	{ ahc_patch0_func, 323, 1, 1 },
+	{ ahc_patch1_func, 332, 40, 6 },
+	{ ahc_patch6_func, 341, 1, 1 },
+	{ ahc_patch7_func, 342, 1, 1 },
+	{ ahc_patch14_func, 344, 2, 1 },
+	{ ahc_patch15_func, 346, 5, 1 },
+	{ ahc_patch0_func, 372, 51, 15 },
+	{ ahc_patch12_func, 372, 1, 1 },
+	{ ahc_patch6_func, 374, 2, 2 },
+	{ ahc_patch16_func, 375, 1, 1 },
+	{ ahc_patch8_func, 378, 1, 1 },
+	{ ahc_patch17_func, 385, 1, 1 },
+	{ ahc_patch12_func, 390, 9, 3 },
+	{ ahc_patch8_func, 391, 3, 2 },
+	{ ahc_patch0_func, 394, 3, 1 },
+	{ ahc_patch8_func, 402, 6, 2 },
+	{ ahc_patch0_func, 408, 8, 1 },
+	{ ahc_patch12_func, 416, 1, 1 },
+	{ ahc_patch8_func, 418, 1, 2 },
+	{ ahc_patch0_func, 419, 1, 1 },
+	{ ahc_patch6_func, 422, 1, 1 },
+	{ ahc_patch6_func, 423, 1, 1 },
+	{ ahc_patch7_func, 424, 2, 1 },
+	{ ahc_patch8_func, 426, 1, 1 },
+	{ ahc_patch12_func, 427, 9, 4 },
+	{ ahc_patch8_func, 427, 1, 1 },
+	{ ahc_patch8_func, 434, 2, 1 },
+	{ ahc_patch0_func, 436, 4, 3 },
+	{ ahc_patch8_func, 436, 1, 2 },
+	{ ahc_patch0_func, 437, 3, 1 },
+	{ ahc_patch1_func, 441, 2, 1 },
+	{ ahc_patch6_func, 443, 5, 2 },
+	{ ahc_patch0_func, 448, 1, 1 },
+	{ ahc_patch7_func, 449, 113, 22 },
+	{ ahc_patch1_func, 450, 3, 2 },
+	{ ahc_patch0_func, 453, 5, 3 },
+	{ ahc_patch8_func, 453, 2, 2 },
+	{ ahc_patch0_func, 455, 3, 1 },
+	{ ahc_patch1_func, 460, 2, 2 },
+	{ ahc_patch0_func, 462, 6, 3 },
+	{ ahc_patch8_func, 462, 2, 2 },
+	{ ahc_patch0_func, 464, 3, 1 },
+	{ ahc_patch1_func, 470, 2, 2 },
+	{ ahc_patch0_func, 472, 9, 7 },
+	{ ahc_patch8_func, 472, 5, 6 },
+	{ ahc_patch18_func, 472, 1, 2 },
+	{ ahc_patch0_func, 473, 1, 1 },
+	{ ahc_patch18_func, 475, 1, 2 },
+	{ ahc_patch0_func, 476, 1, 1 },
+	{ ahc_patch0_func, 477, 4, 1 },
+	{ ahc_patch1_func, 486, 1, 1 },
+	{ ahc_patch2_func, 498, 2, 2 },
+	{ ahc_patch0_func, 500, 2, 2 },
+	{ ahc_patch19_func, 500, 2, 1 },
+	{ ahc_patch19_func, 536, 7, 1 },
+	{ ahc_patch3_func, 564, 1, 2 },
+	{ ahc_patch0_func, 565, 1, 1 },
+	{ ahc_patch20_func, 568, 1, 1 },
+	{ ahc_patch7_func, 570, 95, 26 },
+	{ ahc_patch4_func, 571, 1, 1 },
+	{ ahc_patch8_func, 578, 2, 2 },
+	{ ahc_patch0_func, 580, 3, 1 },
+	{ ahc_patch18_func, 587, 2, 2 },
+	{ ahc_patch0_func, 589, 1, 1 },
+	{ ahc_patch18_func, 593, 10, 3 },
+	{ ahc_patch5_func, 595, 8, 1 },
+	{ ahc_patch0_func, 603, 9, 2 },
+	{ ahc_patch5_func, 604, 8, 1 },
+	{ ahc_patch4_func, 614, 1, 2 },
+	{ ahc_patch0_func, 615, 1, 1 },
+	{ ahc_patch18_func, 616, 1, 2 },
+	{ ahc_patch0_func, 617, 3, 2 },
+	{ ahc_patch4_func, 619, 1, 1 },
+	{ ahc_patch5_func, 620, 1, 1 },
+	{ ahc_patch5_func, 623, 1, 1 },
+	{ ahc_patch5_func, 625, 1, 1 },
+	{ ahc_patch4_func, 627, 2, 2 },
+	{ ahc_patch0_func, 629, 2, 1 },
+	{ ahc_patch5_func, 631, 1, 1 },
+	{ ahc_patch5_func, 634, 1, 1 },
+	{ ahc_patch5_func, 637, 1, 1 },
+	{ ahc_patch18_func, 641, 1, 1 },
+	{ ahc_patch18_func, 644, 1, 1 },
+	{ ahc_patch4_func, 650, 1, 1 },
+	{ ahc_patch6_func, 665, 16, 1 },
+	{ ahc_patch4_func, 683, 20, 1 },
+	{ ahc_patch8_func, 704, 4, 2 },
+	{ ahc_patch0_func, 708, 4, 1 },
+	{ ahc_patch8_func, 712, 4, 2 },
+	{ ahc_patch0_func, 716, 3, 1 },
+	{ ahc_patch21_func, 724, 14, 1 },
+	{ ahc_patch6_func, 738, 3, 1 },
+	{ ahc_patch8_func, 750, 24, 8 },
+	{ ahc_patch18_func, 754, 1, 2 },
+	{ ahc_patch0_func, 755, 1, 1 },
+	{ ahc_patch13_func, 760, 4, 2 },
+	{ ahc_patch0_func, 764, 7, 3 },
+	{ ahc_patch22_func, 764, 5, 2 },
+	{ ahc_patch0_func, 769, 2, 1 },
+	{ ahc_patch0_func, 774, 40, 3 },
+	{ ahc_patch17_func, 786, 16, 2 },
+	{ ahc_patch0_func, 802, 1, 1 },
+	{ ahc_patch4_func, 826, 1, 1 },
+	{ ahc_patch4_func, 827, 3, 2 },
+	{ ahc_patch0_func, 830, 1, 1 },
+	{ ahc_patch4_func, 831, 12, 1 }
+};
+struct cs {
+	u_int16_t	begin;
+	u_int16_t	end;
+} critical_sections[] = {
+	{ 11, 18 },
+	{ 21, 30 },
+	{ 683, 699 },
+	{ 827, 830 },
+	{ 831, 837 },
+	{ 839, 841 },
+	{ 841, 843 }
+};
+const int num_critical_sections = sizeof(critical_sections)
+				 / sizeof(*critical_sections);
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/Makefile linux/drivers/scsi/aic7xxx/aicasm/Makefile
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/Makefile	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,28 @@
+PROG=	aicasm
+
+CSRCS=	aicasm.c aicasm_symbol.c
+GENSRCS= aicasm_gram.c aicasm_scan.c
+
+GENHDRS=	y.tab.h
+
+SRCS=	${GENSRCS} ${CSRCS}
+CLEANFILES= ${GENSRCS} ${GENHDRS} y.output
+# Override default kernel CFLAGS.  This is a userland app.
+AICASM_CFLAGS:= -I/usr/include -ldb1
+YFLAGS= -d
+
+NOMAN=	noman
+
+ifdef DEBUG
+CFLAGS+= -DDEBUG -g
+YFLAGS+= -t -v
+LFLAGS= -d
+endif
+
+.SUFFIXES= .l .y .c
+
+$(PROG): $(SRCS)
+	$(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG)
+
+clean:
+	rm -f $(CLEANFILES) $(PROG)
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.c linux/drivers/scsi/aic7xxx/aicasm/aicasm.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,777 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm.c#6 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.29 2000/10/05 04:25:42 gibbs Exp $
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_insformat.h"
+
+typedef struct patch {
+	STAILQ_ENTRY(patch) links;
+	int		patch_func;
+	u_int		begin;
+	u_int		skip_instr;
+	u_int		skip_patch;
+} patch_t;
+
+STAILQ_HEAD(patch_list, patch) patches;
+
+static void usage(void);
+static void back_patch(void);
+static void output_code(void);
+static void output_listing(char *ifilename);
+static void dump_scope(scope_t *scope);
+static void emit_patch(scope_t *scope, int patch);
+static int check_patch(patch_t **start_patch, int start_instr,
+		       int *skip_addr, int *func_vals);
+
+struct path_list search_path;
+int includes_search_curdir;
+char *appname;
+FILE *ofile;
+char *ofilename;
+char *regfilename;
+FILE *regfile;
+char *listfilename;
+FILE *listfile;
+
+static STAILQ_HEAD(,instruction) seq_program;
+struct cs_tailq cs_tailq;
+struct scope_list scope_stack;
+symlist_t patch_functions;
+
+#if DEBUG
+extern int yy_flex_debug;
+extern int yydebug;
+#endif
+extern FILE *yyin;
+extern int yyparse(void);
+
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+	extern char *optarg;
+	extern int optind;
+	int  ch;
+	int  retval;
+	char *inputfilename;
+	scope_t *sentinal;
+
+	STAILQ_INIT(&patches);
+	SLIST_INIT(&search_path);
+	STAILQ_INIT(&seq_program);
+	TAILQ_INIT(&cs_tailq);
+	SLIST_INIT(&scope_stack);
+
+	/* Set Sentinal scope node */
+	sentinal = scope_alloc();
+	sentinal->type = SCOPE_ROOT;
+	
+	includes_search_curdir = 1;
+	appname = *argv;
+	regfile = NULL;
+	listfile = NULL;
+#if DEBUG
+	yy_flex_debug = 0;
+	yydebug = 0;
+#endif
+	while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) {
+		switch(ch) {
+		case 'd':
+#if DEBUG
+			if (strcmp(optarg, "s") == 0) {
+				yy_flex_debug = 1;
+			} else if (strcmp(optarg, "p") == 0) {
+				yydebug = 1;
+			} else {
+				fprintf(stderr, "%s: -d Requires either an "
+					"'s' or 'p' argument\n", appname);
+				usage();
+			}
+#else
+			stop("-d: Assembler not built with debugging "
+			     "information", EX_SOFTWARE);
+#endif
+			break;
+		case 'l':
+			/* Create a program listing */
+			if ((listfile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			listfilename = optarg;
+			break;
+		case 'n':
+			/* Don't complain about the -nostdinc directrive */
+			if (strcmp(optarg, "ostdinc")) {
+				fprintf(stderr, "%s: Unknown option -%c%s\n",
+					appname, ch, optarg);
+				usage();
+				/* NOTREACHED */
+			}
+			break;
+		case 'o':
+			if ((ofile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			ofilename = optarg;
+			break;
+		case 'r':
+			if ((regfile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			regfilename = optarg;
+			break;
+		case 'I':
+		{
+			path_entry_t include_dir;
+
+			if (strcmp(optarg, "-") == 0) {
+				if (includes_search_curdir == 0) {
+					fprintf(stderr, "%s: Warning - '-I-' "
+							"specified multiple "
+							"times\n", appname);
+				}
+				includes_search_curdir = 0;
+				for (include_dir = search_path.slh_first;
+				     include_dir != NULL;
+				     include_dir = include_dir->links.sle_next)
+					/*
+					 * All entries before a '-I-' only
+					 * apply to includes specified with
+					 * quotes instead of "<>".
+					 */
+					include_dir->quoted_includes_only = 1;
+			} else {
+				include_dir =
+				    (path_entry_t)malloc(sizeof(*include_dir));
+				if (include_dir == NULL) {
+					perror(optarg);
+					stop(NULL, EX_OSERR);
+				}
+				include_dir->directory = strdup(optarg);
+				if (include_dir->directory == NULL) {
+					perror(optarg);
+					stop(NULL, EX_OSERR);
+				}
+				include_dir->quoted_includes_only = 0;
+				SLIST_INSERT_HEAD(&search_path, include_dir,
+						  links);
+			}
+			break;
+		}
+		case '?':
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1) {
+		fprintf(stderr, "%s: No input file specifiled\n", appname);
+		usage();
+		/* NOTREACHED */
+	}
+
+	symtable_open();
+	inputfilename = *argv;
+	include_file(*argv, SOURCE_FILE);
+	retval = yyparse();
+	if (retval == 0) {
+		if (SLIST_FIRST(&scope_stack) == NULL
+		 || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
+			stop("Unterminated conditional expression",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+
+		/* Process outmost scope */
+		process_scope(SLIST_FIRST(&scope_stack));
+		/*
+		 * Decend the tree of scopes and insert/emit
+		 * patches as appropriate.  We perform a depth first
+		 * tranversal, recursively handling each scope.
+		 */
+		/* start at the root scope */
+		dump_scope(SLIST_FIRST(&scope_stack));
+
+		/* Patch up forward jump addresses */
+		back_patch();
+
+		if (ofile != NULL)
+			output_code();
+		if (regfile != NULL) {
+			symtable_dump(regfile);
+		}
+		if (listfile != NULL)
+			output_listing(inputfilename);
+	}
+
+	stop(NULL, 0);
+	/* NOTREACHED */
+	return (0);
+}
+
+static void
+usage()
+{
+
+	(void)fprintf(stderr,
+"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
+			[-r register_output_file] [-l program_list_file]
+			input_file\n",
+			appname);
+	exit(EX_USAGE);
+}
+
+static void
+back_patch()
+{
+	struct instruction *cur_instr;
+
+	for(cur_instr = seq_program.stqh_first;
+	    cur_instr != NULL;
+	    cur_instr = cur_instr->links.stqe_next) {
+		if (cur_instr->patch_label != NULL) {
+			struct ins_format3 *f3_instr;
+			u_int address;
+
+			if (cur_instr->patch_label->type != LABEL) {
+				char buf[255];
+
+				snprintf(buf, sizeof(buf),
+					 "Undefined label %s",
+					 cur_instr->patch_label->name);
+				stop(buf, EX_DATAERR);
+				/* NOTREACHED */
+			}
+			f3_instr = &cur_instr->format.format3;
+			address = f3_instr->address;
+			address += cur_instr->patch_label->info.linfo->address;
+			f3_instr->address = address;
+		}
+	}
+}
+
+static void
+output_code()
+{
+	struct instruction *cur_instr;
+	patch_t *cur_patch;
+	critical_section_t *cs;
+	symbol_node_t *cur_node;
+	int instrcount;
+
+	instrcount = 0;
+	fprintf(ofile,
+"/*
+  * DO NOT EDIT - This file is automatically generated.
+  */\n");
+
+	fprintf(ofile, "static uint8_t seqprog[] = {\n");
+	for(cur_instr = seq_program.stqh_first;
+	    cur_instr != NULL;
+	    cur_instr = cur_instr->links.stqe_next) {
+
+		fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x",
+			cur_instr == seq_program.stqh_first ? "" : ",\n",
+#if BYTE_ORDER == LITTLE_ENDIAN
+			cur_instr->format.bytes[0],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[3]);
+#else
+			cur_instr->format.bytes[3],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[0]);
+#endif
+		instrcount++;
+	}
+	fprintf(ofile, "\n};\n\n");
+
+	/*
+	 *  Output patch information.  Patch functions first.
+	 */
+	for(cur_node = SLIST_FIRST(&patch_functions);
+	    cur_node != NULL;
+	    cur_node = SLIST_NEXT(cur_node,links)) {
+		fprintf(ofile,
+"static int ahc_patch%d_func(struct ahc_softc *ahc);
+
+static int
+ahc_patch%d_func(struct ahc_softc *ahc)
+{
+	return (%s);
+}\n\n",
+			cur_node->symbol->info.condinfo->func_num,
+			cur_node->symbol->info.condinfo->func_num,
+			cur_node->symbol->name);
+	}
+
+	fprintf(ofile,
+"typedef int patch_func_t (struct ahc_softc *);
+struct patch {
+	patch_func_t	*patch_func;
+	uint32_t	begin	   :10,
+			skip_instr :10,
+			skip_patch :12;
+} patches[] = {\n");
+
+	for(cur_patch = STAILQ_FIRST(&patches);
+	    cur_patch != NULL;
+	    cur_patch = STAILQ_NEXT(cur_patch,links)) {
+		fprintf(ofile, "%s\t{ ahc_patch%d_func, %d, %d, %d }",
+			cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n",
+			cur_patch->patch_func, cur_patch->begin,
+			cur_patch->skip_instr, cur_patch->skip_patch);
+	}
+
+	fprintf(ofile, "\n};\n");
+
+	fprintf(ofile,
+"struct cs {
+	u_int16_t	begin;
+	u_int16_t	end;
+} critical_sections[] = {\n");
+
+	for(cs = TAILQ_FIRST(&cs_tailq);
+	    cs != NULL;
+	    cs = TAILQ_NEXT(cs, links)) {
+		fprintf(ofile, "%s\t{ %d, %d }",
+			cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n",
+			cs->begin_addr, cs->end_addr);
+	}
+
+	fprintf(ofile, "\n};\n");
+
+	fprintf(ofile,
+"const int num_critical_sections = sizeof(critical_sections)
+				 / sizeof(*critical_sections);\n");
+
+	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
+}
+
+static void
+dump_scope(scope_t *scope)
+{
+	scope_t *cur_scope;
+
+	/*
+	 * Emit the first patch for this scope
+	 */
+	emit_patch(scope, 0);
+
+	/*
+	 * Dump each scope within this one.
+	 */
+	cur_scope = TAILQ_FIRST(&scope->inner_scope);
+
+	while (cur_scope != NULL) {
+
+		dump_scope(cur_scope);
+
+		cur_scope = TAILQ_NEXT(cur_scope, scope_links);
+	}
+
+	/*
+	 * Emit the second, closing, patch for this scope
+	 */
+	emit_patch(scope, 1);
+}
+
+void
+emit_patch(scope_t *scope, int patch)
+{
+	patch_info_t *pinfo;
+	patch_t *new_patch;
+
+	pinfo = &scope->patches[patch];
+
+	if (pinfo->skip_instr == 0)
+		/* No-Op patch */
+		return;
+
+	new_patch = (patch_t *)malloc(sizeof(*new_patch));
+
+	if (new_patch == NULL)
+		stop("Could not malloc patch structure", EX_OSERR);
+
+	memset(new_patch, 0, sizeof(*new_patch));
+
+	if (patch == 0) {
+		new_patch->patch_func = scope->func_num;
+		new_patch->begin = scope->begin_addr;
+	} else {
+		new_patch->patch_func = 0;
+		new_patch->begin = scope->end_addr;
+	}
+	new_patch->skip_instr = pinfo->skip_instr;
+	new_patch->skip_patch = pinfo->skip_patch;
+	STAILQ_INSERT_TAIL(&patches, new_patch, links);
+}
+
+void
+output_listing(char *ifilename)
+{
+	char buf[1024];
+	FILE *ifile;
+	struct instruction *cur_instr;
+	patch_t *cur_patch;
+	symbol_node_t *cur_func;
+	int *func_values;
+	int instrcount;
+	int instrptr;
+	int line;
+	int func_count;
+	int skip_addr;
+
+	instrcount = 0;
+	instrptr = 0;
+	line = 1;
+	skip_addr = 0;
+	if ((ifile = fopen(ifilename, "r")) == NULL) {
+		perror(ifilename);
+		stop(NULL, EX_DATAERR);
+	}
+
+	/*
+	 * Determine which options to apply to this listing.
+	 */
+	for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
+	    cur_func != NULL;
+	    cur_func = SLIST_NEXT(cur_func, links))
+		func_count++;
+
+	func_values = NULL;
+	if (func_count != 0) {
+		func_values = (int *)malloc(func_count * sizeof(int));
+
+		if (func_values == NULL)
+			stop("Could not malloc", EX_OSERR);
+		
+		func_values[0] = 0; /* FALSE func */
+		func_count--;
+
+		/*
+		 * Ask the user to fill in the return values for
+		 * the rest of the functions.
+		 */
+		
+		
+		for (cur_func = SLIST_FIRST(&patch_functions);
+		     cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
+		     cur_func = SLIST_NEXT(cur_func, links), func_count--) {
+			int input;
+			
+			fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
+			fprintf(stdout,
+				"Enter the return value for "
+				"this expression[T/F]:");
+
+			while (1) {
+
+				input = getchar();
+				input = toupper(input);
+
+				if (input == 'T') {
+					func_values[func_count] = 1;
+					break;
+				} else if (input == 'F') {
+					func_values[func_count] = 0;
+					break;
+				}
+			}
+			if (isatty(fileno(stdin)) == 0)
+				putchar(input);
+		}
+		fprintf(stdout, "\nThanks!\n");
+	}
+
+	/* Now output the listing */
+	cur_patch = STAILQ_FIRST(&patches);
+	for(cur_instr = STAILQ_FIRST(&seq_program);
+	    cur_instr != NULL;
+	    cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
+
+		if (check_patch(&cur_patch, instrcount,
+				&skip_addr, func_values) == 0) {
+			/* Don't count this instruction as it is in a patch
+			 * that was removed.
+			 */
+                        continue;
+		}
+
+		while (line < cur_instr->srcline) {
+			fgets(buf, sizeof(buf), ifile);
+				fprintf(listfile, "\t\t%s", buf);
+				line++;
+		}
+		fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
+#if BYTE_ORDER == LITTLE_ENDIAN
+			cur_instr->format.bytes[0],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[3]);
+#else
+			cur_instr->format.bytes[3],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[0]);
+#endif
+		fgets(buf, sizeof(buf), ifile);
+		fprintf(listfile, "\t%s", buf);
+		line++;
+		instrptr++;
+	}
+	/* Dump the remainder of the file */
+	while(fgets(buf, sizeof(buf), ifile) != NULL)
+		fprintf(listfile, "\t\t%s", buf);
+
+	fclose(ifile);
+}
+
+static int
+check_patch(patch_t **start_patch, int start_instr,
+	    int *skip_addr, int *func_vals)
+{
+	patch_t *cur_patch;
+
+	cur_patch = *start_patch;
+
+	while (cur_patch != NULL && start_instr == cur_patch->begin) {
+		if (func_vals[cur_patch->patch_func] == 0) {
+			int skip;
+
+			/* Start rejecting code */
+			*skip_addr = start_instr + cur_patch->skip_instr;
+			for (skip = cur_patch->skip_patch;
+			     skip > 0 && cur_patch != NULL;
+			     skip--)
+				cur_patch = STAILQ_NEXT(cur_patch, links);
+		} else {
+			/* Accepted this patch.  Advance to the next
+			 * one and wait for our intruction pointer to
+			 * hit this point.
+			 */
+			cur_patch = STAILQ_NEXT(cur_patch, links);
+		}
+	}
+
+	*start_patch = cur_patch;
+	if (start_instr < *skip_addr)
+		/* Still skipping */
+		return (0);
+
+	return (1);
+}
+
+/*
+ * Print out error information if appropriate, and clean up before
+ * terminating the program.
+ */
+void
+stop(const char *string, int err_code)
+{
+	if (string != NULL) {
+		fprintf(stderr, "%s: ", appname);
+		if (yyfilename != NULL) {
+			fprintf(stderr, "Stopped at file %s, line %d - ",
+				yyfilename, yylineno);
+		}
+		fprintf(stderr, "%s\n", string);
+	}
+
+	if (ofile != NULL) {
+		fclose(ofile);
+		if (err_code != 0) {
+			fprintf(stderr, "%s: Removing %s due to error\n",
+				appname, ofilename);
+			unlink(ofilename);
+		}
+	}
+
+	if (regfile != NULL) {
+		fclose(regfile);
+		if (err_code != 0) {
+			fprintf(stderr, "%s: Removing %s due to error\n",
+				appname, regfilename);
+			unlink(regfilename);
+		}
+	}
+
+	if (listfile != NULL) {
+		fclose(listfile);
+		if (err_code != 0) {
+			fprintf(stderr, "%s: Removing %s due to error\n",
+				appname, listfilename);
+			unlink(listfilename);
+		}
+	}
+
+	symlist_free(&patch_functions);
+	symtable_close();
+
+	exit(err_code);
+}
+
+struct instruction *
+seq_alloc()
+{
+	struct instruction *new_instr;
+
+	new_instr = (struct instruction *)malloc(sizeof(struct instruction));
+	if (new_instr == NULL)
+		stop("Unable to malloc instruction object", EX_SOFTWARE);
+	memset(new_instr, 0, sizeof(*new_instr));
+	STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
+	new_instr->srcline = yylineno;
+	return new_instr;
+}
+
+critical_section_t *
+cs_alloc()
+{
+	critical_section_t *new_cs;
+
+	new_cs= (critical_section_t *)malloc(sizeof(critical_section_t));
+	if (new_cs == NULL)
+		stop("Unable to malloc critical_section object", EX_SOFTWARE);
+	memset(new_cs, 0, sizeof(*new_cs));
+	
+	TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links);
+	return new_cs;
+}
+
+scope_t *
+scope_alloc()
+{
+	scope_t *new_scope;
+
+	new_scope = (scope_t *)malloc(sizeof(scope_t));
+	if (new_scope == NULL)
+		stop("Unable to malloc scope object", EX_SOFTWARE);
+	memset(new_scope, 0, sizeof(*new_scope));
+	TAILQ_INIT(&new_scope->inner_scope);
+	
+	if (SLIST_FIRST(&scope_stack) != NULL) {
+		TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
+				  new_scope, scope_links);
+	}
+	/* This patch is now the current scope */
+	SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
+	return new_scope;
+}
+
+void
+process_scope(scope_t *scope)
+{
+	/*
+	 * We are "leaving" this scope.  We should now have
+	 * enough information to process the lists of scopes
+	 * we encapsulate.
+	 */
+	scope_t *cur_scope;
+	u_int skip_patch_count;
+	u_int skip_instr_count;
+
+	cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
+	skip_patch_count = 0;
+	skip_instr_count = 0;
+	while (cur_scope != NULL) {
+		u_int patch0_patch_skip;
+
+		patch0_patch_skip = 0;
+		switch (cur_scope->type) {
+		case SCOPE_IF:
+		case SCOPE_ELSE_IF:
+			if (skip_instr_count != 0) {
+				/* Create a tail patch */
+				patch0_patch_skip++;
+				cur_scope->patches[1].skip_patch =
+				    skip_patch_count + 1;
+				cur_scope->patches[1].skip_instr =
+				    skip_instr_count;
+			}
+
+			/* Count Head patch */
+			patch0_patch_skip++;
+
+			/* Count any patches contained in our inner scope */
+			patch0_patch_skip += cur_scope->inner_scope_patches;
+
+			cur_scope->patches[0].skip_patch = patch0_patch_skip;
+			cur_scope->patches[0].skip_instr =
+			    cur_scope->end_addr - cur_scope->begin_addr;
+
+			skip_instr_count += cur_scope->patches[0].skip_instr;
+
+			skip_patch_count += patch0_patch_skip;
+			if (cur_scope->type == SCOPE_IF) {
+				scope->inner_scope_patches += skip_patch_count;
+				skip_patch_count = 0;
+			        skip_instr_count = 0;
+			}
+			break;
+		case SCOPE_ELSE:
+			/* Count any patches contained in our innter scope */
+			skip_patch_count += cur_scope->inner_scope_patches;
+
+			skip_instr_count += cur_scope->end_addr
+					  - cur_scope->begin_addr;
+			break;
+		case SCOPE_ROOT:
+			stop("Unexpected scope type encountered", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+
+		cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
+	}
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.h linux/drivers/scsi/aic7xxx/aicasm/aicasm.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,78 @@
+/*
+ * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm.h#4 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.h,v 1.11 2000/09/22 22:19:54 gibbs Exp $
+ */
+
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+typedef struct path_entry {
+	char	*directory;
+	int	quoted_includes_only;
+	SLIST_ENTRY(path_entry) links;
+} *path_entry_t;
+
+typedef enum {  
+	QUOTED_INCLUDE,
+	BRACKETED_INCLUDE,
+	SOURCE_FILE
+} include_type;
+
+SLIST_HEAD(path_list, path_entry);
+
+extern struct path_list search_path;
+extern struct cs_tailq cs_tailq;
+extern struct scope_list scope_stack;
+extern struct symlist patch_functions;
+extern int includes_search_curdir;		/* False if we've seen -I- */
+extern char *appname;
+extern int yylineno;
+extern char *yyfilename;
+
+void stop(const char *errstring, int err_code);
+void include_file(char *file_name, include_type type);
+struct instruction *seq_alloc(void);
+struct critical_section *cs_alloc(void);
+struct scope *scope_alloc(void);
+void process_scope(struct scope *);
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,1455 @@
+%{
+/*
+ * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm_gram.y#6 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_gram.y,v 1.12 2000/10/31 18:44:32 gibbs Exp $
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include <sys/types.h>
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_insformat.h"
+
+int yylineno;
+char *yyfilename;
+static symbol_t *cur_symbol;
+static symtype cur_symtype;
+static symbol_t *accumulator;
+static symbol_ref_t allones;
+static symbol_ref_t allzeros;
+static symbol_ref_t none;
+static symbol_ref_t sindex;
+static int instruction_ptr;
+static int sram_or_scb_offset;
+static int download_constant_count;
+static int in_critical_section;
+
+static void process_bitmask(int mask_type, symbol_t *sym, int mask);
+static void initialize_symbol(symbol_t *symbol);
+static void process_register(symbol_t **p_symbol);
+static void format_1_instr(int opcode, symbol_ref_t *dest,
+			   expression_t *immed, symbol_ref_t *src, int ret);
+static void format_2_instr(int opcode, symbol_ref_t *dest,
+			   expression_t *places, symbol_ref_t *src, int ret);
+static void format_3_instr(int opcode, symbol_ref_t *src,
+			   expression_t *immed, symbol_ref_t *address);
+static void test_readable_symbol(symbol_t *symbol);
+static void test_writable_symbol(symbol_t *symbol);
+static void type_check(symbol_t *symbol, expression_t *expression, int and_op);
+static void make_expression(expression_t *immed, int value);
+static void add_conditional(symbol_t *symbol);
+static int  is_download_const(expression_t *immed);
+
+#define YYDEBUG 1
+#define SRAM_SYMNAME "SRAM_BASE"
+#define SCB_SYMNAME "SCB_BASE"
+%}
+
+%union {
+	int		value;
+	char		*str;
+	symbol_t	*sym;
+	symbol_ref_t	sym_ref;
+	expression_t	expression;
+}
+
+%token T_REGISTER
+
+%token <value> T_CONST
+
+%token T_DOWNLOAD
+
+%token T_SCB
+
+%token T_SRAM
+
+%token T_ALIAS
+
+%token T_SIZE
+
+%token <value> T_ADDRESS
+
+%token T_ACCESS_MODE
+
+%token <value> T_MODE
+
+%token T_BEGIN_CS
+
+%token T_END_CS
+
+%token T_BIT
+
+%token T_MASK
+
+%token <value> T_NUMBER
+
+%token <str> T_PATH
+
+%token <sym> T_CEXPR
+
+%token T_EOF T_INCLUDE 
+
+%token <value> T_SHR T_SHL T_ROR T_ROL
+
+%token <value> T_MVI T_MOV T_CLR T_BMOV
+
+%token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
+
+%token <value> T_ADD T_ADC
+
+%token <value> T_INC T_DEC
+
+%token <value> T_STC T_CLC
+
+%token <value> T_CMP T_NOT T_XOR
+
+%token <value> T_TEST T_AND
+
+%token <value> T_OR
+
+%token T_RET
+
+%token T_NOP
+
+%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX
+
+%token T_A
+
+%token <sym> T_SYMBOL
+
+%token T_NL
+
+%token T_IF T_ELSE T_ELSE_IF T_ENDIF
+
+%type <sym_ref> reg_symbol address destination source opt_source
+
+%type <expression> expression immediate immediate_or_a
+
+%type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
+
+%type <value> numerical_value
+
+%left '|'
+%left '&'
+%left '+' '-'
+%right '~'
+%nonassoc UMINUS
+%%
+
+program:
+	include
+|	program include
+|	register
+|	program register
+|	constant
+|	program constant
+|	scratch_ram
+|	program scratch_ram
+|	scb
+|	program scb
+|	label
+|	program label
+|	critical_section_start
+|	program critical_section_start
+|	critical_section_end
+|	program critical_section_end
+|	conditional
+|	program conditional
+|	code
+|	program code
+;
+
+include:
+	T_INCLUDE '<' T_PATH '>'
+	{ include_file($3, BRACKETED_INCLUDE); }
+|	T_INCLUDE '"' T_PATH '"'
+	{ include_file($3, QUOTED_INCLUDE); }
+;
+
+register:
+	T_REGISTER { cur_symtype = REGISTER; } reg_definition
+;
+
+reg_definition:
+	T_SYMBOL '{'
+		{
+			if ($1->type != UNINITIALIZED) {
+				stop("Register multiply defined", EX_DATAERR);
+				/* NOTREACHED */
+			}
+			cur_symbol = $1; 
+			cur_symbol->type = cur_symtype;
+			initialize_symbol(cur_symbol);
+		}
+		reg_attribute_list
+	'}'
+		{                    
+			/*
+			 * Default to allowing everything in for registers
+			 * with no bit or mask definitions.
+			 */
+			if (cur_symbol->info.rinfo->valid_bitmask == 0)
+				cur_symbol->info.rinfo->valid_bitmask = 0xFF;
+
+			if (cur_symbol->info.rinfo->size == 0)
+				cur_symbol->info.rinfo->size = 1;
+
+			/*
+			 * This might be useful for registers too.
+			 */
+			if (cur_symbol->type != REGISTER) {
+				if (cur_symbol->info.rinfo->address == 0)
+					cur_symbol->info.rinfo->address =
+					    sram_or_scb_offset;
+				sram_or_scb_offset +=
+				    cur_symbol->info.rinfo->size;
+			}
+			cur_symbol = NULL;
+		}
+;
+
+reg_attribute_list:
+	reg_attribute
+|	reg_attribute_list reg_attribute
+;
+
+reg_attribute:		
+	reg_address
+|	size
+|	access_mode
+|	bit_defn
+|	mask_defn
+|	alias
+|	accumulator
+|	allones
+|	allzeros
+|	none
+|	sindex
+;
+
+reg_address:
+	T_ADDRESS T_NUMBER
+	{
+		cur_symbol->info.rinfo->address = $2;
+	}
+;
+
+size:
+	T_SIZE T_NUMBER
+	{
+		cur_symbol->info.rinfo->size = $2;
+	}
+;
+
+access_mode:
+	T_ACCESS_MODE T_MODE
+	{
+		cur_symbol->info.rinfo->mode = $2;
+	}
+;
+
+bit_defn:
+	T_BIT T_SYMBOL T_NUMBER
+	{
+		process_bitmask(BIT, $2, $3);
+	}
+;
+
+mask_defn:
+	T_MASK T_SYMBOL expression
+	{
+		process_bitmask(MASK, $2, $3.value);
+	}
+;
+
+alias:
+	T_ALIAS	T_SYMBOL
+	{
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of register alias",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = ALIAS;
+		initialize_symbol($2);
+		$2->info.ainfo->parent = cur_symbol;
+	}
+;
+
+accumulator:
+	T_ACCUM
+	{
+		if (accumulator != NULL) {
+			stop("Only one accumulator definition allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		accumulator = cur_symbol;
+	}
+;
+
+allones:
+	T_ALLONES
+	{
+		if (allones.symbol != NULL) {
+			stop("Only one definition of allones allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		allones.symbol = cur_symbol;
+	}
+;
+
+allzeros:
+	T_ALLZEROS
+	{
+		if (allzeros.symbol != NULL) {
+			stop("Only one definition of allzeros allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		allzeros.symbol = cur_symbol;
+	}
+;
+
+none:
+	T_NONE
+	{
+		if (none.symbol != NULL) {
+			stop("Only one definition of none allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		none.symbol = cur_symbol;
+	}
+;
+
+sindex:
+	T_SINDEX
+	{
+		if (sindex.symbol != NULL) {
+			stop("Only one definition of sindex allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		sindex.symbol = cur_symbol;
+	}
+;
+
+expression:
+	expression '|' expression
+	{
+		 $$.value = $1.value | $3.value;
+		 symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	expression '&' expression
+	{
+		$$.value = $1.value & $3.value;
+		symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	expression '+' expression
+	{
+		$$.value = $1.value + $3.value;
+		symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	expression '-' expression
+	{
+		$$.value = $1.value - $3.value;
+		symlist_merge(&($$.referenced_syms),
+			       &($1.referenced_syms),
+			       &($3.referenced_syms));
+	}
+|	'(' expression ')'
+	{
+		$$ = $2;
+	}
+|	'~' expression
+	{
+		$$ = $2;
+		$$.value = (~$$.value) & 0xFF;
+	}
+|	'-' expression %prec UMINUS
+	{
+		$$ = $2;
+		$$.value = -$$.value;
+	}
+|	T_NUMBER
+	{
+		$$.value = $1;
+		SLIST_INIT(&$$.referenced_syms);
+	}
+|	T_SYMBOL
+	{
+		symbol_t *symbol;
+
+		symbol = $1;
+		switch (symbol->type) {
+		case ALIAS:
+			symbol = $1->info.ainfo->parent;
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+			$$.value = symbol->info.rinfo->address;
+			break;
+		case MASK:
+		case BIT:
+			$$.value = symbol->info.minfo->mask;
+			break;
+		case DOWNLOAD_CONST:
+		case CONST:
+			$$.value = symbol->info.cinfo->value;
+			break;
+		case UNINITIALIZED:
+		default:
+		{
+			char buf[255];
+
+			snprintf(buf, sizeof(buf),
+				 "Undefined symbol %s referenced",
+				 symbol->name);
+			stop(buf, EX_DATAERR);
+			/* NOTREACHED */
+			break;
+		}
+		}
+		SLIST_INIT(&$$.referenced_syms);
+		symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
+	}
+;
+
+constant:
+	T_CONST T_SYMBOL numerical_value
+	{
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of symbol as a constant",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = CONST;
+		initialize_symbol($2);
+		$2->info.cinfo->value = $3;
+		$2->info.cinfo->define = $1;
+	}
+|	T_CONST T_SYMBOL T_DOWNLOAD
+	{
+		if ($1) {
+			stop("Invalid downloaded constant declaration",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of symbol as a downloaded constant",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = DOWNLOAD_CONST;
+		initialize_symbol($2);
+		$2->info.cinfo->value = download_constant_count++;
+		$2->info.cinfo->define = FALSE;
+	}
+;
+
+numerical_value:
+	T_NUMBER
+	{
+		$$ = $1;
+	}
+|	'-' T_NUMBER
+	{
+		$$ = -$2;
+	}
+;
+
+scratch_ram:
+	T_SRAM '{'
+		{
+			cur_symbol = symtable_get(SRAM_SYMNAME);
+			cur_symtype = SRAMLOC;
+			if (cur_symbol->type != UNINITIALIZED) {
+				stop("Only one SRAM definition allowed",
+				     EX_DATAERR);
+				/* NOTREACHED */
+			}
+			cur_symbol->type = SRAMLOC;
+			initialize_symbol(cur_symbol);
+		}
+		reg_address
+		{
+			sram_or_scb_offset = cur_symbol->info.rinfo->address;
+		}
+		scb_or_sram_reg_list
+	'}'
+		{
+			cur_symbol = NULL;
+		}
+;
+
+scb:
+	T_SCB '{'
+		{
+			cur_symbol = symtable_get(SCB_SYMNAME);
+			cur_symtype = SCBLOC;
+			if (cur_symbol->type != UNINITIALIZED) {
+				stop("Only one SRAM definition allowed",
+				     EX_SOFTWARE);
+				/* NOTREACHED */
+			}
+			cur_symbol->type = SCBLOC;
+			initialize_symbol(cur_symbol);
+			/* 64 bytes of SCB space */
+			cur_symbol->info.rinfo->size = 64;
+		}
+		reg_address
+		{
+			sram_or_scb_offset = cur_symbol->info.rinfo->address;
+		}
+		scb_or_sram_reg_list
+	'}'
+		{
+			cur_symbol = NULL;
+		}
+;
+
+scb_or_sram_reg_list:
+	reg_definition
+|	scb_or_sram_reg_list reg_definition
+;
+
+reg_symbol:
+	T_SYMBOL
+	{
+		process_register(&$1);
+		$$.symbol = $1;
+		$$.offset = 0;
+	}
+|	T_SYMBOL '[' T_SYMBOL ']'
+	{
+		process_register(&$1);
+		if ($3->type != CONST) {
+			stop("register offset must be a constant", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) {
+			stop("Accessing offset beyond range of register",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$.symbol = $1;
+		$$.offset = $3->info.cinfo->value;
+	}
+|	T_SYMBOL '[' T_NUMBER ']'
+	{
+		process_register(&$1);
+		if (($3 + 1) > $1->info.rinfo->size) {
+			stop("Accessing offset beyond range of register",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$.symbol = $1;
+		$$.offset = $3;
+	}
+|	T_A
+	{
+		if (accumulator == NULL) {
+			stop("No accumulator has been defined", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$.symbol = accumulator;
+		$$.offset = 0;
+	}
+;
+
+destination:
+	reg_symbol
+	{
+		test_writable_symbol($1.symbol);
+		$$ = $1;
+	}
+;
+
+immediate:
+	expression
+	{ $$ = $1; }
+;
+
+immediate_or_a:
+	expression
+	{
+		$$ = $1;
+	}
+|	T_A
+	{
+		SLIST_INIT(&$$.referenced_syms);
+		$$.value = 0;
+	}
+;
+
+source:
+	reg_symbol
+	{
+		test_readable_symbol($1.symbol);
+		$$ = $1;
+	}
+;
+
+opt_source:
+	{
+		$$.symbol = NULL;
+		$$.offset = 0;
+	}
+|	',' source
+	{ $$ = $2; }
+;
+
+ret:
+	{ $$ = 0; }
+|	T_RET
+	{ $$ = 1; }
+;
+
+critical_section_start:
+	T_BEGIN_CS
+	{
+		critical_section_t *cs;
+
+		if (in_critical_section != FALSE) {
+			stop("Critical Section within Critical Section",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		cs = cs_alloc();
+		cs->begin_addr = instruction_ptr;
+		in_critical_section = TRUE;
+	}
+
+critical_section_end:
+	T_END_CS
+	{
+		critical_section_t *cs;
+
+		if (in_critical_section == FALSE) {
+			stop("Unballanced 'end_cs'", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		cs = TAILQ_LAST(&cs_tailq, cs_tailq);
+		cs->end_addr = instruction_ptr;
+		in_critical_section = FALSE;
+	}
+
+label:
+	T_SYMBOL ':'
+	{
+		if ($1->type != UNINITIALIZED) {
+			stop("Program label multiply defined", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$1->type = LABEL;
+		initialize_symbol($1);
+		$1->info.linfo->address = instruction_ptr;
+	}
+;
+
+address:
+	T_SYMBOL
+	{
+		$$.symbol = $1;
+		$$.offset = 0;
+	}
+|	T_SYMBOL '+' T_NUMBER
+	{
+		$$.symbol = $1;
+		$$.offset = $3;
+	}
+|	T_SYMBOL '-' T_NUMBER
+	{
+		$$.symbol = $1;
+		$$.offset = -$3;
+	}
+|	'.'
+	{
+		$$.symbol = NULL;
+		$$.offset = 0;
+	}
+|	'.' '+' T_NUMBER
+	{
+		$$.symbol = NULL;
+		$$.offset = $3;
+	}
+|	'.' '-' T_NUMBER
+	{
+		$$.symbol = NULL;
+		$$.offset = -$3;
+	}
+;
+
+conditional:
+	T_IF T_CEXPR '{'
+	{
+		scope_t *new_scope;
+
+		add_conditional($2);
+		new_scope = scope_alloc();
+		new_scope->type = SCOPE_IF;
+		new_scope->begin_addr = instruction_ptr;
+		new_scope->func_num = $2->info.condinfo->func_num;
+	}
+|	T_ELSE T_IF T_CEXPR '{'
+	{
+		scope_t *new_scope;
+		scope_t *scope_context;
+		scope_t *last_scope;
+
+		/*
+		 * Ensure that the previous scope is either an
+		 * if or and else if.
+		 */
+		scope_context = SLIST_FIRST(&scope_stack);
+		last_scope = TAILQ_LAST(&scope_context->inner_scope,
+					scope_tailq);
+		if (last_scope == NULL
+		 || last_scope->type == T_ELSE) {
+
+			stop("'else if' without leading 'if'", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		add_conditional($3);
+		new_scope = scope_alloc();
+		new_scope->type = SCOPE_ELSE_IF;
+		new_scope->begin_addr = instruction_ptr;
+		new_scope->func_num = $3->info.condinfo->func_num;
+	}
+|	T_ELSE '{'
+	{
+		scope_t *new_scope;
+		scope_t *scope_context;
+		scope_t *last_scope;
+
+		/*
+		 * Ensure that the previous scope is either an
+		 * if or and else if.
+		 */
+		scope_context = SLIST_FIRST(&scope_stack);
+		last_scope = TAILQ_LAST(&scope_context->inner_scope,
+					scope_tailq);
+		if (last_scope == NULL
+		 || last_scope->type == SCOPE_ELSE) {
+
+			stop("'else' without leading 'if'", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		new_scope = scope_alloc();
+		new_scope->type = SCOPE_ELSE;
+		new_scope->begin_addr = instruction_ptr;
+	}
+;
+
+conditional:
+	'}'
+	{
+		scope_t *scope_context;
+
+		scope_context = SLIST_FIRST(&scope_stack);
+		if (scope_context->type == SCOPE_ROOT) {
+			stop("Unexpected '}' encountered", EX_DATAERR);
+			/* NOTREACHED */
+		}
+
+		scope_context->end_addr = instruction_ptr;
+
+		/* Pop the scope */
+		SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links);
+
+		process_scope(scope_context);
+
+		if (SLIST_FIRST(&scope_stack) == NULL) {
+			stop("Unexpected '}' encountered", EX_DATAERR);
+			/* NOTREACHED */
+		}
+	}
+;
+
+f1_opcode:
+	T_AND { $$ = AIC_OP_AND; }
+|	T_XOR { $$ = AIC_OP_XOR; }
+|	T_ADD { $$ = AIC_OP_ADD; }
+|	T_ADC { $$ = AIC_OP_ADC; }
+;
+
+code:
+	f1_opcode destination ',' immediate_or_a opt_source ret ';'
+	{
+		format_1_instr($1, &$2, &$4, &$5, $6);
+	}
+;
+
+code:
+	T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
+	{
+		format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
+	}
+;
+
+code:
+	T_INC destination opt_source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+	}
+;
+
+code:
+	T_DEC destination opt_source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, -1);
+		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+	}
+;
+
+code:
+	T_CLC ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, -1);
+		format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
+	}
+|	T_CLC T_MVI destination ',' immediate_or_a ret ';'
+	{
+		format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
+	}
+;
+
+code:
+	T_STC ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
+	}
+|	T_STC destination ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
+	}
+;
+
+code:
+	T_BMOV destination ',' source ',' immediate ret ';'
+	{
+		format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
+	}
+;
+
+code:
+	T_MOV destination ',' source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5);
+	}
+;
+
+code:
+	T_MVI destination ',' immediate_or_a ret ';'
+	{
+		format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
+	}
+;
+
+code:
+	T_NOT destination opt_source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4);
+	}
+;
+
+code:
+	T_CLR destination ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
+	}
+;
+
+code:
+	T_NOP ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2);
+	}
+;
+
+code:
+	T_RET ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
+	}
+;
+
+	/*
+	 * This grammer differs from the one in the aic7xxx
+	 * reference manual since the grammer listed there is
+	 * ambiguous and causes a shift/reduce conflict.
+	 * It also seems more logical as the "immediate"
+	 * argument is listed as the second arg like the
+	 * other formats.
+	 */
+
+f2_opcode:
+	T_SHL { $$ = AIC_OP_SHL; }
+|	T_SHR { $$ = AIC_OP_SHR; }
+|	T_ROL { $$ = AIC_OP_ROL; }
+|	T_ROR { $$ = AIC_OP_ROR; }
+;
+
+code:
+	f2_opcode destination ',' expression opt_source ret ';'
+	{
+		format_2_instr($1, &$2, &$4, &$5, $6);
+	}
+;
+
+jmp_jc_jnc_call:
+	T_JMP	{ $$ = AIC_OP_JMP; }
+|	T_JC	{ $$ = AIC_OP_JC; }
+|	T_JNC	{ $$ = AIC_OP_JNC; }
+|	T_CALL	{ $$ = AIC_OP_CALL; }
+;
+
+jz_jnz:
+	T_JZ	{ $$ = AIC_OP_JZ; }
+|	T_JNZ	{ $$ = AIC_OP_JNZ; }
+;
+
+je_jne:
+	T_JE	{ $$ = AIC_OP_JE; }
+|	T_JNE	{ $$ = AIC_OP_JNE; }
+;
+
+code:
+	jmp_jc_jnc_call address ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0);
+		format_3_instr($1, &sindex, &immed, &$2);
+	}
+;
+
+code:
+	T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
+	{
+		format_3_instr($5, &$2, &$4, &$6);
+	}
+;
+
+code:
+	T_TEST source ',' immediate_or_a jz_jnz address ';'
+	{
+		format_3_instr($5, &$2, &$4, &$6);
+	}
+;
+
+code:
+	T_CMP source ',' immediate_or_a je_jne address ';'
+	{
+		format_3_instr($5, &$2, &$4, &$6);
+	}
+;
+
+code:
+	T_MOV source jmp_jc_jnc_call address ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0);
+		format_3_instr($3, &$2, &immed, &$4);
+	}
+;
+
+code:
+	T_MVI immediate jmp_jc_jnc_call address ';'
+	{
+		format_3_instr($3, &allzeros, &$2, &$4);
+	}
+;
+
+%%
+
+static void
+process_bitmask(int mask_type, symbol_t *sym, int mask)
+{
+	/*
+	 * Add the current register to its
+	 * symbol list, if it already exists,
+	 * warn if we are setting it to a
+	 * different value, or in the bit to
+	 * the "allowed bits" of this register.
+	 */
+	if (sym->type == UNINITIALIZED) {
+		sym->type = mask_type;
+		initialize_symbol(sym);
+		if (mask_type == BIT) {
+			if (mask == 0) {
+				stop("Bitmask with no bits set", EX_DATAERR);
+				/* NOTREACHED */
+			}
+			if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) {
+				stop("Bitmask with more than one bit set",
+				     EX_DATAERR);
+				/* NOTREACHED */
+			}
+		}
+		sym->info.minfo->mask = mask;
+	} else if (sym->type != mask_type) {
+		stop("Bit definition mirrors a definition of the same "
+		     " name, but a different type", EX_DATAERR);
+		/* NOTREACHED */
+	} else if (mask != sym->info.minfo->mask) {
+		stop("Bitmask redefined with a conflicting value", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	/* Fail if this symbol is already listed */
+	if (symlist_search(&(sym->info.minfo->symrefs),
+			   cur_symbol->name) != NULL) {
+		stop("Bitmask defined multiple times for register", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	symlist_add(&(sym->info.minfo->symrefs), cur_symbol,
+		    SYMLIST_INSERT_HEAD);
+	cur_symbol->info.rinfo->valid_bitmask |= mask;
+	cur_symbol->info.rinfo->typecheck_masks = TRUE;
+}
+
+static void
+initialize_symbol(symbol_t *symbol)
+{
+	switch (symbol->type) {
+        case UNINITIALIZED:
+		stop("Call to initialize_symbol with type field unset",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+		break;
+        case REGISTER:
+        case SRAMLOC:
+        case SCBLOC:
+		symbol->info.rinfo =
+		    (struct reg_info *)malloc(sizeof(struct reg_info));
+		if (symbol->info.rinfo == NULL) {
+			stop("Can't create register info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.rinfo, 0,
+		       sizeof(struct reg_info));
+		break;
+        case ALIAS:
+		symbol->info.ainfo =
+		    (struct alias_info *)malloc(sizeof(struct alias_info));
+		if (symbol->info.ainfo == NULL) {
+			stop("Can't create alias info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.ainfo, 0,
+		       sizeof(struct alias_info));
+		break;
+        case MASK:
+        case BIT:
+		symbol->info.minfo =
+		    (struct mask_info *)malloc(sizeof(struct mask_info));
+		if (symbol->info.minfo == NULL) {
+			stop("Can't create bitmask info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.minfo, 0, sizeof(struct mask_info));
+		SLIST_INIT(&(symbol->info.minfo->symrefs));
+		break;
+        case CONST:
+        case DOWNLOAD_CONST:
+		symbol->info.cinfo =
+		    (struct const_info *)malloc(sizeof(struct const_info));
+		if (symbol->info.cinfo == NULL) {
+			stop("Can't create alias info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.cinfo, 0,
+		       sizeof(struct const_info));
+		break;
+	case LABEL:
+		symbol->info.linfo =
+		    (struct label_info *)malloc(sizeof(struct label_info));
+		if (symbol->info.linfo == NULL) {
+			stop("Can't create label info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.linfo, 0,
+		       sizeof(struct label_info));
+		break;
+	case CONDITIONAL:
+		symbol->info.condinfo =
+		    (struct cond_info *)malloc(sizeof(struct cond_info));
+		if (symbol->info.condinfo == NULL) {
+			stop("Can't create conditional info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.condinfo, 0,
+		       sizeof(struct cond_info));
+		break;
+	default:
+		stop("Call to initialize_symbol with invalid symbol type",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+		break;
+	}
+}
+
+static void
+process_register(symbol_t **p_symbol)
+{
+	char buf[255];
+	symbol_t *symbol = *p_symbol;
+
+	if (symbol->type == UNINITIALIZED) {
+		snprintf(buf, sizeof(buf), "Undefined register %s",
+			 symbol->name);
+		stop(buf, EX_DATAERR);
+		/* NOTREACHED */
+	} else if (symbol->type == ALIAS) {
+		*p_symbol = symbol->info.ainfo->parent;
+	} else if ((symbol->type != REGISTER)
+		&& (symbol->type != SCBLOC)
+		&& (symbol->type != SRAMLOC)) {
+		snprintf(buf, sizeof(buf),
+			 "Specified symbol %s is not a register",
+			 symbol->name);
+		stop(buf, EX_DATAERR);
+	}
+}
+
+static void
+format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed,
+	       symbol_ref_t *src, int ret)
+{
+	struct instruction *instr;
+	struct ins_format1 *f1_instr;
+
+	if (src->symbol == NULL)
+		src = dest;
+
+	/* Test register permissions */
+	test_writable_symbol(dest->symbol);
+	test_readable_symbol(src->symbol);
+
+	/* Ensure that immediate makes sense for this destination */
+	type_check(dest->symbol, immed, opcode);
+
+	/* Allocate sequencer space for the instruction and fill it out */
+	instr = seq_alloc();
+	f1_instr = &instr->format.format1;
+	f1_instr->ret = ret ? 1 : 0;
+	f1_instr->opcode = opcode;
+	f1_instr->destination = dest->symbol->info.rinfo->address
+			      + dest->offset;
+	f1_instr->source = src->symbol->info.rinfo->address
+			 + src->offset;
+	f1_instr->immediate = immed->value;
+
+	if (is_download_const(immed))
+		f1_instr->parity = 1;
+
+	symlist_free(&immed->referenced_syms);
+	instruction_ptr++;
+}
+
+static void
+format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places,
+	       symbol_ref_t *src, int ret)
+{
+	struct instruction *instr;
+	struct ins_format2 *f2_instr;
+	uint8_t shift_control;
+
+	if (src->symbol == NULL)
+		src = dest;
+
+	/* Test register permissions */
+	test_writable_symbol(dest->symbol);
+	test_readable_symbol(src->symbol);
+
+	/* Allocate sequencer space for the instruction and fill it out */
+	instr = seq_alloc();
+	f2_instr = &instr->format.format2;
+	f2_instr->ret = ret ? 1 : 0;
+	f2_instr->opcode = AIC_OP_ROL;
+	f2_instr->destination = dest->symbol->info.rinfo->address
+			      + dest->offset;
+	f2_instr->source = src->symbol->info.rinfo->address
+			 + src->offset;
+	if (places->value > 8 || places->value <= 0) {
+		stop("illegal shift value", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	switch (opcode) {
+	case AIC_OP_SHL:
+		if (places->value == 8)
+			shift_control = 0xf0;
+		else
+			shift_control = (places->value << 4) | places->value;
+		break;
+	case AIC_OP_SHR:
+		if (places->value == 8) {
+			shift_control = 0xf8;
+		} else {
+			shift_control = (places->value << 4)
+				      | (8 - places->value)
+				      | 0x08;
+		}
+		break;
+	case AIC_OP_ROL:
+		shift_control = places->value & 0x7;
+		break;
+	case AIC_OP_ROR:
+		shift_control = (8 - places->value) | 0x08;
+		break;
+	default:
+		shift_control = 0; /* Quiet Compiler */
+		stop("Invalid shift operation specified", EX_SOFTWARE);
+		/* NOTREACHED */
+		break;
+	};
+	f2_instr->shift_control = shift_control;
+	symlist_free(&places->referenced_syms);
+	instruction_ptr++;
+}
+
+static void
+format_3_instr(int opcode, symbol_ref_t *src,
+	       expression_t *immed, symbol_ref_t *address)
+{
+	struct instruction *instr;
+	struct ins_format3 *f3_instr;
+	int addr;
+
+	/* Test register permissions */
+	test_readable_symbol(src->symbol);
+
+	/* Ensure that immediate makes sense for this source */
+	type_check(src->symbol, immed, opcode);
+
+	/* Allocate sequencer space for the instruction and fill it out */
+	instr = seq_alloc();
+	f3_instr = &instr->format.format3;
+	if (address->symbol == NULL) {
+		/* 'dot' referrence.  Use the current instruction pointer */
+		addr = instruction_ptr + address->offset;
+	} else if (address->symbol->type == UNINITIALIZED) {
+		/* forward reference */
+		addr = address->offset;
+		instr->patch_label = address->symbol;
+	} else
+		addr = address->symbol->info.linfo->address + address->offset;
+	f3_instr->opcode = opcode;
+	f3_instr->address = addr;
+	f3_instr->source = src->symbol->info.rinfo->address
+			 + src->offset;
+	f3_instr->immediate = immed->value;
+
+	if (is_download_const(immed))
+		f3_instr->parity = 1;
+
+	symlist_free(&immed->referenced_syms);
+	instruction_ptr++;
+}
+
+static void
+test_readable_symbol(symbol_t *symbol)
+{
+	if (symbol->info.rinfo->mode == WO) {
+		stop("Write Only register specified as source",
+		     EX_DATAERR);
+		/* NOTREACHED */
+	}
+}
+
+static void
+test_writable_symbol(symbol_t *symbol)
+{
+	if (symbol->info.rinfo->mode == RO) {
+		stop("Read Only register specified as destination",
+		     EX_DATAERR);
+		/* NOTREACHED */
+	}
+}
+
+static void
+type_check(symbol_t *symbol, expression_t *expression, int opcode)
+{
+	symbol_node_t *node;
+	int and_op;
+	char buf[255];
+
+	and_op = FALSE;
+	if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
+		and_op = TRUE;
+
+	/*
+	 * Make sure that we aren't attempting to write something
+	 * that hasn't been defined.  If this is an and operation,
+	 * this is a mask, so "undefined" bits are okay.
+	 */
+	if (and_op == FALSE
+	 && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
+		snprintf(buf, sizeof(buf),
+			 "Invalid bit(s) 0x%x in immediate written to %s",
+			 expression->value & ~symbol->info.rinfo->valid_bitmask,
+			 symbol->name);
+		stop(buf, EX_DATAERR);
+		/* NOTREACHED */
+	}
+
+	/*
+	 * Now make sure that all of the symbols referenced by the
+	 * expression are defined for this register.
+	 */
+	if(symbol->info.rinfo->typecheck_masks != FALSE) {
+		for(node = expression->referenced_syms.slh_first;
+		    node != NULL;
+		    node = node->links.sle_next) {
+			if ((node->symbol->type == MASK
+			  || node->symbol->type == BIT)
+			 && symlist_search(&node->symbol->info.minfo->symrefs,
+					   symbol->name) == NULL) {
+				snprintf(buf, sizeof(buf),
+					 "Invalid bit or mask %s "
+					 "for register %s",
+					 node->symbol->name, symbol->name);
+				stop(buf, EX_DATAERR);
+				/* NOTREACHED */
+			}
+		}
+	}
+}
+
+static void
+make_expression(expression_t *immed, int value)
+{
+	SLIST_INIT(&immed->referenced_syms);
+	immed->value = value & 0xff;
+}
+
+static void
+add_conditional(symbol_t *symbol)
+{
+	static int numfuncs;
+
+	if (numfuncs == 0) {
+		/* add a special conditional, "0" */
+		symbol_t *false_func;
+
+		false_func = symtable_get("0");
+		if (false_func->type != UNINITIALIZED) {
+			stop("Conditional expression '0' "
+			     "conflicts with a symbol", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		false_func->type = CONDITIONAL;
+		initialize_symbol(false_func);
+		false_func->info.condinfo->func_num = numfuncs++;
+		symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD);
+	}
+
+	/* This condition has occurred before */
+	if (symbol->type == CONDITIONAL)
+		return;
+
+	if (symbol->type != UNINITIALIZED) {
+		stop("Conditional expression conflicts with a symbol",
+		     EX_DATAERR);
+		/* NOTREACHED */
+	}
+
+	symbol->type = CONDITIONAL;
+	initialize_symbol(symbol);
+	symbol->info.condinfo->func_num = numfuncs++;
+	symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD);
+}
+
+void
+yyerror(const char *string)
+{
+	stop(string, EX_DATAERR);
+}
+
+static int
+is_download_const(expression_t *immed)
+{
+	if ((immed->referenced_syms.slh_first != NULL)
+	 && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST))
+		return (TRUE);
+
+	return (FALSE);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,129 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm_insformat.h#4 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_insformat.h,v 1.3 2000/09/22 22:19:54 gibbs Exp $
+ */
+
+#if linux
+#include <endian.h>
+#else
+#include <machine/endian.h>
+#endif
+
+struct ins_format1 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint32_t	immediate	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+#else
+	uint32_t	parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			immediate	: 8;
+#endif
+};
+
+struct ins_format2 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint32_t	shift_control	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+#else
+	uint32_t	parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			shift_control	: 8;
+#endif
+};
+
+struct ins_format3 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint32_t	immediate	: 8,
+			source		: 9,
+			address		: 10,
+			opcode		: 4,
+			parity		: 1;
+#else
+	uint32_t	parity		: 1,
+			opcode		: 4,
+			address		: 10,
+			source		: 9,
+			immediate	: 8;
+#endif
+};
+
+union ins_formats {
+		struct ins_format1 format1;
+		struct ins_format2 format2;
+		struct ins_format3 format3;
+		uint8_t		   bytes[4];
+		uint32_t	   integer;
+};
+struct instruction {
+	union	ins_formats format;
+	u_int	srcline;
+	struct symbol *patch_label;
+	STAILQ_ENTRY(instruction) links;
+};
+
+#define	AIC_OP_OR	0x0
+#define	AIC_OP_AND	0x1
+#define AIC_OP_XOR	0x2
+#define	AIC_OP_ADD	0x3
+#define	AIC_OP_ADC	0x4
+#define	AIC_OP_ROL	0x5
+#define	AIC_OP_BMOV	0x6
+
+#define	AIC_OP_JMP	0x8
+#define AIC_OP_JC	0x9
+#define AIC_OP_JNC	0xa
+#define AIC_OP_CALL	0xb
+#define	AIC_OP_JNE	0xc
+#define	AIC_OP_JNZ	0xd
+#define	AIC_OP_JE	0xe
+#define	AIC_OP_JZ	0xf
+
+/* Pseudo Ops */
+#define	AIC_OP_SHL	0x10
+#define	AIC_OP_SHR	0x20
+#define	AIC_OP_ROR	0x30
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,302 @@
+%{
+/*
+ * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm_scan.l#4 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13 2000/09/22 22:19:54 gibbs Exp $
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "y.tab.h"
+
+#define MAX_STR_CONST 256
+char string_buf[MAX_STR_CONST];
+char *string_buf_ptr;
+int  parren_count;
+%}
+
+PATH		[-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
+WORD		[A-Za-z_][-A-Za-z_0-9]*
+SPACE		[ \t]+
+
+%x COMMENT
+%x CEXPR
+%x INCLUDE
+
+%%
+\n			{ ++yylineno; }
+"/*"			{ BEGIN COMMENT;  /* Enter comment eating state */ }
+<COMMENT>"/*"		{ fprintf(stderr, "Warning! Comment within comment."); }
+<COMMENT>\n		{ ++yylineno; }
+<COMMENT>[^*/\n]*	;
+<COMMENT>"*"+[^*/\n]*	;
+<COMMENT>"/"+[^*/\n]*	;
+<COMMENT>"*"+"/"	{ BEGIN INITIAL; }
+if[ \t]*\(		{
+				string_buf_ptr = string_buf;
+				parren_count = 1;
+				BEGIN CEXPR;
+				return T_IF;
+			}
+<CEXPR>\(		{	*string_buf_ptr++ = '('; parren_count++; }
+<CEXPR>\)		{
+				parren_count--;
+				if (parren_count == 0) {
+					/* All done */
+					BEGIN INITIAL;
+					*string_buf_ptr = '\0';
+					yylval.sym = symtable_get(string_buf);
+					return T_CEXPR;
+				} else {
+					*string_buf_ptr++ = ')';
+				}
+			}
+<CEXPR>\n		{ ++yylineno; }
+<CEXPR>[^()\n]+	{
+				char *yptr = yytext;
+
+				while (*yptr != '\0') {
+					/* Remove duplicate spaces */
+					if (*yptr == '\t')
+						*yptr = ' ';
+					if (*yptr == ' '
+					 && string_buf_ptr != string_buf
+					 && string_buf_ptr[-1] == ' ')
+						yptr++;
+					else 
+						*string_buf_ptr++ = *yptr++;
+				}
+			}
+
+{SPACE}			;
+
+	/* Register/SCB/SRAM definition keywords */
+register		{ return T_REGISTER; }
+const			{ yylval.value = FALSE; return T_CONST; }
+download		{ return T_DOWNLOAD; }
+address			{ return T_ADDRESS; }
+access_mode		{ return T_ACCESS_MODE; }
+RW|RO|WO		{
+				 if (strcmp(yytext, "RW") == 0)
+					yylval.value = RW;
+				 else if (strcmp(yytext, "RO") == 0)
+					yylval.value = RO;
+				 else
+					yylval.value = WO;
+				 return T_MODE;
+			}
+BEGIN_CRITICAL		{ return T_BEGIN_CS; }
+END_CRITICAL		{ return T_END_CS; }
+bit			{ return T_BIT; }
+mask			{ return T_MASK; }
+alias			{ return T_ALIAS; }
+size			{ return T_SIZE; }
+scb			{ return T_SCB; }
+scratch_ram		{ return T_SRAM; }
+accumulator		{ return T_ACCUM; }
+allones			{ return T_ALLONES; }
+allzeros		{ return T_ALLZEROS; }
+none			{ return T_NONE; }
+sindex			{ return T_SINDEX; }
+A			{ return T_A; }
+
+	/* Opcodes */
+shl			{ return T_SHL; }
+shr			{ return T_SHR; }
+ror			{ return T_ROR; }
+rol			{ return T_ROL; }
+mvi			{ return T_MVI; }
+mov			{ return T_MOV; }
+clr			{ return T_CLR; }
+jmp			{ return T_JMP; }
+jc			{ return T_JC;	}
+jnc			{ return T_JNC;	}
+je			{ return T_JE;	}
+jne			{ return T_JNE;	}
+jz			{ return T_JZ;	}
+jnz			{ return T_JNZ;	}
+call			{ return T_CALL; }
+add			{ return T_ADD; }
+adc			{ return T_ADC; }
+bmov			{ return T_BMOV; }
+inc			{ return T_INC; }
+dec			{ return T_DEC; }
+stc			{ return T_STC;	}
+clc			{ return T_CLC; }
+cmp			{ return T_CMP;	}
+not			{ return T_NOT;	}
+xor			{ return T_XOR;	}
+test			{ return T_TEST;}
+and			{ return T_AND;	}
+or			{ return T_OR;	}
+ret			{ return T_RET; }
+nop			{ return T_NOP; }
+else			{ return T_ELSE; }
+
+	/* Allowed Symbols */
+[-+,:()~|&."{};<>[\]!]	{ return yytext[0]; }
+
+	/* Number processing */
+0[0-7]*			{
+				yylval.value = strtol(yytext, NULL, 8);
+				return T_NUMBER;
+			}
+
+0[xX][0-9a-fA-F]+	{
+				yylval.value = strtoul(yytext + 2, NULL, 16);
+				return T_NUMBER;
+			}
+
+[1-9][0-9]*		{
+				yylval.value = strtol(yytext, NULL, 10);
+				return T_NUMBER;
+			}
+
+	/* Include Files */
+#include		{ return T_INCLUDE; BEGIN INCLUDE;}
+<INCLUDE>[<>\"]		{ return yytext[0]; }
+<INCLUDE>{PATH}		{ yylval.str = strdup(yytext); return T_PATH; }
+<INCLUDE>;		{ BEGIN INITIAL; return yytext[0]; }
+<INCLUDE>.		{ stop("Invalid include line", EX_DATAERR); }
+
+	/* For parsing C include files with #define foo */
+#define			{ yylval.value = TRUE; return T_CONST; }
+	/* Throw away macros */
+#define[^\n]*[()]+[^\n]* ;
+{PATH}			{ yylval.str = strdup(yytext); return T_PATH; }
+
+{WORD}			{ yylval.sym = symtable_get(yytext);  return T_SYMBOL; }
+
+.			{ 
+				char buf[255];
+
+				snprintf(buf, sizeof(buf), "Invalid character "
+					 "'%c'", yytext[0]);
+				stop(buf, EX_DATAERR);
+			}
+%%
+
+typedef struct include {
+        YY_BUFFER_STATE  buffer;
+        int              lineno;
+        char            *filename;
+	SLIST_ENTRY(include) links;
+}include_t;
+
+SLIST_HEAD(, include) include_stack;
+
+void
+include_file(char *file_name, include_type type)
+{
+	FILE *newfile;
+	include_t *include;
+
+	newfile = NULL;
+	/* Try the current directory first */
+	if (includes_search_curdir != 0 || type == SOURCE_FILE)
+		newfile = fopen(file_name, "r");
+
+	if (newfile == NULL && type != SOURCE_FILE) {
+                path_entry_t include_dir;
+                for (include_dir = search_path.slh_first;
+                     include_dir != NULL;                
+                     include_dir = include_dir->links.sle_next) {
+			char fullname[PATH_MAX];
+
+			if ((include_dir->quoted_includes_only == TRUE)
+			 && (type != QUOTED_INCLUDE))
+				continue;
+
+			snprintf(fullname, sizeof(fullname),
+				 "%s/%s", include_dir->directory, file_name);
+
+			if ((newfile = fopen(fullname, "r")) != NULL)
+				break;
+                }
+        }
+
+	if (newfile == NULL) {
+		perror(file_name);
+		stop("Unable to open input file", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+
+	if (type != SOURCE_FILE) {
+		include = (include_t *)malloc(sizeof(include_t));
+		if (include == NULL) {
+			stop("Unable to allocate include stack entry",
+			     EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		include->buffer = YY_CURRENT_BUFFER;
+		include->lineno = yylineno;
+		include->filename = yyfilename;
+		SLIST_INSERT_HEAD(&include_stack, include, links);
+	}
+	yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
+	yylineno = 1;
+	yyfilename = strdup(file_name);
+}
+
+int
+yywrap()
+{
+	include_t *include;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER);
+	(void)fclose(yyin);
+	if (yyfilename != NULL)
+		free(yyfilename);
+	yyfilename = NULL;
+	include = include_stack.slh_first;
+	if (include != NULL) {
+		yy_switch_to_buffer(include->buffer);
+		yylineno = include->lineno;
+		yyfilename = include->filename;
+		SLIST_REMOVE_HEAD(&include_stack, links);
+		free(include);
+		return (0);
+	}
+	return (1);
+}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,468 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $
+ */
+
+#include <sys/types.h>
+
+#ifdef __linux__
+#include <db1/db.h>
+#else
+#include <db.h>
+#endif
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "aicasm_symbol.h"
+#include "aicasm.h"
+
+static DB *symtable;
+
+symbol_t *
+symbol_create(char *name)
+{
+	symbol_t *new_symbol;
+
+	new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
+	if (new_symbol == NULL) {
+		perror("Unable to create new symbol");
+		exit(EX_SOFTWARE);
+	}
+	memset(new_symbol, 0, sizeof(*new_symbol));
+	new_symbol->name = strdup(name);
+	new_symbol->type = UNINITIALIZED;
+	return (new_symbol);
+}
+
+void
+symbol_delete(symbol_t *symbol)
+{
+	if (symtable != NULL) {
+		DBT	 key;
+
+		key.data = symbol->name;
+		key.size = strlen(symbol->name);
+		symtable->del(symtable, &key, /*flags*/0);
+	}
+	switch(symbol->type) {
+	case SCBLOC:
+	case SRAMLOC:
+	case REGISTER:
+		if (symbol->info.rinfo != NULL)
+			free(symbol->info.rinfo);
+		break;
+	case ALIAS:
+		if (symbol->info.ainfo != NULL)
+			free(symbol->info.ainfo);
+		break;
+	case MASK:
+	case BIT:
+		if (symbol->info.minfo != NULL) {
+			symlist_free(&symbol->info.minfo->symrefs);
+			free(symbol->info.minfo);
+		}
+		break;
+	case DOWNLOAD_CONST:
+	case CONST:
+		if (symbol->info.cinfo != NULL)
+			free(symbol->info.cinfo);
+		break;
+	case LABEL:
+		if (symbol->info.linfo != NULL)
+			free(symbol->info.linfo);
+		break;
+	case UNINITIALIZED:
+	default:
+		break;
+	}
+	free(symbol->name);
+	free(symbol);
+}
+
+void
+symtable_open()
+{
+	symtable = dbopen(/*filename*/NULL,
+			  O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
+			  /*openinfo*/NULL);
+
+	if (symtable == NULL) {
+		perror("Symbol table creation failed");
+		exit(EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+}
+
+void
+symtable_close()
+{
+	if (symtable != NULL) {
+		DBT	 key;
+		DBT	 data;
+
+		while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
+			symbol_t *stored_ptr;
+
+			memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
+			symbol_delete(stored_ptr);
+		}
+		symtable->close(symtable);
+	}
+}
+
+/*
+ * The semantics of get is to return an uninitialized symbol entry
+ * if a lookup fails.
+ */
+symbol_t *
+symtable_get(char *name)
+{
+	symbol_t *stored_ptr;
+	DBT	  key;
+	DBT	  data;
+	int	  retval;
+
+	key.data = (void *)name;
+	key.size = strlen(name);
+
+	if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
+		if (retval == -1) {
+			perror("Symbol table get operation failed");
+			exit(EX_SOFTWARE);
+			/* NOTREACHED */
+		} else if (retval == 1) {
+			/* Symbol wasn't found, so create a new one */
+			symbol_t *new_symbol;
+
+			new_symbol = symbol_create(name);
+			data.data = &new_symbol;
+			data.size = sizeof(new_symbol);
+			if (symtable->put(symtable, &key, &data,
+					  /*flags*/0) !=0) {
+				perror("Symtable put failed");
+				exit(EX_SOFTWARE);
+			}
+			return (new_symbol);
+		} else {
+			perror("Unexpected return value from db get routine");
+			exit(EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+	}
+	memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
+	return (stored_ptr);
+}
+
+symbol_node_t *
+symlist_search(symlist_t *symlist, char *symname)
+{
+	symbol_node_t *curnode;
+
+	curnode = symlist->slh_first;
+	while(curnode != NULL) {
+		if (strcmp(symname, curnode->symbol->name) == 0)
+			break;
+		curnode = curnode->links.sle_next;
+	}
+	return (curnode);
+}
+
+void
+symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
+{
+	symbol_node_t *newnode;
+
+	newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
+	if (newnode == NULL) {
+		stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	newnode->symbol = symbol;
+	if (how == SYMLIST_SORT) {
+		symbol_node_t *curnode;
+		int mask;
+
+		mask = FALSE;
+		switch(symbol->type) {
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+			break;
+		case BIT:
+		case MASK:
+			mask = TRUE;
+			break;
+		default:
+			stop("symlist_add: Invalid symbol type for sorting",
+			     EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+
+		curnode = symlist->slh_first;
+		if (curnode == NULL
+		 || (mask && (curnode->symbol->info.minfo->mask >
+		              newnode->symbol->info.minfo->mask))
+		 || (!mask && (curnode->symbol->info.rinfo->address >
+		               newnode->symbol->info.rinfo->address))) {
+			SLIST_INSERT_HEAD(symlist, newnode, links);
+			return;
+		}
+
+		while (1) {
+			if (curnode->links.sle_next == NULL) {
+				SLIST_INSERT_AFTER(curnode, newnode,
+						   links);
+				break;
+			} else {
+				symbol_t *cursymbol;
+
+				cursymbol = curnode->links.sle_next->symbol;
+				if ((mask && (cursymbol->info.minfo->mask >
+				              symbol->info.minfo->mask))
+				 || (!mask &&(cursymbol->info.rinfo->address >
+				              symbol->info.rinfo->address))){
+					SLIST_INSERT_AFTER(curnode, newnode,
+							   links);
+					break;
+				}
+			}
+			curnode = curnode->links.sle_next;
+		}
+	} else {
+		SLIST_INSERT_HEAD(symlist, newnode, links);
+	}
+}
+
+void
+symlist_free(symlist_t *symlist)
+{
+	symbol_node_t *node1, *node2;
+
+	node1 = symlist->slh_first;
+	while (node1 != NULL) {
+		node2 = node1->links.sle_next;
+		free(node1);
+		node1 = node2;
+	}
+	SLIST_INIT(symlist);
+}
+
+void
+symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
+	      symlist_t *symlist_src2)
+{
+	symbol_node_t *node;
+
+	*symlist_dest = *symlist_src1;
+	while((node = symlist_src2->slh_first) != NULL) {
+		SLIST_REMOVE_HEAD(symlist_src2, links);
+		SLIST_INSERT_HEAD(symlist_dest, node, links);
+	}
+
+	/* These are now empty */
+	SLIST_INIT(symlist_src1);
+	SLIST_INIT(symlist_src2);
+}
+
+void
+symtable_dump(FILE *ofile)
+{
+	/*
+	 * Sort the registers by address with a simple insertion sort.
+	 * Put bitmasks next to the first register that defines them.
+	 * Put constants at the end.
+	 */
+	symlist_t registers;
+	symlist_t masks;
+	symlist_t constants;
+	symlist_t download_constants;
+	symlist_t aliases;
+
+	SLIST_INIT(&registers);
+	SLIST_INIT(&masks);
+	SLIST_INIT(&constants);
+	SLIST_INIT(&download_constants);
+	SLIST_INIT(&aliases);
+
+	if (symtable != NULL) {
+		DBT	 key;
+		DBT	 data;
+		int	 flag = R_FIRST;
+
+		while (symtable->seq(symtable, &key, &data, flag) == 0) {
+			symbol_t *cursym;
+
+			memcpy(&cursym, data.data, sizeof(cursym));
+			switch(cursym->type) {
+			case REGISTER:
+			case SCBLOC:
+			case SRAMLOC:
+				symlist_add(&registers, cursym, SYMLIST_SORT);
+				break;
+			case MASK:
+			case BIT:
+				symlist_add(&masks, cursym, SYMLIST_SORT);
+				break;
+			case CONST:
+				if (cursym->info.cinfo->define == FALSE) {
+					symlist_add(&constants, cursym,
+						    SYMLIST_INSERT_HEAD);
+				}
+				break;
+			case DOWNLOAD_CONST:
+				symlist_add(&download_constants, cursym,
+					    SYMLIST_INSERT_HEAD);
+				break;
+			case ALIAS:
+				symlist_add(&aliases, cursym,
+					    SYMLIST_INSERT_HEAD);
+				break;
+			default:
+				break;
+			}
+			flag = R_NEXT;
+		}
+
+		/* Put in the masks and bits */
+		while (masks.slh_first != NULL) {
+			symbol_node_t *curnode;
+			symbol_node_t *regnode;
+			char *regname;
+
+			curnode = masks.slh_first;
+			SLIST_REMOVE_HEAD(&masks, links);
+
+			regnode =
+			    curnode->symbol->info.minfo->symrefs.slh_first;
+			regname = regnode->symbol->name;
+			regnode = symlist_search(&registers, regname);
+			SLIST_INSERT_AFTER(regnode, curnode, links);
+		}
+
+		/* Add the aliases */
+		while (aliases.slh_first != NULL) {
+			symbol_node_t *curnode;
+			symbol_node_t *regnode;
+			char *regname;
+
+			curnode = aliases.slh_first;
+			SLIST_REMOVE_HEAD(&aliases, links);
+
+			regname = curnode->symbol->info.ainfo->parent->name;
+			regnode = symlist_search(&registers, regname);
+			SLIST_INSERT_AFTER(regnode, curnode, links);
+		}
+
+		/* Output what we have */
+		fprintf(ofile,
+"/*
+  * DO NOT EDIT - This file is automatically generated.
+  */\n");
+		while (registers.slh_first != NULL) {
+			symbol_node_t *curnode;
+			u_int8_t value;
+			char *tab_str;
+			char *tab_str2;
+
+			curnode = registers.slh_first;
+			SLIST_REMOVE_HEAD(&registers, links);
+			switch(curnode->symbol->type) {
+			case REGISTER:
+			case SCBLOC:
+			case SRAMLOC:
+				fprintf(ofile, "\n");
+				value = curnode->symbol->info.rinfo->address;
+				tab_str = "\t";
+				tab_str2 = "\t\t";
+				break;
+			case ALIAS:
+			{
+				symbol_t *parent;
+
+				parent = curnode->symbol->info.ainfo->parent;
+				value = parent->info.rinfo->address;
+				tab_str = "\t";
+				tab_str2 = "\t\t";
+				break;
+			}
+			case MASK:
+			case BIT:
+				value = curnode->symbol->info.minfo->mask;
+				tab_str = "\t\t";
+				tab_str2 = "\t";
+				break;
+			default:
+				value = 0; /* Quiet compiler */
+				tab_str = NULL;
+				tab_str2 = NULL;
+				stop("symtable_dump: Invalid symbol type "
+				     "encountered", EX_SOFTWARE);
+				break;
+			}
+			fprintf(ofile, "#define%s%-16s%s0x%02x\n",
+				tab_str, curnode->symbol->name, tab_str2,
+				value);
+			free(curnode);
+		}
+		fprintf(ofile, "\n\n");
+
+		while (constants.slh_first != NULL) {
+			symbol_node_t *curnode;
+
+			curnode = constants.slh_first;
+			SLIST_REMOVE_HEAD(&constants, links);
+			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+				curnode->symbol->name,
+				curnode->symbol->info.cinfo->value);
+			free(curnode);
+		}
+
+		
+		fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
+
+		while (download_constants.slh_first != NULL) {
+			symbol_node_t *curnode;
+
+			curnode = download_constants.slh_first;
+			SLIST_REMOVE_HEAD(&download_constants, links);
+			fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+				curnode->symbol->name,
+				curnode->symbol->info.cinfo->value);
+			free(curnode);
+		}
+	}
+}
+
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,177 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.h#4 $
+ *
+ * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.h,v 1.11 2000/09/22 22:19:55 gibbs Exp $
+ */
+
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+typedef enum {
+	UNINITIALIZED,
+	REGISTER,
+	ALIAS,
+	SCBLOC,
+	SRAMLOC,
+	MASK,
+	BIT,
+	CONST,
+	DOWNLOAD_CONST,
+	LABEL,
+	CONDITIONAL
+}symtype;
+
+typedef enum {
+	RO = 0x01,
+	WO = 0x02,
+	RW = 0x03
+}amode_t;
+
+struct reg_info {
+	u_int8_t address;
+	int	 size;
+	amode_t	 mode;
+	u_int8_t valid_bitmask;
+	int	 typecheck_masks;
+};
+
+typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
+
+struct mask_info {
+	symlist_t symrefs;
+	u_int8_t mask;
+};
+
+struct const_info {
+	u_int8_t value;
+	int	 define;
+};
+
+struct alias_info {
+	struct symbol *parent;
+};
+
+struct label_info {
+	int	address;
+};
+
+struct cond_info {
+	int	func_num;
+};
+
+typedef struct expression_info {
+        symlist_t       referenced_syms;
+        int             value;
+} expression_t;
+
+typedef struct symbol {
+	char	*name;
+	symtype	type;
+	union	{
+		struct reg_info *rinfo;
+		struct mask_info *minfo;
+		struct const_info *cinfo;
+		struct alias_info *ainfo;
+		struct label_info *linfo;
+		struct cond_info *condinfo;
+	}info;
+} symbol_t;
+
+typedef struct symbol_ref {
+	symbol_t *symbol;
+	int	 offset;
+} symbol_ref_t;
+
+typedef struct symbol_node {
+	SLIST_ENTRY(symbol_node) links;
+	symbol_t *symbol;
+} symbol_node_t;
+
+typedef struct critical_section {
+	TAILQ_ENTRY(critical_section) links;
+	int begin_addr;
+	int end_addr;
+} critical_section_t;
+
+typedef enum {
+	SCOPE_ROOT,
+	SCOPE_IF,
+	SCOPE_ELSE_IF,
+	SCOPE_ELSE
+} scope_type;
+
+typedef struct patch_info {
+	int skip_patch;
+	int skip_instr;
+} patch_info_t;
+
+typedef struct scope {
+	SLIST_ENTRY(scope) scope_stack_links;
+	TAILQ_ENTRY(scope) scope_links;
+	TAILQ_HEAD(, scope) inner_scope;
+	scope_type type;
+	int inner_scope_patches;
+	int begin_addr;
+        int end_addr;
+	patch_info_t patches[2];
+	int func_num;
+} scope_t;
+
+TAILQ_HEAD(cs_tailq, critical_section);
+SLIST_HEAD(scope_list, scope);
+TAILQ_HEAD(scope_tailq, scope);
+
+void	symbol_delete __P((symbol_t *symbol));
+
+void	symtable_open __P((void));
+
+void	symtable_close __P((void));
+
+symbol_t *
+	symtable_get __P((char *name));
+
+symbol_node_t *
+	symlist_search __P((symlist_t *symlist, char *symname));
+
+void
+	symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
+#define SYMLIST_INSERT_HEAD	0x00
+#define SYMLIST_SORT		0x01
+
+void	symlist_free __P((symlist_t *symlist));
+
+void	symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
+			   symlist_t *symlist_src2));
+void	symtable_dump __P((FILE *ofile));
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/cam.h linux/drivers/scsi/aic7xxx/cam.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/cam.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/cam.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,142 @@
+/*
+ * Data structures and definitions for the CAM system.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 2000 Adaptec Inc.
+ * 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.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/cam.h#9 $
+ */
+
+#ifndef _AIC7XXX_CAM_H
+#define _AIC7XXX_CAM_H 1
+
+/* Provide a mapping from CAM constructs to Linux SCSI constructs */
+
+#define	CAM_BUS_WILDCARD ((u_int)~0)
+#define	CAM_TARGET_WILDCARD ((u_int)~0)
+#define	CAM_LUN_WILDCARD ((u_int)~0)
+
+/* CAM Status field values */
+typedef enum {
+	/* CCB request is in progress */
+	CAM_REQ_INPROG		= 0x3F, /* Some value unused by Linux */
+	/* CCB request completed without error */
+	CAM_REQ_CMP		= DID_OK,
+	/* CCB request aborted by the host */
+	CAM_REQ_ABORTED		= DID_ABORT,
+	/* Unable to abort CCB request */
+	CAM_UA_ABORT		= DID_ERROR,
+	/* CCB request completed with an error */
+	CAM_REQ_CMP_ERR		= DID_ERROR,
+	/* CAM subsytem is busy */
+	CAM_BUSY		= DID_BUS_BUSY,
+	/* CCB request was invalid */
+	CAM_REQ_INVALID		= DID_BAD_TARGET,
+	/* Supplied Path ID is invalid */
+	CAM_PATH_INVALID	= DID_BAD_TARGET,
+	/* Target Selection Timeout */
+	CAM_SEL_TIMEOUT		= DID_NO_CONNECT,
+	/* Command timeout */
+	CAM_CMD_TIMEOUT		= DID_ERROR, /*
+					      * Should never occur in Linux
+					      * as the upper level code
+					      * handles all timeout processing.
+					      */
+	/* SCSI error, look at error code in CCB */
+	CAM_SCSI_STATUS_ERROR	= DID_OK, /* Linux looks at status byte */
+	/* SCSI Bus Reset Sent/Received */
+	CAM_SCSI_BUS_RESET	= DID_RESET,
+	/* Uncorrectable parity error occurred */
+	CAM_UNCOR_PARITY	= DID_PARITY,
+	/* Autosense: request sense cmd fail */
+	CAM_AUTOSENSE_FAIL	= DID_ERROR,
+	/* No HBA Detected Error */
+	CAM_NO_HBA		= DID_ERROR,
+	/* Data Overrun error */
+	CAM_DATA_RUN_ERR	= DID_ERROR,
+	/* Unexpected Bus Free */
+	CAM_UNEXP_BUSFREE	= DID_ERROR,
+	/* CCB length supplied is inadequate */
+	CAM_CCB_LEN_ERR		= DID_ERROR,
+	/* Unable to provide requested capability */
+	CAM_PROVIDE_FAIL	= DID_ERROR,
+	/* A SCSI BDR msg was sent to target */
+	CAM_BDR_SENT		= DID_RESET,
+	/* CCB request terminated by the host */
+	CAM_REQ_TERMIO		= DID_ERROR,
+	/* Unrecoverable Host Bus Adapter Error */
+	CAM_UNREC_HBA_ERROR	= DID_ERROR,
+	/* The request was too large for this host */
+	CAM_REQ_TOO_BIG		= DID_ERROR,
+	/*
+	 * This request should be requeued to preserve
+	 * transaction ordering.  This typically occurs
+	 * when the SIM recognizes an error that should
+	 * freeze the queue and must place additional
+	 * requests for the target at the sim level
+	 * back into the XPT queue.
+	 */
+	CAM_REQUEUE_REQ		= DID_BUS_BUSY,
+	/*
+	 * The transaction has made it through our queue routine.
+	 */
+	CAM_SIM_QUEUED		= 0x200,
+
+	CAM_STATUS_MASK		= 0x3F
+} cam_status;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+#define	SCSI_DATA_READ	1
+#define	SCSI_DATA_WRITE 2
+#define SCSI_DATA_NONE  3
+#endif
+
+/*
+ * Definitions for the asynchronous callback CCB fields.
+ */
+typedef enum {
+	AC_GETDEV_CHANGED	= 0x800,/* Getdev info might have changed */
+	AC_INQ_CHANGED		= 0x400,/* Inquiry info might have changed */
+	AC_TRANSFER_NEG		= 0x200,/* New transfer settings in effect */
+	AC_LOST_DEVICE		= 0x100,/* A device went away */
+	AC_FOUND_DEVICE		= 0x080,/* A new device was found */
+	AC_PATH_DEREGISTERED	= 0x040,/* A path has de-registered */
+	AC_PATH_REGISTERED	= 0x020,/* A new path has been registered */
+	AC_SENT_BDR		= 0x010,/* A BDR message was sent to target */
+	AC_SCSI_AEN		= 0x008,/* A SCSI AEN has been received */
+	AC_UNSOL_RESEL		= 0x002,/* Unsolicited reselection occurred */
+	AC_BUS_RESET		= 0x001 /* A SCSI bus reset occurred */
+} ac_code;
+
+typedef enum {
+	CAM_DIR_IN		= SCSI_DATA_READ,
+	CAM_DIR_OUT		= SCSI_DATA_WRITE,
+	CAM_DIR_NONE		= SCSI_DATA_NONE
+} ccb_flags;
+
+#endif /* _AIC7XXX_CAM_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/queue.h linux/drivers/scsi/aic7xxx/queue.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/queue.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx/queue.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.38 2000/05/26 02:06:56 jake Exp $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *			SLIST	LIST	STAILQ	TAILQ	CIRCLEQ
+ * _HEAD		+	+	+	+	+
+ * _HEAD_INITIALIZER	+	+	+	+	+
+ * _ENTRY		+	+	+	+	+
+ * _INIT		+	+	+	+	+
+ * _EMPTY		+	+	+	+	+
+ * _FIRST		+	+	+	+	+
+ * _NEXT		+	+	+	+	+
+ * _PREV		-	-	-	+	+
+ * _LAST		-	-	+	+	+
+ * _FOREACH		+	+	+	+	+
+ * _FOREACH_REVERSE	-	-	-	+	+
+ * _INSERT_HEAD		+	+	+	+	+
+ * _INSERT_BEFORE	-	+	-	+	+
+ * _INSERT_AFTER	+	+	+	+	+
+ * _INSERT_TAIL		-	-	+	+	+
+ * _REMOVE_HEAD		+	-	+	-	-
+ * _REMOVE		+	+	+	+	+
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+ 
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+ 
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_NEXT(curelm, field) =				\
+		    SLIST_NEXT(SLIST_NEXT(curelm, field), field);	\
+	}								\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	STAILQ_LAST((head)) = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head)	(*(head)->stqh_last)
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD(head, field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		if ((STAILQ_NEXT(curelm, field) =			\
+		     STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+			(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+	}								\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {			\
+	if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Circular queue declarations.
+ */
+#define	CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define	CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ (void *)&(head), (void *)&(head) }
+
+#define	CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_EMPTY(head)	((head)->cqh_first == (void *)(head))
+
+#define	CIRCLEQ_FIRST(head)	((head)->cqh_first)
+
+#define	CIRCLEQ_FOREACH(var, head, field)				\
+	for ((var) = CIRCLEQ_FIRST((head));				\
+	    (var) != (void *)(head);					\
+	    (var) = CIRCLEQ_NEXT((var), field))
+
+#define	CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for ((var) = CIRCLEQ_LAST((head));				\
+	    (var) != (void *)(head);					\
+	    (var) = CIRCLEQ_PREV((var), field))
+
+#define	CIRCLEQ_INIT(head) do {						\
+	CIRCLEQ_FIRST((head)) = (void *)(head);				\
+	CIRCLEQ_LAST((head)) = (void *)(head);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field);	\
+	CIRCLEQ_PREV((elm), field) = (listelm);				\
+	if (CIRCLEQ_NEXT((listelm), field) == (void *)(head))		\
+		CIRCLEQ_LAST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
+	CIRCLEQ_NEXT((listelm), field) = (elm);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	CIRCLEQ_NEXT((elm), field) = (listelm);				\
+	CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field);	\
+	if (CIRCLEQ_PREV((listelm), field) == (void *)(head))		\
+		CIRCLEQ_FIRST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
+	CIRCLEQ_PREV((listelm), field) = (elm);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head));		\
+	CIRCLEQ_PREV((elm), field) = (void *)(head);			\
+	if (CIRCLEQ_LAST((head)) == (void *)(head))			\
+		CIRCLEQ_LAST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm);	\
+	CIRCLEQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	CIRCLEQ_NEXT((elm), field) = (void *)(head);			\
+	CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head));		\
+	if (CIRCLEQ_FIRST((head)) == (void *)(head))			\
+		CIRCLEQ_FIRST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm);	\
+	CIRCLEQ_LAST((head)) = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_LAST(head)	((head)->cqh_last)
+
+#define	CIRCLEQ_NEXT(elm,field)	((elm)->field.cqe_next)
+
+#define	CIRCLEQ_PREV(elm,field)	((elm)->field.cqe_prev)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	if (CIRCLEQ_NEXT((elm), field) == (void *)(head))		\
+		CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field);	\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) =	\
+		    CIRCLEQ_PREV((elm), field);				\
+	if (CIRCLEQ_PREV((elm), field) == (void *)(head))		\
+		CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field);	\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) =	\
+		    CIRCLEQ_NEXT((elm), field);				\
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/scsi_message.h linux/drivers/scsi/aic7xxx/scsi_message.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/scsi_message.h	Wed Jun  9 16:59:15 1999
+++ linux/drivers/scsi/aic7xxx/scsi_message.h	Sun Mar  4 14:30:18 2001
@@ -1,34 +1,52 @@
+/*
+ * This file is in the public domain.
+ * $FreeBSD: src/sys/cam/scsi/scsi_message.h,v 1.2 2000/05/01 20:21:29 peter Exp $
+ */
+
 /* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
 #define MSG_CMDCOMPLETE		0x00 /* M/M */
+#define MSG_TASK_COMPLETE	0x00 /* M/M */ /* SPI3 Terminology */
 #define MSG_EXTENDED		0x01 /* O/O */
 #define MSG_SAVEDATAPOINTER	0x02 /* O/O */
 #define MSG_RESTOREPOINTERS	0x03 /* O/O */
 #define MSG_DISCONNECT		0x04 /* O/O */
 #define MSG_INITIATOR_DET_ERR	0x05 /* M/M */
 #define MSG_ABORT		0x06 /* O/M */
+#define MSG_ABORT_TASK_SET	0x06 /* O/M */ /* SPI3 Terminology */
 #define MSG_MESSAGE_REJECT	0x07 /* M/M */
 #define MSG_NOOP		0x08 /* M/M */
 #define MSG_PARITY_ERROR	0x09 /* M/M */
 #define MSG_LINK_CMD_COMPLETE	0x0a /* O/O */
 #define MSG_LINK_CMD_COMPLETEF	0x0b /* O/O */
 #define MSG_BUS_DEV_RESET	0x0c /* O/M */
+#define MSG_TARGET_RESET	0x0c /* O/M */ /* SPI3 Terminology */
 #define MSG_ABORT_TAG		0x0d /* O/O */
+#define MSG_ABORT_TASK		0x0d /* O/O */ /* SPI3 Terminology */
 #define MSG_CLEAR_QUEUE		0x0e /* O/O */
-#define MSG_INIT_RECOVERY	0x0f /* O/O */
-#define MSG_REL_RECOVERY	0x10 /* O/O */
-#define MSG_TERM_IO_PROC	0x11 /* O/O */
+#define MSG_CLEAR_TASK_SET	0x0e /* O/O */ /* SPI3 Terminology */
+#define MSG_INIT_RECOVERY	0x0f /* O/O */ /* Deprecated in SPI3 */
+#define MSG_REL_RECOVERY	0x10 /* O/O */ /* Deprecated in SPI3 */
+#define MSG_TERM_IO_PROC	0x11 /* O/O */ /* Deprecated in SPI3 */
+#define MSG_CLEAR_ACA		0x16 /* O/O */ /* SPI3 */
+#define MSG_LOGICAL_UNIT_RESET	0x17 /* O/O */ /* SPI3 */
+#define MSG_QAS_REQUEST		0x55 /* O/O */ /* SPI3 */
 
 /* Messages (2 byte) */
 #define MSG_SIMPLE_Q_TAG	0x20 /* O/O */
+#define MSG_SIMPLE_TASK		0x20 /* O/O */ /* SPI3 Terminology */
 #define MSG_HEAD_OF_Q_TAG	0x21 /* O/O */
+#define MSG_HEAD_OF_QUEUE_TASK	0x21 /* O/O */ /* SPI3 Terminology */
 #define MSG_ORDERED_Q_TAG	0x22 /* O/O */
+#define MSG_ORDERED_TASK	0x22 /* O/O */ /* SPI3 Terminology */
 #define MSG_IGN_WIDE_RESIDUE	0x23 /* O/O */
+#define MSG_ACA_TASK		0x24 /* 0/0 */ /* SPI3 */
 
 /* Identify message */		     /* M/M */	
 #define MSG_IDENTIFYFLAG	0x80 
 #define MSG_IDENTIFY_DISCFLAG	0x40 
 #define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
 #define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
+#define MSG_IDENTIFY_LUNMASK	0x03F 
 
 /* Extended messages (opcode and length) */
 #define MSG_EXT_SDTR		0x01
@@ -38,12 +56,10 @@
 #define MSG_EXT_WDTR_LEN	0x02
 #define MSG_EXT_WDTR_BUS_8_BIT	0x00
 #define MSG_EXT_WDTR_BUS_16_BIT	0x01
-#define MSG_EXT_WDTR_BUS_32_BIT	0x02
+#define MSG_EXT_WDTR_BUS_32_BIT	0x02 /* Deprecated in SPI3 */
 
-#define MSG_EXT_PPR     0x04
-#define MSG_EXT_PPR_LEN	0x06
-#define MSG_EXT_PPR_OPTION_ST 0x00
-#define MSG_EXT_PPR_OPTION_DT_CRC 0x02
-#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03
-#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04
-#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05
+#define MSG_EXT_PPR		0x04 /* SPI3 */
+#define MSG_EXT_PPR_LEN		0x06
+#define MSG_EXT_PPR_QAS_REQ	0x04
+#define MSG_EXT_PPR_DT_REQ	0x02
+#define MSG_EXT_PPR_IU_REQ	0x01
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h
--- v2.4.2/linux/drivers/scsi/aic7xxx/sequencer.h	Sun Nov  8 13:20:14 1998
+++ linux/drivers/scsi/aic7xxx/sequencer.h	Wed Dec 31 16:00:00 1969
@@ -1,135 +0,0 @@
-/*
- * Instruction formats for the sequencer program downloaded to
- * Aic7xxx SCSI host adapters
- *
- * Copyright (c) 1997, 1998 Justin T. Gibbs.
- * 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. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
- */
-
-#ifdef __LITTLE_ENDIAN_BITFIELD
-struct ins_format1 {
-	unsigned int
-			immediate	: 8,
-			source		: 9,
-			destination	: 9,
-			ret		: 1,
-			opcode		: 4,
-			parity		: 1;
-};
-
-struct ins_format2 {
-	unsigned int
-			shift_control	: 8,
-			source		: 9,
-			destination	: 9,
-			ret		: 1,
-			opcode		: 4,
-			parity		: 1;
-};
-
-struct ins_format3 {
-	unsigned int
-			immediate	: 8,
-			source		: 9,
-			address		: 10,
-			opcode		: 4,
-			parity		: 1;
-};
-#elif defined(__BIG_ENDIAN_BITFIELD)
-struct ins_format1 {
-	unsigned int
-			parity		: 1,
-			opcode		: 4,
-			ret		: 1,
-			destination	: 9,
-			source		: 9,
-			immediate	: 8;
-};
-
-struct ins_format2 {
-	unsigned int
-			parity		: 1,
-			opcode		: 4,
-			ret		: 1,
-			destination	: 9,
-			source		: 9,
-			shift_control	: 8;
-};
-
-struct ins_format3 {
-	unsigned int
-			parity		: 1,
-			opcode		: 4,
-			address		: 10,
-			source		: 9,
-			immediate	: 8;
-};
-#endif
-
-union ins_formats {
-		struct ins_format1 format1;
-		struct ins_format2 format2;
-		struct ins_format3 format3;
-		unsigned char	   bytes[4];
-		unsigned int	   integer;
-};
-struct instruction {
-	union	ins_formats format;
-	unsigned int	srcline;
-	struct symbol *patch_label;
-  struct {
-    struct instruction *stqe_next;
-  } links;
-};
-
-#define	AIC_OP_OR	0x0
-#define	AIC_OP_AND	0x1
-#define AIC_OP_XOR	0x2
-#define	AIC_OP_ADD	0x3
-#define	AIC_OP_ADC	0x4
-#define	AIC_OP_ROL	0x5
-#define	AIC_OP_BMOV	0x6
-
-#define	AIC_OP_JMP	0x8
-#define AIC_OP_JC	0x9
-#define AIC_OP_JNC	0xa
-#define AIC_OP_CALL	0xb
-#define	AIC_OP_JNE	0xc
-#define	AIC_OP_JNZ	0xd
-#define	AIC_OP_JE	0xe
-#define	AIC_OP_JZ	0xf
-
-/* Pseudo Ops */
-#define	AIC_OP_SHL	0x10
-#define	AIC_OP_SHR	0x20
-#define	AIC_OP_ROR	0x30
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.4.2/linux/drivers/scsi/aic7xxx.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/aic7xxx.c	Wed Dec 31 16:00:00 1969
@@ -1,12242 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux.
- *
- * Copyright (c) 1994 John Aycock
- *   The University of Calgary Department of Computer Science.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
- * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
- * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
- * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
- * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
- * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
- * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
- * ANSI SCSI-2 specification (draft 10c), ...
- *
- * --------------------------------------------------------------------------
- *
- *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
- *
- *  Substantially modified to include support for wide and twin bus
- *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
- *  SCB paging, and other rework of the code.
- *
- *  Parts of this driver were also based on the FreeBSD driver by
- *  Justin T. Gibbs.  His copyright follows:
- *
- * --------------------------------------------------------------------------  
- * Copyright (c) 1994-1997 Justin Gibbs.
- * 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.
- *
- * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
- *
- *      $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
- *---------------------------------------------------------------------------
- *
- *  Thanks also go to (in alphabetical order) the following:
- *
- *    Rory Bolt     - Sequencer bug fixes
- *    Jay Estabrook - Initial DEC Alpha support
- *    Doug Ledford  - Much needed abort/reset bug fixes
- *    Kai Makisara  - DMAing of SCBs
- *
- *  A Boot time option was also added for not resetting the scsi bus.
- *
- *    Form:  aic7xxx=extended
- *           aic7xxx=no_reset
- *           aic7xxx=ultra
- *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
- *           aic7xxx=verbose
- *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
- *
- *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
- *-M*************************************************************************/
-
-/*+M**************************************************************************
- *
- * Further driver modifications made by Doug Ledford <dledford@redhat.com>
- *
- * Copyright (c) 1997-1999 Doug Ledford
- *
- * These changes are released under the same licensing terms as the FreeBSD
- * driver written by Justin Gibbs.  Please see his Copyright notice above
- * for the exact terms and conditions covering my changes as well as the
- * warranty statement.
- *
- * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
- * but are not limited to:
- *
- *  1: Import of the latest FreeBSD sequencer code for this driver
- *  2: Modification of kernel code to accomodate different sequencer semantics
- *  3: Extensive changes throughout kernel portion of driver to improve
- *     abort/reset processing and error hanndling
- *  4: Other work contributed by various people on the Internet
- *  5: Changes to printk information and verbosity selection code
- *  6: General reliability related changes, especially in IRQ management
- *  7: Modifications to the default probe/attach order for supported cards
- *  8: SMP friendliness has been improved
- *
- * Overall, this driver represents a significant departure from the official
- * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
- * itself.  A diff between the two version of the driver is now a several
- * thousand line diff.  Second, in approach to solving the same problem.  The
- * problem is importing the FreeBSD aic7xxx driver code to linux can be a
- * difficult and time consuming process, that also can be error prone.  Dan
- * Eischen's official driver uses the approach that the linux and FreeBSD
- * drivers should be as identical as possible.  To that end, his next version
- * of this driver will be using a mid-layer code library that he is developing
- * to moderate communications between the linux mid-level SCSI code and the
- * low level FreeBSD driver.  He intends to be able to essentially drop the
- * FreeBSD driver into the linux kernel with only a few minor tweaks to some
- * include files and the like and get things working, making for fast easy
- * imports of the FreeBSD code into linux.
- *
- * I disagree with Dan's approach.  Not that I don't think his way of doing
- * things would be nice, easy to maintain, and create a more uniform driver
- * between FreeBSD and Linux.  I have no objection to those issues.  My
- * disagreement is on the needed functionality.  There simply are certain
- * things that are done differently in FreeBSD than linux that will cause
- * problems for this driver regardless of any middle ware Dan implements.
- * The biggest example of this at the moment is interrupt semantics.  Linux
- * doesn't provide the same protection techniques as FreeBSD does, nor can
- * they be easily implemented in any middle ware code since they would truly
- * belong in the kernel proper and would effect all drivers.  For the time
- * being, I see issues such as these as major stumbling blocks to the 
- * reliability of code based upon such middle ware.  Therefore, I choose to
- * use a different approach to importing the FreeBSD code that doesn't
- * involve any middle ware type code.  My approach is to import the sequencer
- * code from FreeBSD wholesale.  Then, to only make changes in the kernel
- * portion of the driver as they are needed for the new sequencer semantics.
- * In this way, the portion of the driver that speaks to the rest of the
- * linux kernel is fairly static and can be changed/modified to solve
- * any problems one might encounter without concern for the FreeBSD driver.
- *
- * Note: If time and experience should prove me wrong that the middle ware
- * code Dan writes is reliable in its operation, then I'll retract my above
- * statements.  But, for those that don't know, I'm from Missouri (in the US)
- * and our state motto is "The Show-Me State".  Well, before I will put
- * faith into it, you'll have to show me that it works :)
- *
- *_M*************************************************************************/
-
-/*
- * The next three defines are user configurable.  These should be the only
- * defines a user might need to get in here and change.  There are other
- * defines buried deeper in the code, but those really shouldn't need touched
- * under normal conditions.
- */
-
-/*
- * AIC7XXX_STRICT_PCI_SETUP
- *   Should we assume the PCI config options on our controllers are set with
- *   sane and proper values, or should we be anal about our PCI config
- *   registers and force them to what we want?  The main advantage to
- *   defining this option is on non-Intel hardware where the BIOS may not
- *   have been run to set things up, or if you have one of the BIOSless
- *   Adaptec controllers, such as a 2910, that don't get set up by the
- *   BIOS.  However, keep in mind that we really do set the most important
- *   items in the driver regardless of this setting, this only controls some
- *   of the more esoteric PCI options on these cards.  In that sense, I
- *   would default to leaving this off.  However, if people wish to try
- *   things both ways, that would also help me to know if there are some
- *   machines where it works one way but not another.
- *
- *   -- July 7, 17:09
- *     OK...I need this on my machine for testing, so the default is to
- *     leave it defined.
- *
- *   -- July 7, 18:49
- *     I needed it for testing, but it didn't make any difference, so back
- *     off she goes.
- *
- *   -- July 16, 23:04
- *     I turned it back on to try and compensate for the 2.1.x PCI code
- *     which no longer relies solely on the BIOS and now tries to set
- *     things itself.
- */
-
-#define AIC7XXX_STRICT_PCI_SETUP
-
-/*
- * AIC7XXX_VERBOSE_DEBUGGING
- *   This option enables a lot of extra printk();s in the code, surrounded
- *   by if (aic7xxx_verbose ...) statements.  Executing all of those if
- *   statements and the extra checks can get to where it actually does have
- *   an impact on CPU usage and such, as well as code size.  Disabling this
- *   define will keep some of those from becoming part of the code.
- *
- *   NOTE:  Currently, this option has no real effect, I will be adding the
- *   various #ifdef's in the code later when I've decided a section is
- *   complete and no longer needs debugging.  OK...a lot of things are now
- *   surrounded by this define, so turning this off does have an impact.
- */
- 
-/*
- * #define AIC7XXX_VERBOSE_DEBUGGING
- */
- 
-#if defined(MODULE) || defined(PCMCIA)
-#include <linux/module.h>
-#endif
-
-#if defined(PCMCIA)
-#  undef MODULE
-#endif
-
-#include <stdarg.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <linux/version.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/blk.h>
-#include <linux/tqueue.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp.h>
-#include "sd.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "aic7xxx.h"
-
-#include "aic7xxx/sequencer.h"
-#include "aic7xxx/scsi_message.h"
-#include "aic7xxx_reg.h"
-#include <scsi/scsicam.h>
-
-#include <linux/stat.h>
-#include <linux/slab.h>        /* for kmalloc() */
-
-#include <linux/config.h>        /* for CONFIG_PCI */
-
-/*
- * To generate the correct addresses for the controller to issue
- * on the bus.  Originally added for DEC Alpha support.
- */
-#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-
-#define AIC7XXX_C_VERSION  "5.2.1"
-
-#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
-#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
-#define ALL_TARGETS -1
-#define ALL_CHANNELS -1
-#define ALL_LUNS -1
-#define MAX_TARGETS  16
-#define MAX_LUNS     8
-#ifndef TRUE
-#  define TRUE 1
-#endif
-#ifndef FALSE
-#  define FALSE 0
-#endif
-
-#if defined(__powerpc__) || defined(__i386__)
-#  define MMAPIO
-#endif
-
-#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-#    define cpuid smp_processor_id()
-#    define DRIVER_LOCK_INIT \
-       spin_lock_init(&p->spin_lock);
-#    define DRIVER_LOCK \
-       if(!p->cpu_lock_count[cpuid]) { \
-         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
-         p->cpu_lock_count[cpuid]++; \
-       } else { \
-         p->cpu_lock_count[cpuid]++; \
-       }
-#    define DRIVER_UNLOCK \
-       if(--p->cpu_lock_count[cpuid] == 0) \
-         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
-#  else
-#    define DRIVER_LOCK_INIT
-#    define DRIVER_LOCK
-#    define DRIVER_UNLOCK
-#  endif
-
-/*
- * You can try raising me if tagged queueing is enabled, or lowering
- * me if you only have 4 SCBs.
- */
-#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
-#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
-#else
-#define AIC7XXX_CMDS_PER_DEVICE 8
-#endif
-
-/*
- * Control collection of SCSI transfer statistics for the /proc filesystem.
- *
- * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
- * NOTE: This does affect performance since it has to maintain statistics.
- */
-#ifdef CONFIG_AIC7XXX_PROC_STATS
-#define AIC7XXX_PROC_STATS
-#endif
-
-/*
- * *** Determining commands per LUN ***
- * 
- * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
- * own algorithm to determine the commands/LUN.  If SCB paging is
- * enabled, which is always now, the default is 8 commands per lun
- * that indicates it supports tagged queueing.  All non-tagged devices
- * use an internal queue depth of 3, with no more than one of those
- * three commands active at one time.
- */
-
-typedef struct
-{
-  unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
-} adapter_tag_info_t;
-
-/*
- * Make a define that will tell the driver not to use tagged queueing
- * by default.
- */
-#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
-                              0, 0, 0, 0, 0, 0, 0, 0}
-#else
-#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
-                              255, 255, 255, 255, 255, 255, 255, 255}
-#endif
-
-/*
- * Modify this as you see fit for your system.  By setting tag_commands
- * to 0, the driver will use it's own algorithm for determining the
- * number of commands to use (see above).  When 255, the driver will
- * not enable tagged queueing for that particular device.  When positive
- * (> 0) and (< 255) the values in the array are used for the queue_depth.
- * Note that the maximum value for an entry is 254, but you're insane if
- * you try to use that many commands on one device.
- *
- * In this example, the first line will disable tagged queueing for all
- * the devices on the first probed aic7xxx adapter.
- *
- * The second line enables tagged queueing with 4 commands/LUN for IDs
- * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
- * driver to use its own algorithm for ID 1.
- *
- * The third line is the same as the first line.
- *
- * The fourth line disables tagged queueing for devices 0 and 3.  It
- * enables tagged queueing for the other IDs, with 16 commands/LUN
- * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
- * IDs 2, 5-7, and 9-15.
- */
-
-/*
- * NOTE: The below structure is for reference only, the actual structure
- *       to modify in order to change things is found after this fake one.
- *
-adapter_tag_info_t aic7xxx_tag_info[] =
-{
-  {DEFAULT_TAG_COMMANDS},
-  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
-  {DEFAULT_TAG_COMMANDS},
-  {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
-};
-*/
-
-static adapter_tag_info_t aic7xxx_tag_info[] =
-{
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS}
-};
-
-
-/*
- * Define an array of board names that can be indexed by aha_type.
- * Don't forget to change this when changing the types!
- */
-static const char *board_names[] = {
-  "AIC-7xxx Unknown",                                   /* AIC_NONE */
-  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
-  "Adaptec AIC-7770 SCSI host adapter",                 /* AIC_7770 */
-  "Adaptec AHA-274X SCSI host adapter",                 /* AIC_7771 */
-  "Adaptec AHA-284X SCSI host adapter",                 /* AIC_284x */
-  "Adaptec AIC-7850 SCSI host adapter",                 /* AIC_7850 */
-  "Adaptec AIC-7855 SCSI host adapter",                 /* AIC_7855 */
-  "Adaptec AIC-7860 Ultra SCSI host adapter",           /* AIC_7860 */
-  "Adaptec AHA-2940A Ultra SCSI host adapter",          /* AIC_7861 */
-  "Adaptec AIC-7870 SCSI host adapter",                 /* AIC_7870 */
-  "Adaptec AHA-294X SCSI host adapter",                 /* AIC_7871 */
-  "Adaptec AHA-394X SCSI host adapter",                 /* AIC_7872 */
-  "Adaptec AHA-398X SCSI host adapter",                 /* AIC_7873 */
-  "Adaptec AHA-2944 SCSI host adapter",                 /* AIC_7874 */
-  "Adaptec AIC-7880 Ultra SCSI host adapter",           /* AIC_7880 */
-  "Adaptec AHA-294X Ultra SCSI host adapter",           /* AIC_7881 */
-  "Adaptec AHA-394X Ultra SCSI host adapter",           /* AIC_7882 */
-  "Adaptec AHA-398X Ultra SCSI host adapter",           /* AIC_7883 */
-  "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
-  "Adaptec AHA-2940UW Pro Ultra SCSI host adapter",     /* AIC_7887 */
-  "Adaptec AIC-7895 Ultra SCSI host adapter",           /* AIC_7895 */
-  "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
-  "Adaptec AHA-293X Ultra2 SCSI host adapter",          /* AIC_7890 */
-  "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
-  "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
-  "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
-  "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
-  "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
-  "Adaptec AIC-7892 Ultra 160/m SCSI host adapter",     /* AIC_7892 */
-  "Adaptec AIC-7899 Ultra 160/m SCSI host adapter",     /* AIC_7899 */
-};
-
-/*
- * There should be a specific return value for this in scsi.h, but
- * it seems that most drivers ignore it.
- */
-#define DID_UNDERFLOW   DID_ERROR
-
-/*
- *  What we want to do is have the higher level scsi driver requeue
- *  the command to us. There is no specific driver status for this
- *  condition, but the higher level scsi driver will requeue the
- *  command on a DID_BUS_BUSY error.
- *
- *  Upon further inspection and testing, it seems that DID_BUS_BUSY
- *  will *always* retry the command.  We can get into an infinite loop
- *  if this happens when we really want some sort of counter that
- *  will automatically abort/reset the command after so many retries.
- *  Using DID_ERROR will do just that.  (Made by a suggestion by
- *  Doug Ledford 8/1/96)
- */
-#define DID_RETRY_COMMAND DID_ERROR
-
-#define HSCSIID        0x07
-#define SCSI_RESET     0x040
-
-/*
- * EISA/VL-bus stuff
- */
-#define MINSLOT                1
-#define MAXSLOT                15
-#define SLOTBASE(x)        ((x) << 12)
-#define BASE_TO_SLOT(x) ((x) >> 12)
-
-/*
- * Standard EISA Host ID regs  (Offset from slot base)
- */
-#define AHC_HID0              0x80   /* 0,1: msb of ID2, 2-7: ID1      */
-#define AHC_HID1              0x81   /* 0-4: ID3, 5-7: LSB ID2         */
-#define AHC_HID2              0x82   /* product                        */
-#define AHC_HID3              0x83   /* firmware revision              */
-
-/*
- * AIC-7770 I/O range to reserve for a card
- */
-#define MINREG                0xC00
-#define MAXREG                0xCFF
-
-#define INTDEF                0x5C      /* Interrupt Definition Register */
-
-/*
- * AIC-78X0 PCI registers
- */
-#define        CLASS_PROGIF_REVID        0x08
-#define                DEVREVID        0x000000FFul
-#define                PROGINFC        0x0000FF00ul
-#define                SUBCLASS        0x00FF0000ul
-#define                BASECLASS        0xFF000000ul
-
-#define        CSIZE_LATTIME                0x0C
-#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
-#define                LATTIME                0x0000FF00ul
-
-#define        DEVCONFIG                0x40
-#define                SCBSIZE32        0x00010000ul        /* aic789X only */
-#define                MPORTMODE        0x00000400ul        /* aic7870 only */
-#define                RAMPSM           0x00000200ul        /* aic7870 only */
-#define                RAMPSM_ULTRA2    0x00000004
-#define                VOLSENSE         0x00000100ul
-#define                SCBRAMSEL        0x00000080ul
-#define                SCBRAMSEL_ULTRA2 0x00000008
-#define                MRDCEN           0x00000040ul
-#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
-#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
-#define                BERREN           0x00000008ul
-#define                DACEN            0x00000004ul
-#define                STPWLEVEL        0x00000002ul
-#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
-
-#define        SCAMCTL                  0x1a                /* Ultra2 only  */
-#define        CCSCBBADDR               0xf0                /* aic7895/6/7  */
-
-/*
- * Define the different types of SEEPROMs on aic7xxx adapters
- * and make it also represent the address size used in accessing
- * its registers.  The 93C46 chips have 1024 bits organized into
- * 64 16-bit words, while the 93C56 chips have 2048 bits organized
- * into 128 16-bit words.  The C46 chips use 6 bits to address
- * each word, while the C56 and C66 (4096 bits) use 8 bits to
- * address each word.
- */
-typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
-
-/*
- *
- * Define the format of the SEEPROM registers (16 bits).
- *
- */
-struct seeprom_config {
-
-/*
- * SCSI ID Configuration Flags
- */
-#define CFXFER                0x0007      /* synchronous transfer rate */
-#define CFSYNCH               0x0008      /* enable synchronous transfer */
-#define CFDISC                0x0010      /* enable disconnection */
-#define CFWIDEB               0x0020      /* wide bus device (wide card) */
-#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
-#define CFNEWULTRAFORMAT      0x0080      /* Use the Ultra2 SEEPROM format */
-#define CFSTART               0x0100      /* send start unit SCSI command */
-#define CFINCBIOS             0x0200      /* include in BIOS scan */
-#define CFRNFOUND             0x0400      /* report even if not found */
-#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
-#define CFWBCACHEYES          0x4000      /* Enable W-Behind Cache on drive */
-#define CFWBCACHENC           0xc000      /* Don't change W-Behind Cache */
-/* UNUSED                0x3000 */
-  unsigned short device_flags[16];        /* words 0-15 */
-
-/*
- * BIOS Control Bits
- */
-#define CFSUPREM        0x0001  /* support all removable drives */
-#define CFSUPREMB       0x0002  /* support removable drives for boot only */
-#define CFBIOSEN        0x0004  /* BIOS enabled */
-/* UNUSED                0x0008 */
-#define CFSM2DRV        0x0010  /* support more than two drives */
-#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
-/* UNUSED                0x0040 */
-#define CFEXTEND        0x0080  /* extended translation enabled */
-/* UNUSED                0xFF00 */
-  unsigned short bios_control;  /* word 16 */
-
-/*
- * Host Adapter Control Bits
- */
-#define CFAUTOTERM      0x0001  /* Perform Auto termination */
-#define CFULTRAEN       0x0002  /* Ultra SCSI speed enable (Ultra cards) */
-#define CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
-#define CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
-#define CFSTERM         0x0004  /* SCSI low byte termination */
-#define CFWSTERM        0x0008  /* SCSI high byte termination (wide card) */
-#define CFSPARITY       0x0010  /* SCSI parity */
-#define CF284XSTERM     0x0020  /* SCSI low byte termination (284x cards) */
-#define CFRESETB        0x0040  /* reset SCSI bus at boot */
-#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
-#define CFSEAUTOTERM    0x0400  /* aic7890 Perform SE Auto Term */
-#define CFLVDSTERM      0x0800  /* aic7890 LVD Termination */
-/* UNUSED                0xF280 */
-  unsigned short adapter_control;        /* word 17 */
-
-/*
- * Bus Release, Host Adapter ID
- */
-#define CFSCSIID        0x000F                /* host adapter SCSI ID */
-/* UNUSED                0x00F0 */
-#define CFBRTIME        0xFF00                /* bus release time */
-  unsigned short brtime_id;                /* word 18 */
-
-/*
- * Maximum targets
- */
-#define CFMAXTARG        0x00FF        /* maximum targets */
-/* UNUSED                0xFF00 */
-  unsigned short max_targets;                /* word 19 */
-
-  unsigned short res_1[11];                /* words 20-30 */
-  unsigned short checksum;                /* word 31 */
-};
-
-#define SELBUS_MASK                0x0a
-#define         SELNARROW        0x00
-#define         SELBUSB                0x08
-#define SINGLE_BUS                0x00
-
-#define SCB_TARGET(scb)         \
-       (((scb)->hscb->target_channel_lun & TID) >> 4)
-#define SCB_LUN(scb)            \
-       ((scb)->hscb->target_channel_lun & LID)
-#define SCB_IS_SCSIBUS_B(scb)   \
-       (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
-
-/*
- * If an error occurs during a data transfer phase, run the command
- * to completion - it's easier that way - making a note of the error
- * condition in this location. This then will modify a DID_OK status
- * into an appropriate error for the higher-level SCSI code.
- */
-#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
-
-/*
- * Keep track of the targets returned status.
- */
-#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
-
-/*
- * The position of the SCSI commands scb within the scb array.
- */
-#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
-
-/*
- * The stored DMA mapping for single-buffer data transfers.
- */
-#define aic7xxx_mapping(cmd)	     ((cmd)->SCp.phase)
-
-/*
- * So we can keep track of our host structs
- */
-static struct aic7xxx_host *first_aic7xxx = NULL;
-
-/*
- * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
- * in the scatter-gather lists.  We need to convert the virtual
- * addresses to physical addresses.
- */
-struct hw_scatterlist {
-  unsigned int address;
-  unsigned int length;
-};
-
-/*
- * Maximum number of SG segments these cards can support.
- */
-#define        AIC7XXX_MAX_SG 128
-
-/*
- * The maximum number of SCBs we could have for ANY type
- * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
- * SEQUENCER CODE IF THIS IS MODIFIED!
- */
-#define AIC7XXX_MAXSCB        255
-
-
-struct aic7xxx_hwscb {
-/* ------------    Begin hardware supported fields    ---------------- */
-/* 0*/  unsigned char control;
-/* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
-/* 2*/  unsigned char target_status;
-/* 3*/  unsigned char SG_segment_count;
-/* 4*/  unsigned int  SG_list_pointer;
-/* 8*/  unsigned char residual_SG_segment_count;
-/* 9*/  unsigned char residual_data_count[3];
-/*12*/  unsigned int  data_pointer;
-/*16*/  unsigned int  data_count;
-/*20*/  unsigned int  SCSI_cmd_pointer;
-/*24*/  unsigned char SCSI_cmd_length;
-/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
-                                     * Also used as the tag for tagged I/O
-                                     */
-#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
-                                     * via PIO to initialize a transaction.
-                                     */
-/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
-                                     * or disconnected down in the sequencer.
-                                     */
-/*27*/  unsigned char prev;
-/*28*/  unsigned int pad;           /*
-                                     * Unused by the kernel, but we require
-                                     * the padding so that the array of
-                                     * hardware SCBs is alligned on 32 byte
-                                     * boundaries so the sequencer can index
-                                     */
-};
-
-typedef enum {
-        SCB_FREE                = 0x0000,
-        SCB_WAITINGQ            = 0x0002,
-        SCB_ACTIVE              = 0x0004,
-        SCB_SENSE               = 0x0008,
-        SCB_ABORT               = 0x0010,
-        SCB_DEVICE_RESET        = 0x0020,
-        SCB_RESET               = 0x0040,
-        SCB_RECOVERY_SCB        = 0x0080,
-        SCB_MSGOUT_PPR          = 0x0100,
-        SCB_MSGOUT_SENT         = 0x0200,
-        SCB_MSGOUT_SDTR         = 0x0400,
-        SCB_MSGOUT_WDTR         = 0x0800,
-        SCB_MSGOUT_BITS         = SCB_MSGOUT_PPR |
-                                  SCB_MSGOUT_SENT | 
-                                  SCB_MSGOUT_SDTR |
-                                  SCB_MSGOUT_WDTR,
-        SCB_QUEUED_ABORT        = 0x1000,
-        SCB_QUEUED_FOR_DONE     = 0x2000,
-        SCB_WAS_BUSY            = 0x4000
-} scb_flag_type;
-
-typedef enum {
-        AHC_FNONE                 = 0x00000000,
-        AHC_PAGESCBS              = 0x00000001,
-        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
-        AHC_USEDEFAULTS           = 0x00000004,
-        AHC_INDIRECT_PAGING       = 0x00000008,
-        AHC_CHNLB                 = 0x00000020,
-        AHC_CHNLC                 = 0x00000040,
-        AHC_EXTEND_TRANS_A        = 0x00000100,
-        AHC_EXTEND_TRANS_B        = 0x00000200,
-        AHC_TERM_ENB_A            = 0x00000400,
-        AHC_TERM_ENB_SE_LOW       = 0x00000400,
-        AHC_TERM_ENB_B            = 0x00000800,
-        AHC_TERM_ENB_SE_HIGH      = 0x00000800,
-        AHC_HANDLING_REQINITS     = 0x00001000,
-        AHC_TARGETMODE            = 0x00002000,
-        AHC_NEWEEPROM_FMT         = 0x00004000,
- /*
-  *  Here ends the FreeBSD defined flags and here begins the linux defined
-  *  flags.  NOTE: I did not preserve the old flag name during this change
-  *  specifically to force me to evaluate what flags were being used properly
-  *  and what flags weren't.  This way, I could clean up the flag usage on
-  *  a use by use basis.  Doug Ledford
-  */
-        AHC_MOTHERBOARD           = 0x00020000,
-        AHC_NO_STPWEN             = 0x00040000,
-        AHC_RESET_DELAY           = 0x00080000,
-        AHC_A_SCANNED             = 0x00100000,
-        AHC_B_SCANNED             = 0x00200000,
-        AHC_MULTI_CHANNEL         = 0x00400000,
-        AHC_BIOS_ENABLED          = 0x00800000,
-        AHC_SEEPROM_FOUND         = 0x01000000,
-        AHC_TERM_ENB_LVD          = 0x02000000,
-        AHC_ABORT_PENDING         = 0x04000000,
-        AHC_RESET_PENDING         = 0x08000000,
-#define AHC_IN_ISR_BIT              28
-        AHC_IN_ISR                = 0x10000000,
-        AHC_IN_ABORT              = 0x20000000,
-        AHC_IN_RESET              = 0x40000000,
-        AHC_EXTERNAL_SRAM         = 0x80000000
-} ahc_flag_type;
-
-typedef enum {
-  AHC_NONE             = 0x0000,
-  AHC_CHIPID_MASK      = 0x00ff,
-  AHC_AIC7770          = 0x0001,
-  AHC_AIC7850          = 0x0002,
-  AHC_AIC7860          = 0x0003,
-  AHC_AIC7870          = 0x0004,
-  AHC_AIC7880          = 0x0005,
-  AHC_AIC7890          = 0x0006,
-  AHC_AIC7895          = 0x0007,
-  AHC_AIC7896          = 0x0008,
-  AHC_AIC7892          = 0x0009,
-  AHC_AIC7899          = 0x000a,
-  AHC_VL               = 0x0100,
-  AHC_EISA             = 0x0200,
-  AHC_PCI              = 0x0400,
-} ahc_chip;
-
-typedef enum {
-  AHC_FENONE           = 0x0000,
-  AHC_ULTRA            = 0x0001,
-  AHC_ULTRA2           = 0x0002,
-  AHC_WIDE             = 0x0004,
-  AHC_TWIN             = 0x0008,
-  AHC_MORE_SRAM        = 0x0010,
-  AHC_CMD_CHAN         = 0x0020,
-  AHC_QUEUE_REGS       = 0x0040,
-  AHC_SG_PRELOAD       = 0x0080,
-  AHC_SPIOCAP          = 0x0100,
-  AHC_ULTRA3           = 0x0200,
-  AHC_NEW_AUTOTERM     = 0x0400,
-  AHC_AIC7770_FE       = AHC_FENONE,
-  AHC_AIC7850_FE       = AHC_SPIOCAP,
-  AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
-  AHC_AIC7870_FE       = AHC_FENONE,
-  AHC_AIC7880_FE       = AHC_ULTRA,
-  AHC_AIC7890_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|
-                         AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM,
-  AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
-  AHC_AIC7896_FE       = AHC_AIC7890_FE,
-  AHC_AIC7892_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
-  AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
-} ahc_feature;
-
-#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset)
-
-struct aic7xxx_scb_dma {
-	unsigned long	       dma_offset;    /* Correction you have to add
-					       * to virtual address to get
-					       * dma handle in this region */
-	dma_addr_t	       dma_address;   /* DMA handle of the start,
-					       * for unmap */
-	unsigned int	       dma_len;	      /* DMA length */
-};
-
-struct aic7xxx_scb {
-        struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
-        Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
-        struct aic7xxx_scb    *q_next;        /* next scb in queue */
-        volatile scb_flag_type flags;         /* current state of scb */
-        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
-        unsigned char          tag_action;
-        unsigned char          sg_count;
-        unsigned char          *sense_cmd;    /*
-                                               * Allocate 6 characters for
-                                               * sense command.
-                                               */
-	unsigned char	       *cmnd;
-        unsigned int           sg_length; /* We init this during buildscb so we
-                                           * don't have to calculate anything
-                                           * during underflow/overflow/stat code
-                                           */
-        void                  *kmalloc_ptr;
-	struct aic7xxx_scb_dma *scb_dma;
-};
-
-/*
- * Define a linked list of SCBs.
- */
-typedef struct {
-  struct aic7xxx_scb *head;
-  struct aic7xxx_scb *tail;
-} scb_queue_type;
-
-static struct {
-  unsigned char errno;
-  const char *errmesg;
-} hard_error[] = {
-  { ILLHADDR,  "Illegal Host Access" },
-  { ILLSADDR,  "Illegal Sequencer Address referenced" },
-  { ILLOPCODE, "Illegal Opcode in sequencer program" },
-  { SQPARERR,  "Sequencer Ram Parity Error" },
-  { DPARERR,   "Data-Path Ram Parity Error" },
-  { MPARERR,   "Scratch Ram/SCB Array Ram Parity Error" },
-  { PCIERRSTAT,"PCI Error detected" },
-  { CIOPARERR, "CIOBUS Parity Error" }
-};
-
-static unsigned char
-generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
-
-typedef struct {
-  scb_queue_type free_scbs;        /*
-                                    * SCBs assigned to free slot on
-                                    * card (no paging required)
-                                    */
-  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
-  struct aic7xxx_hwscb *hscbs;
-  unsigned char  numscbs;          /* current number of scbs */
-  unsigned char  maxhscbs;         /* hardware scbs */
-  unsigned char  maxscbs;          /* max scbs including pageable scbs */
-  dma_addr_t	 hscbs_dma;	   /* DMA handle to hscbs */
-  unsigned int   hscbs_dma_len;    /* length of the above DMA area */
-  void          *hscb_kmalloc_ptr;
-} scb_data_type;
-
-struct target_cmd {
-  unsigned char mesg_bytes[4];
-  unsigned char command[28];
-};
-
-#define AHC_TRANS_CUR    0x0001
-#define AHC_TRANS_ACTIVE 0x0002
-#define AHC_TRANS_GOAL   0x0004
-#define AHC_TRANS_USER   0x0008
-#define AHC_TRANS_QUITE  0x0010
-typedef struct {
-  unsigned char cur_width;
-  unsigned char goal_width;
-  unsigned char cur_period;
-  unsigned char goal_period;
-  unsigned char cur_offset;
-  unsigned char goal_offset;
-  unsigned char cur_options;
-  unsigned char goal_options;
-  unsigned char user_width;
-  unsigned char user_period;
-  unsigned char user_offset;
-  unsigned char user_options;
-} transinfo_type;
-
-/*
- * Define a structure used for each host adapter.  Note, in order to avoid
- * problems with architectures I can't test on (because I don't have one,
- * such as the Alpha based systems) which happen to give faults for
- * non-aligned memory accesses, care was taken to align this structure
- * in a way that gauranteed all accesses larger than 8 bits were aligned
- * on the appropriate boundary.  It's also organized to try and be more
- * cache line efficient.  Be careful when changing this lest you might hurt
- * overall performance and bring down the wrath of the masses.
- */
-struct aic7xxx_host {
-  /*
-   *  This is the first 64 bytes in the host struct
-   */
-
-  /*
-   * We are grouping things here....first, items that get either read or
-   * written with nearly every interrupt
-   */
-  volatile ahc_flag_type   flags;
-  ahc_feature              features;         /* chip features */
-  unsigned long            base;             /* card base address */
-  volatile unsigned char  *maddr;            /* memory mapped address */
-  unsigned long            isr_count;        /* Interrupt count */
-  unsigned long            spurious_int;
-  scb_data_type           *scb_data;
-  volatile unsigned short  needdv;
-  volatile unsigned short  needppr;
-  volatile unsigned short  needsdtr;
-  volatile unsigned short  needwdtr;
-  volatile unsigned short  dtr_pending;
-  struct aic7xxx_cmd_queue {
-    Scsi_Cmnd *head;
-    Scsi_Cmnd *tail;
-  } completeq;
-
-  /*
-   * Things read/written on nearly every entry into aic7xxx_queue()
-   */
-  volatile scb_queue_type  waiting_scbs;
-  unsigned short           discenable;       /* Targets allowed to disconnect */
-  unsigned short           tagenable;        /* Targets using tagged I/O */
-  unsigned short           orderedtag;       /* Ordered Q tags allowed */
-  unsigned char            unpause;          /* unpause value for HCNTRL */
-  unsigned char            pause;            /* pause value for HCNTRL */
-  volatile unsigned char   qoutfifonext;
-  volatile unsigned char   activescbs;       /* active scbs */
-  volatile unsigned char   max_activescbs;
-  volatile unsigned char   qinfifonext;
-  volatile unsigned char  *untagged_scbs;
-  volatile unsigned char  *qoutfifo;
-  volatile unsigned char  *qinfifo;
-
-#define  DEVICE_PRESENT                 0x01
-#define  BUS_DEVICE_RESET_PENDING       0x02
-#define  DEVICE_RESET_DELAY             0x04
-#define  DEVICE_PRINT_DTR               0x08
-#define  DEVICE_PARITY_ERROR            0x10
-#define  DEVICE_WAS_BUSY                0x20
-#define  DEVICE_SCSI_3                  0x40
-#define  DEVICE_SCANNED                 0x80
-  volatile unsigned char   dev_flags[MAX_TARGETS];
-  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
-  volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
-  unsigned char            dev_commands_sent[MAX_TARGETS];
-
-  unsigned int             dev_timer_active; /* Which devs have a timer set */
-  struct timer_list        dev_timer;
-  unsigned long            dev_expires[MAX_TARGETS];
-
-  spinlock_t               spin_lock;
-  volatile unsigned char   cpu_lock_count[NR_CPUS];
-
-  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
-
-  unsigned int             dev_checksum[MAX_TARGETS];
-  
-  unsigned char            dev_last_queue_full[MAX_TARGETS];
-  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
-  unsigned char            dev_max_queue_depth[MAX_TARGETS];
-
-  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
-
-
-  unsigned char            msg_buf[13];      /* The message for the target */
-  unsigned char            msg_type;
-#define MSG_TYPE_NONE              0x00
-#define MSG_TYPE_INITIATOR_MSGOUT  0x01
-#define MSG_TYPE_INITIATOR_MSGIN   0x02
-  unsigned char            msg_len;          /* Length of message */
-  unsigned char            msg_index;        /* Index into msg_buf array */
-  transinfo_type           transinfo[MAX_TARGETS];
-
-
-  /*
-   * We put the less frequently used host structure items after the more
-   * frequently used items to try and ease the burden on the cache subsystem.
-   * These entries are not *commonly* accessed, whereas the preceding entries
-   * are accessed very often.
-   */
-
-  unsigned int             irq;              /* IRQ for this adapter */
-  int                      instance;         /* aic7xxx instance number */
-  int                      scsi_id;          /* host adapter SCSI ID */
-  int                      scsi_id_b;        /* channel B for twin adapters */
-  unsigned int             bios_address;
-  int                      board_name_index;
-  unsigned short           needppr_copy;     /* default config */
-  unsigned short           needsdtr_copy;    /* default config */
-  unsigned short           needwdtr_copy;    /* default config */
-  unsigned short           ultraenb;         /* Ultra mode target list */
-  unsigned short           bios_control;     /* bios control - SEEPROM */
-  unsigned short           adapter_control;  /* adapter control - SEEPROM */
-  struct pci_dev	  *pdev;
-  unsigned char            pci_bus;
-  unsigned char            pci_device_fn;
-  struct seeprom_config    sc;
-  unsigned short           sc_type;
-  unsigned short           sc_size;
-  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
-  struct Scsi_Host        *host;             /* pointer to scsi host */
-  int                      host_no;          /* SCSI host number */
-  unsigned long            mbase;            /* I/O memory address */
-  ahc_chip                 chip;             /* chip type */
-  dma_addr_t		   fifo_dma;	     /* DMA handle for fifo arrays */
-
-  /*
-   * Statistics Kept:
-   *
-   * Total Xfers (count for each command that has a data xfer),
-   * broken down further by reads && writes.
-   *
-   * Binned sizes, writes && reads:
-   *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
-   *
-   * Total amounts read/written above 512 bytes (amts under ignored)
-   *
-   * NOTE: Enabling this feature is likely to cause a noticeable performance
-   * decrease as the accesses into the stats structures blows apart multiple
-   * cache lines and is CPU time consuming.
-   *
-   * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM
-   * and blows apart all sorts of cache lines, I modified this so that we
-   * no longer look at the LUN.  All LUNs now go into the same bin on each
-   * device for stats purposes.
-   */
-  struct aic7xxx_xferstats {
-    long w_total;                          /* total writes */
-    long r_total;                          /* total reads */
-#ifdef AIC7XXX_PROC_STATS
-    long w_bins[8];                       /* binned write */
-    long r_bins[8];                       /* binned reads */
-#endif /* AIC7XXX_PROC_STATS */
-  } stats[MAX_TARGETS];                    /* [(channel << 3)|target] */
-
-#if 0
-  struct target_cmd       *targetcmds;
-  unsigned int             num_targetcmds;
-#endif
-
-};
-
-/*
- * Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns/4 to the proper value to
- * stick in the SCSIRATE reg to use that transfer rate.
- */
-#define AHC_SYNCRATE_ULTRA3 0
-#define AHC_SYNCRATE_ULTRA2 1
-#define AHC_SYNCRATE_ULTRA  3
-#define AHC_SYNCRATE_FAST   6
-#define AHC_SYNCRATE_CRC 0x40
-#define AHC_SYNCRATE_SE  0x10
-static struct aic7xxx_syncrate {
-  /* Rates in Ultra mode have bit 8 of sxfr set */
-#define                ULTRA_SXFR 0x100
-  int sxfr_ultra2;
-  int sxfr;
-  unsigned char period;
-  const char *rate[2];
-} aic7xxx_syncrates[] = {
-  { 0x42,  0x000,   9,  {"80.0", "160.0"} },
-  { 0x13,  0x000,  10,  {"40.0", "80.0"} },
-  { 0x14,  0x000,  11,  {"33.0", "66.6"} },
-  { 0x15,  0x100,  12,  {"20.0", "40.0"} },
-  { 0x16,  0x110,  15,  {"16.0", "32.0"} },
-  { 0x17,  0x120,  18,  {"13.4", "26.8"} },
-  { 0x18,  0x000,  25,  {"10.0", "20.0"} },
-  { 0x19,  0x010,  31,  {"8.0",  "16.0"} },
-  { 0x1a,  0x020,  37,  {"6.67", "13.3"} },
-  { 0x1b,  0x030,  43,  {"5.7",  "11.4"} },
-  { 0x10,  0x040,  50,  {"5.0",  "10.0"} },
-  { 0x00,  0x050,  56,  {"4.4",  "8.8" } },
-  { 0x00,  0x060,  62,  {"4.0",  "8.0" } },
-  { 0x00,  0x070,  68,  {"3.6",  "7.2" } },
-  { 0x00,  0x000,  0,   {NULL, NULL}   },
-};
-
-#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
-                        (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
-                        ((scb->hscb)->target_channel_lun & 0x07)
-
-#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01),  \
-                        ((cmd->target) & 0x0f), \
-                        ((cmd->lun) & 0x07)
-
-#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
-
-/*
- * A nice little define to make doing our printks a little easier
- */
-
-#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
-#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
-
-/*
- * XXX - these options apply unilaterally to _all_ 274x/284x/294x
- *       cards in the system.  This should be fixed.  Exceptions to this
- *       rule are noted in the comments.
- */
-
-
-/*
- * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
- * has no effect on any later resets that might occur due to things like
- * SCSI bus timeouts.
- */
-static unsigned int aic7xxx_no_reset = 0;
-/*
- * Certain PCI motherboards will scan PCI devices from highest to lowest,
- * others scan from lowest to highest, and they tend to do all kinds of
- * strange things when they come into contact with PCI bridge chips.  The
- * net result of all this is that the PCI card that is actually used to boot
- * the machine is very hard to detect.  Most motherboards go from lowest
- * PCI slot number to highest, and the first SCSI controller found is the
- * one you boot from.  The only exceptions to this are when a controller
- * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
- * from lowest PCI slot number to highest PCI slot number.  We also force
- * all controllers with their BIOS disabled to the end of the list.  This
- * works on *almost* all computers.  Where it doesn't work, we have this
- * option.  Setting this option to non-0 will reverse the order of the sort
- * to highest first, then lowest, but will still leave cards with their BIOS
- * disabled at the very end.  That should fix everyone up unless there are
- * really strange cirumstances.
- */
-static int aic7xxx_reverse_scan = 0;
-/*
- * Should we force EXTENDED translation on a controller.
- *     0 == Use whatever is in the SEEPROM or default to off
- *     1 == Use whatever is in the SEEPROM or default to on
- */
-static unsigned int aic7xxx_extended = 0;
-/*
- * The IRQ trigger method used on EISA controllers. Does not effect PCI cards.
- *   -1 = Use detected settings.
- *    0 = Force Edge triggered mode.
- *    1 = Force Level triggered mode.
- */
-static int aic7xxx_irq_trigger = -1;
-/*
- * This variable is used to override the termination settings on a controller.
- * This should not be used under normal conditions.  However, in the case
- * that a controller does not have a readable SEEPROM (so that we can't
- * read the SEEPROM settings directly) and that a controller has a buggered
- * version of the cable detection logic, this can be used to force the 
- * correct termination.  It is preferable to use the manual termination
- * settings in the BIOS if possible, but some motherboard controllers store
- * those settings in a format we can't read.  In other cases, auto term
- * should also work, but the chipset was put together with no auto term
- * logic (common on motherboard controllers).  In those cases, we have
- * 32 bits here to work with.  That's good for 8 controllers/channels.  The
- * bits are organized as 4 bits per channel, with scsi0 getting the lowest
- * 4 bits in the int.  A 1 in a bit position indicates the termination setting
- * that corresponds to that bit should be enabled, a 0 is disabled.
- * It looks something like this:
- *
- *    0x0f =  1111-Single Ended Low Byte Termination on/off
- *            ||\-Single Ended High Byte Termination on/off
- *            |\-LVD Low Byte Termination on/off
- *            \-LVD High Byte Termination on/off
- *
- * For non-Ultra2 controllers, the upper 2 bits are not important.  So, to
- * enable both high byte and low byte termination on scsi0, I would need to
- * make sure that the override_term variable was set to 0x03 (bits 0011).
- * To make sure that all termination is enabled on an Ultra2 controller at
- * scsi2 and only high byte termination on scsi1 and high and low byte
- * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011)
- *
- * For the most part, users should never have to use this, that's why I
- * left it fairly cryptic instead of easy to understand.  If you need it,
- * most likely someone will be telling you what your's needs to be set to.
- */
-static int aic7xxx_override_term = -1;
-/*
- * Certain motherboard chipset controllers tend to screw
- * up the polarity of the term enable output pin.  Use this variable
- * to force the correct polarity for your system.  This is a bitfield variable
- * similar to the previous one, but this one has one bit per channel instead
- * of four.
- *    0 = Force the setting to active low.
- *    1 = Force setting to active high.
- * Most Adaptec cards are active high, several motherboards are active low.
- * To force a 2940 card at SCSI 0 to active high and a motherboard 7895
- * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3
- * to active high, you would need to set stpwlev=0x9 (bits 1001).
- *
- * People shouldn't need to use this, but if you are experiencing lots of
- * SCSI timeout problems, this may help.  There is one sure way to test what
- * this option needs to be.  Using a boot floppy to boot the system, configure
- * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and
- * if needed then also pass a value to override_term to make sure that the
- * driver is enabling SCSI termination, then set this variable to either 0
- * or 1.  When the driver boots, make sure there are *NO* SCSI cables
- * connected to your controller.  If it finds and inits the controller
- * without problem, then the setting you passed to stpwlev was correct.  If
- * the driver goes into a reset loop and hangs the system, then you need the
- * other setting for this variable.  If neither setting lets the machine
- * boot then you have definite termination problems that may not be fixable.
- */
-static int aic7xxx_stpwlev = -1;
-/*
- * Set this to non-0 in order to force the driver to panic the kernel
- * and print out debugging info on a SCSI abort or reset cycle.
- */
-static int aic7xxx_panic_on_abort = 0;
-/*
- * PCI bus parity checking of the Adaptec controllers.  This is somewhat
- * dubious at best.  To my knowledge, this option has never actually
- * solved a PCI parity problem, but on certain machines with broken PCI
- * chipset configurations, it can generate tons of false error messages.
- * It's included in the driver for completeness.
- *   0 = Shut off PCI parity check
- *  -1 = Normal polarity pci parity checking
- *   1 = reverse polarity pci parity checking
- *
- * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
- * variable to -1 you would actually want to simply pass the variable
- * name without a number.  That will invert the 0 which will result in
- * -1.
- */
-static int aic7xxx_pci_parity = 0;
-/*
- * Set this to any non-0 value to cause us to dump the contents of all
- * the card's registers in a hex dump format tailored to each model of
- * controller.
- * 
- * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION.
- *       YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES
- *       ONLY
- */
-static int aic7xxx_dump_card = 0;
-/*
- * Set this to a non-0 value to make us dump out the 32 bit instruction
- * registers on the card after completing the sequencer download.  This
- * allows the actual sequencer download to be verified.  It is possible
- * to use this option and still boot up and run your system.  This is
- * only intended for debugging purposes.
- */
-static int aic7xxx_dump_sequencer = 0;
-/*
- * Certain newer motherboards have put new PCI based devices into the
- * IO spaces that used to typically be occupied by VLB or EISA cards.
- * This overlap can cause these newer motherboards to lock up when scanned
- * for older EISA and VLB devices.  Setting this option to non-0 will
- * cause the driver to skip scanning for any VLB or EISA controllers and
- * only support the PCI controllers.  NOTE: this means that if the kernel
- * os compiled with PCI support disabled, then setting this to non-0
- * would result in never finding any devices :)
- */
-static int aic7xxx_no_probe = 0;
-/*
- * On some machines, enabling the external SCB RAM isn't reliable yet.  I
- * haven't had time to make test patches for things like changing the
- * timing mode on that external RAM either.  Some of those changes may
- * fix the problem.  Until then though, we default to external SCB RAM
- * off and give a command line option to enable it.
- */
-static int aic7xxx_scbram = 0;
-/*
- * So that we can set how long each device is given as a selection timeout.
- * The table of values goes like this:
- *   0 - 256ms
- *   1 - 128ms
- *   2 - 64ms
- *   3 - 32ms
- * We default to 64ms because it's fast.  Some old SCSI-I devices need a
- * longer time.  The final value has to be left shifted by 3, hence 0x10
- * is the final value.
- */
-static int aic7xxx_seltime = 0x10;
-/*
- * So that insmod can find the variable and make it point to something
- */
-#ifdef MODULE
-static char * aic7xxx = NULL;
-MODULE_PARM(aic7xxx, "s");
-
-/*
- * Just in case someone uses commas to separate items on the insmod
- * command line, we define a dummy buffer here to avoid having insmod
- * write wild stuff into our code segment
- */
-static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
-
-#endif
-
-#define VERBOSE_NORMAL         0x0000
-#define VERBOSE_NEGOTIATION    0x0001
-#define VERBOSE_SEQINT         0x0002
-#define VERBOSE_SCSIINT        0x0004
-#define VERBOSE_PROBE          0x0008
-#define VERBOSE_PROBE2         0x0010
-#define VERBOSE_NEGOTIATION2   0x0020
-#define VERBOSE_MINOR_ERROR    0x0040
-#define VERBOSE_TRACING        0x0080
-#define VERBOSE_ABORT          0x0f00
-#define VERBOSE_ABORT_MID      0x0100
-#define VERBOSE_ABORT_FIND     0x0200
-#define VERBOSE_ABORT_PROCESS  0x0400
-#define VERBOSE_ABORT_RETURN   0x0800
-#define VERBOSE_RESET          0xf000
-#define VERBOSE_RESET_MID      0x1000
-#define VERBOSE_RESET_FIND     0x2000
-#define VERBOSE_RESET_PROCESS  0x4000
-#define VERBOSE_RESET_RETURN   0x8000
-static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
-           VERBOSE_PROBE;                     /* verbose messages */
-
-
-/****************************************************************************
- *
- * We're going to start putting in function declarations so that order of
- * functions is no longer important.  As needed, they are added here.
- *
- ***************************************************************************/
-
-static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
-static void aic7xxx_print_card(struct aic7xxx_host *p);
-static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
-static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer);
-#endif
-
-/****************************************************************************
- *
- * These functions are now used.  They happen to be wrapped in useless
- * inb/outb port read/writes around the real reads and writes because it
- * seems that certain very fast CPUs have a problem dealing with us when
- * going at full speed.
- *
- ***************************************************************************/
-
-static inline unsigned char
-aic_inb(struct aic7xxx_host *p, long port)
-{
-#ifdef MMAPIO
-  unsigned char x;
-  if(p->maddr)
-  {
-    x = readb(p->maddr + port);
-  }
-  else
-  {
-    x = inb(p->base + port);
-  }
-  return(x);
-#else
-  return(inb(p->base + port));
-#endif
-}
-
-static inline void
-aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
-{
-#ifdef MMAPIO
-  if(p->maddr)
-  {
-    writeb(val, p->maddr + port);
-    mb(); /* locked operation in order to force CPU ordering */
-    readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */
-  }
-  else
-  {
-    outb(val, p->base + port);
-    mb(); /* locked operation in order to force CPU ordering */
-  }
-#else
-  outb(val, p->base + port);
-  mb(); /* locked operation in order to force CPU ordering */
-#endif
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_setup
- *
- * Description:
- *   Handle Linux boot parameters. This routine allows for assigning a value
- *   to a parameter with a ':' between the parameter and the value.
- *   ie. aic7xxx=unpause:0x0A,extended
- *-F*************************************************************************/
-static int
-aic7xxx_setup(char *s)
-{
-  int   i, n;
-  char *p;
-  char *end;
-
-  static struct {
-    const char *name;
-    unsigned int *flag;
-  } options[] = {
-    { "extended",    &aic7xxx_extended },
-    { "no_reset",    &aic7xxx_no_reset },
-    { "irq_trigger", &aic7xxx_irq_trigger },
-    { "verbose",     &aic7xxx_verbose },
-    { "reverse_scan",&aic7xxx_reverse_scan },
-    { "override_term", &aic7xxx_override_term },
-    { "stpwlev", &aic7xxx_stpwlev },
-    { "no_probe", &aic7xxx_no_probe },
-    { "panic_on_abort", &aic7xxx_panic_on_abort },
-    { "pci_parity", &aic7xxx_pci_parity },
-    { "dump_card", &aic7xxx_dump_card },
-    { "dump_sequencer", &aic7xxx_dump_sequencer },
-    { "scbram", &aic7xxx_scbram },
-    { "seltime", &aic7xxx_seltime },
-    { "tag_info",    NULL }
-  };
-
-  end = strchr(s, '\0');
-
-  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
-  {
-    for (i = 0; i < NUMBER(options); i++)
-    {
-      n = strlen(options[i].name);
-      if (!strncmp(options[i].name, p, n))
-      {
-        if (!strncmp(p, "tag_info", n))
-        {
-          if (p[n] == ':')
-          {
-            char *base;
-            char *tok, *tok_end, *tok_end2;
-            char tok_list[] = { '.', ',', '{', '}', '\0' };
-            int i, instance = -1, device = -1;
-            unsigned char done = FALSE;
-
-            base = p;
-            tok = base + n + 1;  /* Forward us just past the ':' */
-            tok_end = strchr(tok, '\0');
-            if (tok_end < end)
-              *tok_end = ',';
-            while(!done)
-            {
-              switch(*tok)
-              {
-                case '{':
-                  if (instance == -1)
-                    instance = 0;
-                  else if (device == -1)
-                    device = 0;
-                  tok++;
-                  break;
-                case '}':
-                  if (device != -1)
-                    device = -1;
-                  else if (instance != -1)
-                    instance = -1;
-                  tok++;
-                  break;
-                case ',':
-                case '.':
-                  if (instance == -1)
-                    done = TRUE;
-                  else if (device >= 0)
-                    device++;
-                  else if (instance >= 0)
-                    instance++;
-                  if ( (device >= MAX_TARGETS) || 
-                       (instance >= NUMBER(aic7xxx_tag_info)) )
-                    done = TRUE;
-                  tok++;
-                  if (!done)
-                  {
-                    base = tok;
-                  }
-                  break;
-                case '\0':
-                  done = TRUE;
-                  break;
-                default:
-                  done = TRUE;
-                  tok_end = strchr(tok, '\0');
-                  for(i=0; tok_list[i]; i++)
-                  {
-                    tok_end2 = strchr(tok, tok_list[i]);
-                    if ( (tok_end2) && (tok_end2 < tok_end) )
-                    {
-                      tok_end = tok_end2;
-                      done = FALSE;
-                    }
-                  }
-                  if ( (instance >= 0) && (device >= 0) &&
-                       (instance < NUMBER(aic7xxx_tag_info)) &&
-                       (device < MAX_TARGETS) )
-                    aic7xxx_tag_info[instance].tag_commands[device] =
-                      simple_strtoul(tok, NULL, 0) & 0xff;
-                  tok = tok_end;
-                  break;
-              }
-            }
-            while((p != base) && (p != NULL))
-              p = strtok(NULL, ",.");
-          }
-        }
-        else if (p[n] == ':')
-        {
-          *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
-          if(!strncmp(p, "seltime", n))
-          {
-            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
-          }
-        }
-        else if (!strncmp(p, "verbose", n))
-        {
-          *(options[i].flag) = 0xff29;
-        }
-        else
-        {
-          *(options[i].flag) = ~(*(options[i].flag));
-          if(!strncmp(p, "seltime", n))
-          {
-            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
-          }
-        }
-      }
-    }
-  }
-  return 1;
-}
-
-__setup("aic7xxx=", aic7xxx_setup);
-
-/*+F*************************************************************************
- * Function:
- *   pause_sequencer
- *
- * Description:
- *   Pause the sequencer and wait for it to actually stop - this
- *   is important since the sequencer can disable pausing for critical
- *   sections.
- *-F*************************************************************************/
-static void
-pause_sequencer(struct aic7xxx_host *p)
-{
-  aic_outb(p, p->pause, HCNTRL);
-  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
-  {
-    ;
-  }
-  if(p->features & AHC_ULTRA2)
-  {
-    aic_inb(p, CCSCBCTL);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   unpause_sequencer
- *
- * Description:
- *   Unpause the sequencer. Unremarkable, yet done often enough to
- *   warrant an easy way to do it.
- *-F*************************************************************************/
-static void
-unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
-{
-  if (unpause_always ||
-      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
-        !(p->flags & AHC_HANDLING_REQINITS) ) )
-  {
-    aic_outb(p, p->unpause, HCNTRL);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   restart_sequencer
- *
- * Description:
- *   Restart the sequencer program from address zero.  This assumes
- *   that the sequencer is already paused.
- *-F*************************************************************************/
-static void
-restart_sequencer(struct aic7xxx_host *p)
-{
-  aic_outb(p, 0, SEQADDR0);
-  aic_outb(p, 0, SEQADDR1);
-  aic_outb(p, FASTMODE, SEQCTL);
-}
-
-/*
- * We include the aic7xxx_seq.c file here so that the other defines have
- * already been made, and so that it comes before the code that actually
- * downloads the instructions (since we don't typically use function
- * prototype, our code has to be ordered that way, it's a left-over from
- * the original driver days.....I should fix it some time DL).
- */
-#include "aic7xxx_seq.c"
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_check_patch
- *
- * Description:
- *   See if the next patch to download should be downloaded.
- *-F*************************************************************************/
-static int
-aic7xxx_check_patch(struct aic7xxx_host *p,
-  struct sequencer_patch **start_patch, int start_instr, int *skip_addr)
-{
-  struct sequencer_patch *cur_patch;
-  struct sequencer_patch *last_patch;
-  int num_patches;
-
-  num_patches = sizeof(sequencer_patches)/sizeof(struct sequencer_patch);
-  last_patch = &sequencer_patches[num_patches];
-  cur_patch = *start_patch;
-
-  while ((cur_patch < last_patch) && (start_instr == cur_patch->begin))
-  {
-    if (cur_patch->patch_func(p) == 0)
-    {
-      /*
-       * Start rejecting code.
-       */
-      *skip_addr = start_instr + cur_patch->skip_instr;
-      cur_patch += cur_patch->skip_patch;
-    }
-    else
-    {
-      /*
-       * Found an OK patch.  Advance the patch pointer to the next patch
-       * and wait for our instruction pointer to get here.
-       */
-      cur_patch++;
-    }
-  }
-
-  *start_patch = cur_patch;
-  if (start_instr < *skip_addr)
-    /*
-     * Still skipping
-     */
-    return (0);
-  return(1);
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_download_instr
- *
- * Description:
- *   Find the next patch to download.
- *-F*************************************************************************/
-static void
-aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
-  unsigned char *dconsts)
-{
-  union ins_formats instr;
-  struct ins_format1 *fmt1_ins;
-  struct ins_format3 *fmt3_ins;
-  unsigned char opcode;
-
-  instr = *(union ins_formats*) &seqprog[instrptr * 4];
-
-  instr.integer = le32_to_cpu(instr.integer);
-  
-  fmt1_ins = &instr.format1;
-  fmt3_ins = NULL;
-
-  /* Pull the opcode */
-  opcode = instr.format1.opcode;
-  switch (opcode)
-  {
-    case AIC_OP_JMP:
-    case AIC_OP_JC:
-    case AIC_OP_JNC:
-    case AIC_OP_CALL:
-    case AIC_OP_JNE:
-    case AIC_OP_JNZ:
-    case AIC_OP_JE:
-    case AIC_OP_JZ:
-    {
-      struct sequencer_patch *cur_patch;
-      int address_offset;
-      unsigned int address;
-      int skip_addr;
-      int i;
-
-      fmt3_ins = &instr.format3;
-      address_offset = 0;
-      address = fmt3_ins->address;
-      cur_patch = sequencer_patches;
-      skip_addr = 0;
-
-      for (i = 0; i < address;)
-      {
-        aic7xxx_check_patch(p, &cur_patch, i, &skip_addr);
-        if (skip_addr > i)
-        {
-          int end_addr;
-
-          end_addr = MIN(address, skip_addr);
-          address_offset += end_addr - i;
-          i = skip_addr;
-        }
-        else
-        {
-          i++;
-        }
-      }
-      address -= address_offset;
-      fmt3_ins->address = address;
-      /* Fall Through to the next code section */
-    }
-    case AIC_OP_OR:
-    case AIC_OP_AND:
-    case AIC_OP_XOR:
-    case AIC_OP_ADD:
-    case AIC_OP_ADC:
-    case AIC_OP_BMOV:
-      if (fmt1_ins->parity != 0)
-      {
-        fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
-      }
-      fmt1_ins->parity = 0;
-      /* Fall Through to the next code section */
-    case AIC_OP_ROL:
-      if ((p->features & AHC_ULTRA2) != 0)
-      {
-        int i, count;
-
-        /* Calculate odd parity for the instruction */
-        for ( i=0, count=0; i < 31; i++)
-        {
-          unsigned int mask;
-
-          mask = 0x01 << i;
-          if ((instr.integer & mask) != 0)
-            count++;
-        }
-        if (!(count & 0x01))
-          instr.format1.parity = 1;
-      }
-      else
-      {
-        if (fmt3_ins != NULL)
-        {
-          instr.integer =  fmt3_ins->immediate |
-                          (fmt3_ins->source << 8) |
-                          (fmt3_ins->address << 16) |
-                          (fmt3_ins->opcode << 25);
-        }
-        else
-        {
-          instr.integer =  fmt1_ins->immediate |
-                          (fmt1_ins->source << 8) |
-                          (fmt1_ins->destination << 16) |
-                          (fmt1_ins->ret << 24) |
-                          (fmt1_ins->opcode << 25);
-        }
-      }
-      aic_outb(p, (instr.integer & 0xff), SEQRAM);
-      aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
-      aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
-      aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
-      udelay(10);
-      break;
-
-    default:
-      panic("aic7xxx: Unknown opcode encountered in sequencer program.");
-      break;
-  }
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_loadseq
- *
- * Description:
- *   Load the sequencer code into the controller memory.
- *-F*************************************************************************/
-static void
-aic7xxx_loadseq(struct aic7xxx_host *p)
-{
-  struct sequencer_patch *cur_patch;
-  int i;
-  int downloaded;
-  int skip_addr;
-  unsigned char download_consts[4] = {0, 0, 0, 0};
-
-  if (aic7xxx_verbose & VERBOSE_PROBE)
-  {
-    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
-  }
-#if 0
-  download_consts[TMODE_NUMCMDS] = p->num_targetcmds;
-#endif
-  download_consts[TMODE_NUMCMDS] = 0;
-  cur_patch = &sequencer_patches[0];
-  downloaded = 0;
-  skip_addr = 0;
-
-  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
-  aic_outb(p, 0, SEQADDR0);
-  aic_outb(p, 0, SEQADDR1);
-
-  for (i = 0; i < sizeof(seqprog) / 4;  i++)
-  {
-    if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0)
-    {
-      /* Skip this instruction for this configuration. */
-      continue;
-    }
-    aic7xxx_download_instr(p, i, &download_consts[0]);
-    downloaded++;
-  }
-
-  aic_outb(p, 0, SEQADDR0);
-  aic_outb(p, 0, SEQADDR1);
-  aic_outb(p, FASTMODE | FAILDIS, SEQCTL);
-  unpause_sequencer(p, TRUE);
-  mdelay(1);
-  pause_sequencer(p);
-  aic_outb(p, FASTMODE, SEQCTL);
-  if (aic7xxx_verbose & VERBOSE_PROBE)
-  {
-    printk(" %d instructions downloaded\n", downloaded);
-  }
-  if (aic7xxx_dump_sequencer)
-    aic7xxx_print_sequencer(p, downloaded);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_print_sequencer
- *
- * Description:
- *   Print the contents of the sequencer memory to the screen.
- *-F*************************************************************************/
-static void
-aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded)
-{
-  int i, k, temp;
-  
-  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
-  aic_outb(p, 0, SEQADDR0);
-  aic_outb(p, 0, SEQADDR1);
-
-  k = 0;
-  for (i=0; i < downloaded; i++)
-  {
-    if ( k == 0 )
-      printk("%03x: ", i);
-    temp = aic_inb(p, SEQRAM);
-    temp |= (aic_inb(p, SEQRAM) << 8);
-    temp |= (aic_inb(p, SEQRAM) << 16);
-    temp |= (aic_inb(p, SEQRAM) << 24);
-    printk("%08x", temp);
-    if ( ++k == 8 )
-    {
-      printk("\n");
-      k = 0;
-    }
-    else
-      printk(" ");
-  }
-  aic_outb(p, 0, SEQADDR0);
-  aic_outb(p, 0, SEQADDR1);
-  aic_outb(p, FASTMODE | FAILDIS, SEQCTL);
-  unpause_sequencer(p, TRUE);
-  mdelay(1);
-  pause_sequencer(p);
-  aic_outb(p, FASTMODE, SEQCTL);
-  printk("\n");
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_info
- *
- * Description:
- *   Return a string describing the driver.
- *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *dooh)
-{
-  static char buffer[256];
-  char *bp;
-  struct aic7xxx_host *p;
-
-  bp = &buffer[0];
-  p = (struct aic7xxx_host *)dooh->hostdata;
-  memset(bp, 0, sizeof(buffer));
-  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
-  strcat(bp, AIC7XXX_C_VERSION);
-  strcat(bp, "/");
-  strcat(bp, AIC7XXX_H_VERSION);
-  strcat(bp, "\n");
-  strcat(bp, "       <");
-  strcat(bp, board_names[p->board_name_index]);
-  strcat(bp, ">");
-
-  return(bp);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_find_syncrate
- *
- * Description:
- *   Look up the valid period to SCSIRATE conversion in our table
- *-F*************************************************************************/
-static struct aic7xxx_syncrate *
-aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
-  unsigned int maxsync, unsigned char *options)
-{
-  struct aic7xxx_syncrate *syncrate;
-  int done = FALSE;
-
-  switch(*options)
-  {
-    case MSG_EXT_PPR_OPTION_DT_CRC:
-    case MSG_EXT_PPR_OPTION_DT_UNITS:
-      if(!(p->features & AHC_ULTRA3))
-      {
-        *options = 0;
-        maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
-      }
-      break;
-    case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
-    case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
-      if(!(p->features & AHC_ULTRA3))
-      {
-        *options = 0;
-        maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
-      }
-      else
-      {
-        /*
-         * we don't support the Quick Arbitration variants of dual edge
-         * clocking.  As it turns out, we want to send back the
-         * same basic option, but without the QA attribute.
-         * We know that we are responding because we would never set
-         * these options ourself, we would only respond to them.
-         */
-        switch(*options)
-        {
-          case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
-            *options = MSG_EXT_PPR_OPTION_DT_CRC;
-            break;
-          case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
-            *options = MSG_EXT_PPR_OPTION_DT_UNITS;
-            break;
-        }
-      }
-      break;
-    default:
-      *options = 0;
-      maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
-      break;
-  }
-  syncrate = &aic7xxx_syncrates[maxsync];
-  while ( (syncrate->rate[0] != NULL) &&
-         (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
-  {
-    if (*period <= syncrate->period) 
-    {
-      switch(*options)
-      {
-        case MSG_EXT_PPR_OPTION_DT_CRC:
-        case MSG_EXT_PPR_OPTION_DT_UNITS:
-          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
-          {
-            done = TRUE;
-            /*
-             * oops, we went too low for the CRC/DualEdge signalling, so
-             * clear the options byte
-             */
-            *options = 0;
-            /*
-             * We'll be sending a reply to this packet to set the options
-             * properly, so unilaterally set the period as well.
-             */
-            *period = syncrate->period;
-          }
-          else
-          {
-            done = TRUE;
-            if(syncrate == &aic7xxx_syncrates[maxsync])
-            {
-              *period = syncrate->period;
-            }
-          }
-          break;
-        default:
-          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
-          {
-            done = TRUE;
-            if(syncrate == &aic7xxx_syncrates[maxsync])
-            {
-              *period = syncrate->period;
-            }
-          }
-          break;
-      }
-      if(done)
-      {
-        break;
-      }
-    }
-    syncrate++;
-  }
-  if ( (*period == 0) || (syncrate->rate[0] == NULL) ||
-       ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) )
-  {
-    /*
-     * Use async transfers for this target
-     */
-    *options = 0;
-    *period = 255;
-    syncrate = NULL;
-  }
-  return (syncrate);
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_find_period
- *
- * Description:
- *   Look up the valid SCSIRATE to period conversion in our table
- *-F*************************************************************************/
-static unsigned int
-aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate,
-  unsigned int maxsync)
-{
-  struct aic7xxx_syncrate *syncrate;
-
-  if (p->features & AHC_ULTRA2)
-  {
-    scsirate &= SXFR_ULTRA2;
-  }
-  else
-  {
-    scsirate &= SXFR;
-  }
-
-  syncrate = &aic7xxx_syncrates[maxsync];
-  while (syncrate->rate[0] != NULL)
-  {
-    if (p->features & AHC_ULTRA2)
-    {
-      if (syncrate->sxfr_ultra2 == 0)
-        break;
-      else if (scsirate == syncrate->sxfr_ultra2)
-        return (syncrate->period);
-      else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC))
-        return (syncrate->period);
-    }
-    else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
-    {
-      return (syncrate->period);
-    }
-    syncrate++;
-  }
-  return (0); /* async */
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_validate_offset
- *
- * Description:
- *   Set a valid offset value for a particular card in use and transfer
- *   settings in use.
- *-F*************************************************************************/
-static void
-aic7xxx_validate_offset(struct aic7xxx_host *p,
-  struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide)
-{
-  unsigned int maxoffset;
-
-  /* Limit offset to what the card (and device) can do */
-  if (syncrate == NULL)
-  {
-    maxoffset = 0;
-  }
-  else if (p->features & AHC_ULTRA2)
-  {
-    maxoffset = MAX_OFFSET_ULTRA2;
-  }
-  else
-  {
-    if (wide)
-      maxoffset = MAX_OFFSET_16BIT;
-    else
-      maxoffset = MAX_OFFSET_8BIT;
-  }
-  *offset = MIN(*offset, maxoffset);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_set_syncrate
- *
- * Description:
- *   Set the actual syncrate down in the card and in our host structs
- *-F*************************************************************************/
-static void
-aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
-    int target, int channel, unsigned int period, unsigned int offset,
-    unsigned char options, unsigned int type)
-{
-  unsigned char tindex;
-  unsigned short target_mask;
-  unsigned char lun, old_options;
-  unsigned int old_period, old_offset;
-
-  tindex = target | (channel << 3);
-  target_mask = 0x01 << tindex;
-  lun = aic_inb(p, SCB_TCL) & 0x07;
-
-  if (syncrate == NULL)
-  {
-    period = 0;
-    offset = 0;
-  }
-
-  old_period = p->transinfo[tindex].cur_period;
-  old_offset = p->transinfo[tindex].cur_offset;
-  old_options = p->transinfo[tindex].cur_options;
-
-  
-  if (type & AHC_TRANS_CUR)
-  {
-    unsigned int scsirate;
-
-    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
-    if (p->features & AHC_ULTRA2)
-    {
-      scsirate &= ~SXFR_ULTRA2;
-      if (syncrate != NULL)
-      {
-        switch(options)
-        {
-          case MSG_EXT_PPR_OPTION_DT_UNITS:
-            /*
-             * mask off the CRC bit in the xfer settings
-             */
-            scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC);
-            break;
-          default:
-            scsirate |= syncrate->sxfr_ultra2;
-            break;
-        }
-      }
-      if (type & AHC_TRANS_ACTIVE)
-      {
-        aic_outb(p, offset, SCSIOFFSET);
-      }
-      aic_outb(p, offset, TARG_OFFSET + tindex);
-    }
-    else /* Not an Ultra2 controller */
-    {
-      scsirate &= ~(SXFR|SOFS);
-      p->ultraenb &= ~target_mask;
-      if (syncrate != NULL)
-      {
-        if (syncrate->sxfr & ULTRA_SXFR)
-        {
-          p->ultraenb |= target_mask;
-        }
-        scsirate |= (syncrate->sxfr & SXFR);
-        scsirate |= (offset & SOFS);
-      }
-      if (type & AHC_TRANS_ACTIVE)
-      {
-        unsigned char sxfrctl0;
-
-        sxfrctl0 = aic_inb(p, SXFRCTL0);
-        sxfrctl0 &= ~FAST20;
-        if (p->ultraenb & target_mask)
-          sxfrctl0 |= FAST20;
-        aic_outb(p, sxfrctl0, SXFRCTL0);
-      }
-      aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
-      aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 );
-    }
-    if (type & AHC_TRANS_ACTIVE)
-    {
-      aic_outb(p, scsirate, SCSIRATE);
-    }
-    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
-    p->transinfo[tindex].cur_period = period;
-    p->transinfo[tindex].cur_offset = offset;
-    p->transinfo[tindex].cur_options = options;
-    if ( !(type & AHC_TRANS_QUITE) &&
-         (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
-         (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
-    {
-      if (offset)
-      {
-        int rate_mod = (scsirate & WIDEXFER) ? 1 : 0;
-      
-        printk(INFO_LEAD "Synchronous at %s Mbyte/sec, "
-               "offset %d.\n", p->host_no, channel, target, lun,
-               syncrate->rate[rate_mod], offset);
-      }
-      else
-      {
-        printk(INFO_LEAD "Using asynchronous transfers.\n",
-               p->host_no, channel, target, lun);
-      }
-      p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
-    }
-  }
-
-  if (type & AHC_TRANS_GOAL)
-  {
-    p->transinfo[tindex].goal_period = period;
-    p->transinfo[tindex].goal_offset = offset;
-    p->transinfo[tindex].goal_options = options;
-  }
-
-  if (type & AHC_TRANS_USER)
-  {
-    p->transinfo[tindex].user_period = period;
-    p->transinfo[tindex].user_offset = offset;
-    p->transinfo[tindex].user_options = options;
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_set_width
- *
- * Description:
- *   Set the actual width down in the card and in our host structs
- *-F*************************************************************************/
-static void
-aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
-    unsigned int width, unsigned int type)
-{
-  unsigned char tindex;
-  unsigned short target_mask;
-  unsigned int old_width;
-
-  tindex = target | (channel << 3);
-  target_mask = 1 << tindex;
-  
-  old_width = p->transinfo[tindex].cur_width;
-
-  if (type & AHC_TRANS_CUR) 
-  {
-    unsigned char scsirate;
-
-    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
-
-    scsirate &= ~WIDEXFER;
-    if (width == MSG_EXT_WDTR_BUS_16_BIT)
-      scsirate |= WIDEXFER;
-
-    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
-
-    if (type & AHC_TRANS_ACTIVE)
-      aic_outb(p, scsirate, SCSIRATE);
-
-    p->transinfo[tindex].cur_width = width;
-
-    if ( !(type & AHC_TRANS_QUITE) &&
-          (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
-          (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
-    {
-      printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
-        lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
-    }
-  }
-
-  if (type & AHC_TRANS_GOAL)
-    p->transinfo[tindex].goal_width = width;
-  if (type & AHC_TRANS_USER)
-    p->transinfo[tindex].user_width = width;
-
-  if (p->transinfo[tindex].goal_offset)
-  {
-    if (p->features & AHC_ULTRA2)
-    {
-      p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-    }
-    else if (width == MSG_EXT_WDTR_BUS_16_BIT)
-    {
-      p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-    }
-    else
-    {
-      p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-    }
-  }
-}
-      
-/*+F*************************************************************************
- * Function:
- *   scbq_init
- *
- * Description:
- *   SCB queue initialization.
- *
- *-F*************************************************************************/
-static void
-scbq_init(volatile scb_queue_type *queue)
-{
-  queue->head = NULL;
-  queue->tail = NULL;
-}
-
-/*+F*************************************************************************
- * Function:
- *   scbq_insert_head
- *
- * Description:
- *   Add an SCB to the head of the list.
- *
- *-F*************************************************************************/
-static inline void
-scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
-  scb->q_next = queue->head;
-  queue->head = scb;
-  if (queue->tail == NULL)       /* If list was empty, update tail. */
-    queue->tail = queue->head;
-  DRIVER_UNLOCK
-}
-
-/*+F*************************************************************************
- * Function:
- *   scbq_remove_head
- *
- * Description:
- *   Remove an SCB from the head of the list.
- *
- *-F*************************************************************************/
-static inline struct aic7xxx_scb *
-scbq_remove_head(volatile scb_queue_type *queue)
-{
-  struct aic7xxx_scb * scbp;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
-  scbp = queue->head;
-  if (queue->head != NULL)
-    queue->head = queue->head->q_next;
-  if (queue->head == NULL)       /* If list is now empty, update tail. */
-    queue->tail = NULL;
-  DRIVER_UNLOCK
-  return(scbp);
-}
-
-/*+F*************************************************************************
- * Function:
- *   scbq_remove
- *
- * Description:
- *   Removes an SCB from the list.
- *
- *-F*************************************************************************/
-static inline void
-scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
-  if (queue->head == scb)
-  {
-    /* At beginning of queue, remove from head. */
-    scbq_remove_head(queue);
-  }
-  else
-  {
-    struct aic7xxx_scb *curscb = queue->head;
-
-    /*
-     * Search until the next scb is the one we're looking for, or
-     * we run out of queue.
-     */
-    while ((curscb != NULL) && (curscb->q_next != scb))
-    {
-      curscb = curscb->q_next;
-    }
-    if (curscb != NULL)
-    {
-      /* Found it. */
-      curscb->q_next = scb->q_next;
-      if (scb->q_next == NULL)
-      {
-        /* Update the tail when removing the tail. */
-        queue->tail = curscb;
-      }
-    }
-  }
-  DRIVER_UNLOCK
-}
-
-/*+F*************************************************************************
- * Function:
- *   scbq_insert_tail
- *
- * Description:
- *   Add an SCB at the tail of the list.
- *
- *-F*************************************************************************/
-static inline void
-scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags;
-#endif
-
-  DRIVER_LOCK
-  scb->q_next = NULL;
-  if (queue->tail != NULL)       /* Add the scb at the end of the list. */
-    queue->tail->q_next = scb;
-  queue->tail = scb;             /* Update the tail. */
-  if (queue->head == NULL)       /* If list was empty, update head. */
-    queue->head = queue->tail;
-  DRIVER_UNLOCK
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_match_scb
- *
- * Description:
- *   Checks to see if an scb matches the target/channel as specified.
- *   If target is ALL_TARGETS (-1), then we're looking for any device
- *   on the specified channel; this happens when a channel is going
- *   to be reset and all devices on that channel must be aborted.
- *-F*************************************************************************/
-static int
-aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
-    int target, int channel, int lun, unsigned char tag)
-{
-  int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
-  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
-  int slun = scb->hscb->target_channel_lun & 0x07;
-  int match;
-
-  match = ((chan == channel) || (channel == ALL_CHANNELS));
-  if (match != 0)
-    match = ((targ == target) || (target == ALL_TARGETS));
-  if (match != 0)
-    match = ((lun == slun) || (lun == ALL_LUNS));
-  if (match != 0)
-    match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
-
-  return (match);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_add_curscb_to_free_list
- *
- * Description:
- *   Adds the current scb (in SCBPTR) to the list of free SCBs.
- *-F*************************************************************************/
-static void
-aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
-{
-  /*
-   * Invalidate the tag so that aic7xxx_find_scb doesn't think
-   * it's active
-   */
-  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-  aic_outb(p, 0, SCB_CONTROL);
-
-  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
-  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_rem_scb_from_disc_list
- *
- * Description:
- *   Removes the current SCB from the disconnected list and adds it
- *   to the free list.
- *-F*************************************************************************/
-static unsigned char
-aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr,
-                               unsigned char prev)
-{
-  unsigned char next;
-
-  aic_outb(p, scbptr, SCBPTR);
-  next = aic_inb(p, SCB_NEXT);
-  aic7xxx_add_curscb_to_free_list(p);
-
-  if (prev != SCB_LIST_NULL)
-  {
-    aic_outb(p, prev, SCBPTR);
-    aic_outb(p, next, SCB_NEXT);
-  }
-  else
-  {
-    aic_outb(p, next, DISCONNECTED_SCBH);
-  }
-
-  return next;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_busy_target
- *
- * Description:
- *   Set the specified target busy.
- *-F*************************************************************************/
-static inline void
-aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_index_busy_target
- *
- * Description:
- *   Returns the index of the busy target, and optionally sets the
- *   target inactive.
- *-F*************************************************************************/
-static inline unsigned char
-aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
-    int unbusy)
-{
-  unsigned char busy_scbid;
-
-  busy_scbid = p->untagged_scbs[tcl];
-  if (unbusy)
-  {
-    p->untagged_scbs[tcl] = SCB_LIST_NULL;
-  }
-  return (busy_scbid);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_find_scb
- *
- * Description:
- *   Look through the SCB array of the card and attempt to find the
- *   hardware SCB that corresponds to the passed in SCB.  Return
- *   SCB_LIST_NULL if unsuccessful.  This routine assumes that the
- *   card is already paused.
- *-F*************************************************************************/
-static unsigned char
-aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  unsigned char saved_scbptr;
-  unsigned char curindex;
-
-  saved_scbptr = aic_inb(p, SCBPTR);
-  curindex = 0;
-  for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
-  {
-    aic_outb(p, curindex, SCBPTR);
-    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
-    {
-      break;
-    }
-  }
-  aic_outb(p, saved_scbptr, SCBPTR);
-  if (curindex >= p->scb_data->maxhscbs)
-  {
-    curindex = SCB_LIST_NULL;
-  }
-
-  return (curindex);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_allocate_scb
- *
- * Description:
- *   Get an SCB from the free list or by allocating a new one.
- *-F*************************************************************************/
-static int
-aic7xxx_allocate_scb(struct aic7xxx_host *p)
-{
-  struct aic7xxx_scb   *scbp = NULL;
-  int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6;
-  int i;
-  int step = PAGE_SIZE / 1024;
-  unsigned long scb_count = 0;
-  struct hw_scatterlist *hsgp;
-  struct aic7xxx_scb *scb_ap;
-  struct aic7xxx_scb_dma *scb_dma;
-  unsigned char *bufs;
-
-  if (p->scb_data->numscbs < p->scb_data->maxscbs)
-  {
-    /*
-     * Calculate the optimal number of SCBs to allocate.
-     *
-     * NOTE: This formula works because the sizeof(sg_array) is always
-     * 1024.  Therefore, scb_size * i would always be > PAGE_SIZE *
-     * (i/step).  The (i-1) allows the left hand side of the equation
-     * to grow into the right hand side to a point of near perfect
-     * efficiency since scb_size * (i -1) is growing slightly faster
-     * than the right hand side.  If the number of SG array elements
-     * is changed, this function may not be near so efficient any more.
-     *
-     * Since the DMA'able buffers are now allocated in a seperate
-     * chunk this algorithm has been modified to match.  The '12'
-     * and '6' factors in scb_size are for the DMA'able command byte
-     * and sensebuffers respectively.  -DaveM
-     */
-    for ( i=step;; i *= 2 )
-    {
-      if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) )
-      {
-        i /= 2;
-        break;
-      }
-    }
-    scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
-    scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
-					   + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
-    if (scb_ap == NULL)
-      return(0);
-    scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count];
-    hsgp = (struct hw_scatterlist *)
-      pci_alloc_consistent(p->pdev, scb_size * scb_count,
-			   &scb_dma->dma_address);
-    if (hsgp == NULL)
-    {
-      kfree(scb_ap);
-      return(0);
-    }
-    bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG];
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if (aic7xxx_verbose > 0xffff)
-    {
-      if (p->scb_data->numscbs == 0)
-	printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
-	  p->host_no, -1, -1, -1, scb_count);
-      else
-	printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
-	  p->host_no, -1, -1, -1, scb_count);
-    }
-#endif
-    memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count);
-    scb_dma->dma_offset = (unsigned long)scb_dma->dma_address
-			  - (unsigned long)hsgp;
-    scb_dma->dma_len = scb_size * scb_count;
-    for (i=0; i < scb_count; i++)
-    {
-      scbp = &scb_ap[i];
-      scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
-      scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
-      scbp->sense_cmd = bufs;
-      scbp->cmnd = bufs + 6;
-      bufs += 12 + 6;
-      scbp->scb_dma = scb_dma;
-      memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
-      scbp->hscb->tag = p->scb_data->numscbs;
-      /*
-       * Place in the scb array; never is removed
-       */
-      p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
-      scbq_insert_tail(&p->scb_data->free_scbs, scbp);
-    }
-    scbp->kmalloc_ptr = scb_ap;
-  }
-  return(scb_count);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_queue_cmd_complete
- *
- * Description:
- *   Due to race conditions present in the SCSI subsystem, it is easier
- *   to queue completed commands, then call scsi_done() on them when
- *   we're finished.  This function queues the completed commands.
- *-F*************************************************************************/
-static void
-aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
-{
-  cmd->host_scribble = (char *)p->completeq.head;
-  p->completeq.head = cmd;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_done_cmds_complete
- *
- * Description:
- *   Process the completed command queue.
- *-F*************************************************************************/
-static void
-aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
-{
-  Scsi_Cmnd *cmd;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned int cpu_flags = 0;
-#endif
-  
-  DRIVER_LOCK
-  while (p->completeq.head != NULL)
-  {
-    cmd = p->completeq.head;
-    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
-    cmd->host_scribble = NULL;
-    cmd->scsi_done(cmd);
-  }
-  DRIVER_UNLOCK
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_free_scb
- *
- * Description:
- *   Free the scb and insert into the free scb list.
- *-F*************************************************************************/
-static void
-aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-
-  scb->flags = SCB_FREE;
-  scb->cmd = NULL;
-  scb->sg_count = 0;
-  scb->sg_length = 0;
-  scb->tag_action = 0;
-  scb->hscb->control = 0;
-  scb->hscb->target_status = 0;
-  scb->hscb->target_channel_lun = SCB_LIST_NULL;
-
-  scbq_insert_head(&p->scb_data->free_scbs, scb);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_done
- *
- * Description:
- *   Calls the higher level scsi done function and frees the scb.
- *-F*************************************************************************/
-static void
-aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  Scsi_Cmnd *cmd = scb->cmd;
-  int tindex = TARGET_INDEX(cmd);
-  struct aic7xxx_scb *scbp;
-  unsigned char queue_depth;
-
-  if (cmd->use_sg > 1)
-  {
-    struct scatterlist *sg;
-
-    sg = (struct scatterlist *)cmd->request_buffer;
-    pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
-  }
-  else if (cmd->request_bufflen)
-    pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
-		     cmd->request_bufflen,
-                     scsi_to_pci_dma_dir(cmd->sc_data_direction));
-  if (scb->flags & SCB_SENSE)
-  {
-    pci_unmap_single(p->pdev,
-                     le32_to_cpu(scb->sg_list[0].address),
-                     sizeof(cmd->sense_buffer),
-                     PCI_DMA_FROMDEVICE);
-  }
-  if (scb->flags & SCB_RECOVERY_SCB)
-  {
-    p->flags &= ~AHC_ABORT_PENDING;
-  }
-  if (scb->flags & SCB_RESET)
-  {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
-  }
-  else if (scb->flags & SCB_ABORT)
-  {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
-  }
-  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
-  {
-    if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
-    {
-      char *buffer;
-      
-      p->dev_flags[tindex] |= DEVICE_PRESENT;
-      if(cmd->use_sg)
-      {
-        struct scatterlist *sg;
-
-        sg = (struct scatterlist *)cmd->request_buffer;
-        buffer = (char *)sg[0].address;
-      }
-      else
-      {
-        buffer = (char *)cmd->request_buffer;
-      }
-#define WIDE_INQUIRY_BITS 0x60
-#define SYNC_INQUIRY_BITS 0x10
-#define SCSI_VERSION_BITS 0x07
-#define SCSI_DT_BIT       0x04
-      if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
-           (p->features & AHC_WIDE) )
-      {
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
-      }
-      else
-      {
-        p->needwdtr &= ~(1<<tindex);
-        p->needwdtr_copy &= ~(1<<tindex);
-        pause_sequencer(p);
-        aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
-                          MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
-                                                   AHC_TRANS_GOAL |
-                                                   AHC_TRANS_CUR) );
-        unpause_sequencer(p, FALSE);
-      }
-      if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
-            p->transinfo[tindex].user_offset )
-      {
-        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
-        if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-        else
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
-               (buffer[56] & SCSI_DT_BIT) ||
-	       (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
-               (p->transinfo[tindex].user_period <= 9) &&
-               (p->transinfo[tindex].user_options) )
-        {
-          p->needppr |= (1<<tindex);
-          p->needppr_copy |= (1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
-          p->needwdtr &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-          p->dev_flags[tindex] |= DEVICE_SCSI_3;
-        }
-        else
-        {
-          p->needsdtr |= (1<<tindex);
-          p->needsdtr_copy |= (1<<tindex);
-          p->transinfo[tindex].goal_period = 
-            MAX(10, p->transinfo[tindex].goal_period);
-          p->transinfo[tindex].goal_options = 0;
-        }
-      }
-      else
-      {
-        p->needsdtr &= ~(1<<tindex);
-        p->needsdtr_copy &= ~(1<<tindex);
-        p->transinfo[tindex].goal_period = 255;
-        p->transinfo[tindex].goal_offset = 0;
-        p->transinfo[tindex].goal_options = 0;
-      }
-      /*
-       * This is needed to work around a sequencer bug for now.  Regardless
-       * of the controller in use, if we have a Quantum drive, we need to
-       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
-       * of the sequencer, this code will get yanked.
-       */
-      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
-         p->transinfo[tindex].goal_options )
-      {
-        p->transinfo[tindex].goal_period = 
-          MAX(p->transinfo[tindex].goal_period, 10);
-        p->transinfo[tindex].goal_options = 0;
-        p->needppr &= ~(1<<tindex);
-        p->needppr_copy &= ~(1<<tindex);
-        p->needsdtr |= (1<<tindex);
-        p->needsdtr_copy |= (1<<tindex);
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-      }
-      /*
-       * Get the INQUIRY checksum.  We use this on Ultra 160/m
-       * and older devices both.  It allows us to drop speed on any bus type
-       * while at the same time giving us the needed domain validation for
-       * Ultra 160/m
-       *
-       * Note: We only get the checksum and set the SCANNED bit if this is
-       * one of our dtr commands.  If we don't do this, then we end up
-       * getting bad checksum results on the mid-level SCSI code's INQUIRY
-       * commands.
-       */
-      if(p->dev_dtr_cmnd[tindex] == cmd) {
-        unsigned int checksum = 0;
-        int *ibuffer;
-        int i=0;
-
-        ibuffer = (int *)buffer;
-        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
-        {
-          checksum += ibuffer[i];
-        }
-        p->dev_checksum[tindex] = checksum;
-        p->dev_flags[tindex] |= DEVICE_SCANNED;
-        p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
-      }
-#undef WIDE_INQUIRY_BITS
-#undef SYNC_INQUIRY_BITS
-#undef SCSI_VERSION_BITS
-#undef SCSI_DT_BIT
-    }
-  }
-  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
-  {
-    unsigned short mask;
-    int message_error = FALSE;
-
-    mask = 0x01 << tindex;
- 
-    /*
-     * Check to see if we get an invalid message or a message error
-     * after failing to negotiate a wide or sync transfer message.
-     */
-    if ((scb->flags & SCB_SENSE) && 
-          ((scb->cmd->sense_buffer[12] == 0x43) ||  /* INVALID_MESSAGE */
-          (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR  */
-    {
-      message_error = TRUE;
-    }
-
-    if (scb->flags & SCB_MSGOUT_WDTR)
-    {
-      p->dtr_pending &= ~mask;
-      if (message_error)
-      {
-        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
-        {
-          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
-            "processing and\n", p->host_no, CTL_OF_SCB(scb));
-          printk(INFO_LEAD "returned a sense error code for invalid message, "
-            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
-          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
-            CTL_OF_SCB(scb));
-        }
-        p->needwdtr &= ~mask;
-        p->needwdtr_copy &= ~mask;
-      }
-    }
-    if (scb->flags & SCB_MSGOUT_SDTR)
-    {
-      p->dtr_pending &= ~mask;
-      if (message_error)
-      {
-        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
-        {
-          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
-            "processing and\n", p->host_no, CTL_OF_SCB(scb));
-          printk(INFO_LEAD "returned a sense error code for invalid message, "
-            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
-          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
-            CTL_OF_SCB(scb));
-          p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
-        }
-        p->needsdtr &= ~mask;
-        p->needsdtr_copy &= ~mask;
-      }
-    }
-    if (scb->flags & SCB_MSGOUT_PPR)
-    {
-      p->dtr_pending &= ~mask;
-      if(message_error)
-      {
-        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
-        {
-          printk(INFO_LEAD "Device failed to complete Parallel Protocol "
-            "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
-          printk(INFO_LEAD "returned a sense error code for invalid message, "
-            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
-          printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
-            "device.\n", p->host_no, CTL_OF_SCB(scb));
-        }
-        /*
-         * Disable PPR negotiation and revert back to WDTR and SDTR setup
-         */
-        p->needppr &= ~mask;
-        p->needppr_copy &= ~mask;
-        p->needsdtr |= mask;
-        p->needsdtr_copy |= mask;
-        p->needwdtr |= mask;
-        p->needwdtr_copy |= mask;
-      }
-    }
-  }
-  queue_depth = p->dev_temp_queue_depth[tindex];
-  if (queue_depth >= p->dev_active_cmds[tindex])
-  {
-    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
-    if (scbp)
-    {
-      if (queue_depth == 1)
-      {
-        /*
-         * Give extra preference to untagged devices, such as CD-R devices
-         * This makes it more likely that a drive *won't* stuff up while
-         * waiting on data at a critical time, such as CD-R writing and
-         * audio CD ripping operations.  Should also benefit tape drives.
-         */
-        scbq_insert_head(&p->waiting_scbs, scbp);
-      }
-      else
-      {
-        scbq_insert_tail(&p->waiting_scbs, scbp);
-      }
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n",
-               p->host_no, CTL_OF_SCB(scbp));
-#endif
-      if (queue_depth > p->dev_active_cmds[tindex])
-      {
-        scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
-        if (scbp)
-          scbq_insert_tail(&p->waiting_scbs, scbp);
-      }
-    }
-  }
-  if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
-  {
-    p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
-  }
-  p->dev_active_cmds[tindex]--;
-  p->activescbs--;
-
-  {
-    int actual;
-
-    /*
-     * XXX: we should actually know how much actually transferred
-     * XXX: for each command, but apparently that's too difficult.
-     * 
-     * We set a lower limit of 512 bytes on the transfer length.  We
-     * ignore anything less than this because we don't have a real
-     * reason to count it.  Read/Writes to tapes are usually about 20K
-     * and disks are a minimum of 512 bytes unless you want to count
-     * non-read/write commands (such as TEST_UNIT_READY) which we don't
-     */
-    actual = scb->sg_length;
-    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
-    {
-      struct aic7xxx_xferstats *sp;
-#ifdef AIC7XXX_PROC_STATS
-      long *ptr;
-      int x;
-#endif /* AIC7XXX_PROC_STATS */
-
-      sp = &p->stats[TARGET_INDEX(cmd)];
-
-      /*
-       * For block devices, cmd->request.cmd is always == either READ or
-       * WRITE.  For character devices, this isn't always set properly, so
-       * we check data_cmnd[0].  This catches the conditions for st.c, but
-       * I'm still not sure if request.cmd is valid for sg devices.
-       */
-      if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
-           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
-      {
-        sp->w_total++;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) )
-          aic7xxx_verbose &= 0xffff;
-#endif
-#ifdef AIC7XXX_PROC_STATS
-        ptr = sp->w_bins;
-#endif /* AIC7XXX_PROC_STATS */
-      }
-      else
-      {
-        sp->r_total++;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) )
-          aic7xxx_verbose &= 0xffff;
-#endif
-#ifdef AIC7XXX_PROC_STATS
-        ptr = sp->r_bins;
-#endif /* AIC7XXX_PROC_STATS */
-      }
-#ifdef AIC7XXX_PROC_STATS
-      x = -11;
-      while(actual)
-      {
-        actual >>= 1;
-        x++;
-      }
-      if (x < 0)
-      {
-        ptr[0]++;
-      }
-      else if (x > 7)
-      {
-        ptr[7]++;
-      }
-      else
-      {
-        ptr[x]++;
-      }
-#endif /* AIC7XXX_PROC_STATS */
-    }
-  }
-  aic7xxx_free_scb(p, scb);
-  aic7xxx_queue_cmd_complete(p, cmd);
-
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_run_done_queue
- *
- * Description:
- *   Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
- *   aborted list, and adds each scb to the free list.  If complete
- *   is TRUE, we also process the commands complete list.
- *-F*************************************************************************/
-static void
-aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
-{
-  struct aic7xxx_scb *scb;
-  int i, found = 0;
-
-  for (i = 0; i < p->scb_data->numscbs; i++)
-  {
-    scb = p->scb_data->scb_array[i];
-    if (scb->flags & SCB_QUEUED_FOR_DONE)
-    {
-      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-        printk(INFO_LEAD "Aborting scb %d\n",
-             p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
-      found++;
-      aic7xxx_done(p, scb);
-    }
-  }
-  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
-  {
-    printk(INFO_LEAD "%d commands found and queued for "
-        "completion.\n", p->host_no, -1, -1, -1, found);
-  }
-  if (complete)
-  {
-    aic7xxx_done_cmds_complete(p);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_abort_waiting_scb
- *
- * Description:
- *   Manipulate the waiting for selection list and return the
- *   scb that follows the one that we remove.
- *-F*************************************************************************/
-static unsigned char
-aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
-    unsigned char scbpos, unsigned char prev)
-{
-  unsigned char curscb, next;
-
-  /*
-   * Select the SCB we want to abort and pull the next pointer out of it.
-   */
-  curscb = aic_inb(p, SCBPTR);
-  aic_outb(p, scbpos, SCBPTR);
-  next = aic_inb(p, SCB_NEXT);
-
-  aic7xxx_add_curscb_to_free_list(p);
-
-  /*
-   * Update the waiting list
-   */
-  if (prev == SCB_LIST_NULL)
-  {
-    /*
-     * First in the list
-     */
-    aic_outb(p, next, WAITING_SCBH);
-  }
-  else
-  {
-    /*
-     * Select the scb that pointed to us and update its next pointer.
-     */
-    aic_outb(p, prev, SCBPTR);
-    aic_outb(p, next, SCB_NEXT);
-  }
-  /*
-   * Point us back at the original scb position and inform the SCSI
-   * system that the command has been aborted.
-   */
-  aic_outb(p, curscb, SCBPTR);
-  return (next);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_search_qinfifo
- *
- * Description:
- *   Search the queue-in FIFO for matching SCBs and conditionally
- *   requeue.  Returns the number of matching SCBs.
- *-F*************************************************************************/
-static int
-aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
-    int lun, unsigned char tag, int flags, int requeue,
-    volatile scb_queue_type *queue)
-{
-  int      found;
-  unsigned char qinpos, qintail;
-  struct aic7xxx_scb *scbp;
-
-  found = 0;
-  qinpos = aic_inb(p, QINPOS);
-  qintail = p->qinfifonext;
-
-  p->qinfifonext = qinpos;
-
-  while (qinpos != qintail)
-  {
-    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
-    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
-    {
-       /*
-        * We found an scb that needs to be removed.
-        */
-       if (requeue && (queue != NULL))
-       {
-         if (scbp->flags & SCB_WAITINGQ)
-         {
-           scbq_remove(queue, scbp);
-           scbq_remove(&p->waiting_scbs, scbp);
-           scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
-           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
-           p->activescbs++;
-         }
-         scbq_insert_tail(queue, scbp);
-         p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
-         p->activescbs--;
-         scbp->flags |= SCB_WAITINGQ;
-         if ( !(scbp->tag_action & TAG_ENB) )
-         {
-           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
-             TRUE);
-         }
-       }
-       else if (requeue)
-       {
-         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
-       }
-       else
-       {
-        /*
-         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
-         * flags we were called with, presumeably so aic7xxx_run_done_queue
-         * can find this scb
-         */
-         scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
-         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
-                                       FALSE) == scbp->hscb->tag)
-         {
-           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
-             TRUE);
-         }
-       }
-       found++;
-    }
-    else
-    {
-      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
-    }
-  }
-  /*
-   * Now that we've done the work, clear out any left over commands in the
-   * qinfifo and update the KERNEL_QINPOS down on the card.
-   *
-   *  NOTE: This routine expect the sequencer to already be paused when
-   *        it is run....make sure it's that way!
-   */
-  qinpos = p->qinfifonext;
-  while(qinpos != qintail)
-  {
-    p->qinfifo[qinpos++] = SCB_LIST_NULL;
-  }
-  if (p->features & AHC_QUEUE_REGS)
-    aic_outb(p, p->qinfifonext, HNSCB_QOFF);
-  else
-    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-
-  return (found);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_scb_on_qoutfifo
- *
- * Description:
- *   Is the scb that was passed to us currently on the qoutfifo?
- *-F*************************************************************************/
-static int
-aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int i=0;
-
-  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
-  {
-    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
-      return TRUE;
-    else
-      i++;
-  }
-  return FALSE;
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_reset_device
- *
- * Description:
- *   The device at the given target/channel has been reset.  Abort
- *   all active and queued scbs for that target/channel.  This function
- *   need not worry about linked next pointers because if was a MSG_ABORT_TAG
- *   then we had a tagged command (no linked next), if it was MSG_ABORT or
- *   MSG_BUS_DEV_RESET then the device won't know about any commands any more
- *   and no busy commands will exist, and if it was a bus reset, then nothing
- *   knows about any linked next commands any more.  In all cases, we don't
- *   need to worry about the linked next or busy scb, we just need to clear
- *   them.
- *-F*************************************************************************/
-static void
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
-                     int lun, unsigned char tag)
-{
-  struct aic7xxx_scb *scbp;
-  unsigned char active_scb, tcl;
-  int i = 0, j, init_lists = FALSE;
-
-  /*
-   * Restore this when we're done
-   */
-  active_scb = aic_inb(p, SCBPTR);
-
-  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
-    printk(INFO_LEAD "Reset device, active_scb %d\n",
-         p->host_no, channel, target, lun, active_scb);
-  /*
-   * Deal with the busy target and linked next issues.
-   */
-  {
-    int min_target, max_target;
-    struct aic7xxx_scb *scbp, *prev_scbp;
-
-    /* Make all targets 'relative' to bus A. */
-    if (target == ALL_TARGETS)
-    {
-      switch (channel)
-      {
-        case 0:
-                 min_target = 0;
-                 max_target = (p->features & AHC_WIDE) ? 15 : 7;
-                 break;
-        case 1:
-                 min_target = 8;
-                 max_target = 15;
-                 break;
-        case ALL_CHANNELS:
-        default:
-                 min_target = 0;
-                 max_target = (p->features & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
-                 break;
-      }
-    }
-    else
-    { 
-      min_target = target | (channel << 3);
-      max_target = min_target;
-    }
-
-
-    for (i = min_target; i <= max_target; i++)
-    {
-      if ( i == p->scsi_id )
-      {
-        continue;
-      }
-      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-        printk(INFO_LEAD "Cleaning up status information "
-          "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
-      if ( tag == SCB_LIST_NULL )
-      {
-        p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
-        p->dev_expires[i] = jiffies + (4 * HZ);
-        p->dev_timer_active |= (0x01 << i);
-        p->dev_last_queue_full_count[i] = 0;
-        p->dev_last_queue_full[i] = 0;
-        p->dev_temp_queue_depth[i] =
-          p->dev_max_queue_depth[i];
-      }
-      for(j=0; j<MAX_LUNS; j++)
-      {
-        if (channel == 1)
-          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
-        else
-          tcl = (i << 4) | (channel << 3) | j;
-        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
-             (tag == SCB_LIST_NULL) )
-          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
-      }
-      j = 0; 
-      prev_scbp = NULL; 
-      scbp = p->delayed_scbs[i].head;
-      while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
-      {
-        prev_scbp = scbp;
-        scbp = scbp->q_next;
-        if ( prev_scbp == scbp )
-        {
-          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
-              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
-          scbp = NULL;
-          prev_scbp->q_next = NULL;
-          p->delayed_scbs[i].tail = prev_scbp;
-        }
-        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
-        {
-          scbq_remove(&p->delayed_scbs[i], prev_scbp);
-          if (prev_scbp->flags & SCB_WAITINGQ)
-          {
-            p->dev_active_cmds[i]++;
-            p->activescbs++;
-          }
-          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-        }
-      }
-      if ( j > (p->scb_data->maxscbs + 1) )
-      {
-        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-          printk(WARN_LEAD "Yikes!! There's a loop in the "
-            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
-        scbq_init(&p->delayed_scbs[i]);
-      }
-      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
-            time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
-      {
-        mod_timer(&p->dev_timer, p->dev_expires[i]);
-        p->dev_timer_active |= (0x01 << MAX_TARGETS);
-      }
-    }
-  }
-
-  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
-  aic7xxx_search_qinfifo(p, target, channel, lun, tag,
-      SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
-
-/*
- *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
- *  ABORT/RESET commands.
- */
-  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
-      target, lun );
-  {
-    struct aic7xxx_scb *scbp, *prev_scbp;
-
-    j = 0; 
-    prev_scbp = NULL; 
-    scbp = p->waiting_scbs.head;
-    while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
-    {
-      prev_scbp = scbp;
-      scbp = scbp->q_next;
-      if ( prev_scbp == scbp )
-      {
-        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
-            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
-        scbp = NULL;
-        prev_scbp->q_next = NULL;
-        p->waiting_scbs.tail = prev_scbp;
-      }
-      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
-      {
-        scbq_remove(&p->waiting_scbs, prev_scbp);
-        if (prev_scbp->flags & SCB_WAITINGQ)
-        {
-          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
-          p->activescbs++;
-        }
-        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-      }
-    }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
-        printk(WARN_LEAD "Yikes!! There's a loop in the "
-          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
-      scbq_init(&p->waiting_scbs);
-    }
-  }
-
-
-  /*
-   * Search waiting for selection list.
-   */
-  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-    printk(INFO_LEAD "Cleaning waiting for selection "
-      "list.\n", p->host_no, channel, target, lun);
-  {
-    unsigned char next, prev, scb_index;
-
-    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
-    prev = SCB_LIST_NULL;
-    j = 0;
-    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
-    {
-      aic_outb(p, next, SCBPTR);
-      scb_index = aic_inb(p, SCB_TAG);
-      if (scb_index >= p->scb_data->numscbs)
-      {
-       /*
-        * No aic7xxx_verbose check here.....we want to see this since it
-        * means either the kernel driver or the sequencer screwed things up
-        */
-        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
-          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
-          p->scb_data->numscbs);
-        next = aic_inb(p, SCB_NEXT);
-        aic7xxx_add_curscb_to_free_list(p);
-      }
-      else
-      {
-        scbp = p->scb_data->scb_array[scb_index];
-        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
-        {
-          next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-          if (scbp->flags & SCB_WAITINGQ)
-          {
-            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
-            p->activescbs++;
-          }
-          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-          if (prev == SCB_LIST_NULL)
-          {
-            /*
-             * This is either the first scb on the waiting list, or we
-             * have already yanked the first and haven't left any behind.
-             * Either way, we need to turn off the selection hardware if
-             * it isn't already off.
-             */
-            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
-            aic_outb(p, CLRSELTIMEO, CLRSINT1);
-          }
-        }
-        else
-        {
-          prev = next;
-          next = aic_inb(p, SCB_NEXT);
-        }
-      }
-    }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
-        "selection list!\n", p->host_no, channel, target, lun);
-      init_lists = TRUE;
-    }
-  }
-
-  /*
-   * Go through disconnected list and remove any entries we have queued
-   * for completion, zeroing their control byte too.
-   */
-  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
-    printk(INFO_LEAD "Cleaning disconnected scbs "
-      "list.\n", p->host_no, channel, target, lun);
-  if (p->flags & AHC_PAGESCBS)
-  {
-    unsigned char next, prev, scb_index;
-
-    next = aic_inb(p, DISCONNECTED_SCBH);
-    prev = SCB_LIST_NULL;
-    j = 0;
-    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
-    {
-      aic_outb(p, next, SCBPTR);
-      scb_index = aic_inb(p, SCB_TAG);
-      if (scb_index > p->scb_data->numscbs)
-      {
-        printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
-          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
-          p->scb_data->numscbs);
-        next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
-      }
-      else
-      {
-        scbp = p->scb_data->scb_array[scb_index];
-        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
-        {
-          next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
-          if (scbp->flags & SCB_WAITINGQ)
-          {
-            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
-            p->activescbs++;
-          }
-          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-          scbp->hscb->control = 0;
-        }
-        else
-        {
-          prev = next;
-          next = aic_inb(p, SCB_NEXT);
-        }
-      }
-    }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
-        p->host_no, channel, target, lun);
-      init_lists = TRUE;
-    }
-  }
-
-  /*
-   * Walk the free list making sure no entries on the free list have
-   * a valid SCB_TAG value or SCB_CONTROL byte.
-   */
-  if (p->flags & AHC_PAGESCBS)
-  {
-    unsigned char next;
-
-    j = 0;
-    next = aic_inb(p, FREE_SCBH);
-    if ( (next >= p->scb_data->maxhscbs) && (next != SCB_LIST_NULL) )
-    {
-      printk(WARN_LEAD "Bogus FREE_SCBH!.\n", p->host_no, channel,
-        target, lun);
-      init_lists = TRUE;
-      next = SCB_LIST_NULL;
-    }
-    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
-    {
-      aic_outb(p, next, SCBPTR);
-      if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs)
-      {
-        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
-          target, lun);
-        init_lists = TRUE;
-        next = SCB_LIST_NULL;
-      }
-      else
-      {
-        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-        aic_outb(p, 0, SCB_CONTROL);
-        next = aic_inb(p, SCB_NEXT);
-      }
-    }
-    if ( j > (p->scb_data->maxscbs + 1) )
-    {
-      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
-        p->host_no, channel, target, lun);
-      init_lists = TRUE;
-    }
-  }
-
-  /*
-   * Go through the hardware SCB array looking for commands that
-   * were active but not on any list.
-   */
-  if (init_lists)
-  {
-    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
-    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
-    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
-  }
-  for (i = p->scb_data->maxhscbs - 1; i >= 0; i--)
-  {
-    unsigned char scbid;
-
-    aic_outb(p, i, SCBPTR);
-    if (init_lists)
-    {
-      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
-      aic_outb(p, 0, SCB_CONTROL);
-      aic7xxx_add_curscb_to_free_list(p);
-    }
-    else
-    {
-      scbid = aic_inb(p, SCB_TAG);
-      if (scbid < p->scb_data->numscbs)
-      {
-        scbp = p->scb_data->scb_array[scbid];
-        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
-        {
-          aic_outb(p, 0, SCB_CONTROL);
-          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-          aic7xxx_add_curscb_to_free_list(p);
-        }
-      }
-    }
-  }
-
-  /*
-   * Go through the entire SCB array now and look for commands for
-   * for this target that are stillactive.  These are other (most likely
-   * tagged) commands that were disconnected when the reset occurred.
-   * Any commands we find here we know this about, it wasn't on any queue,
-   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
-   * lists, so it really must have been a paged out SCB.  In that case,
-   * we shouldn't need to bother with updating any counters, just mark
-   * the correct flags and go on.
-   */
-  for (i = 0; i < p->scb_data->numscbs; i++)
-  {
-    scbp = p->scb_data->scb_array[i];
-    if ((scbp->flags & SCB_ACTIVE) &&
-        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
-        !aic7xxx_scb_on_qoutfifo(p, scbp))
-    {
-      if (scbp->flags & SCB_WAITINGQ)
-      {
-        scbq_remove(&p->waiting_scbs, scbp);
-        scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
-        p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
-        p->activescbs++;
-      }
-      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
-      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
-    }
-  }
-
-  aic_outb(p, active_scb, SCBPTR);
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_clear_intstat
- *
- * Description:
- *   Clears the interrupt status.
- *-F*************************************************************************/
-static void
-aic7xxx_clear_intstat(struct aic7xxx_host *p)
-{
-  /* Clear any interrupt conditions this may have caused. */
-  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
-  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
-       CLRPHASECHG | CLRREQINIT, CLRSINT1);
-  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_reset_current_bus
- *
- * Description:
- *   Reset the current SCSI bus.
- *-F*************************************************************************/
-static void
-aic7xxx_reset_current_bus(struct aic7xxx_host *p)
-{
-
-  /* Disable reset interrupts. */
-  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
-
-  /* Turn off the bus' current operations, after all, we shouldn't have any
-   * valid commands left to cause a RSELI and SELO once we've tossed the
-   * bus away with this reset, so we might as well shut down the sequencer
-   * until the bus is restarted as oppossed to saving the current settings
-   * and restoring them (which makes no sense to me). */
-
-  /* Turn on the bus reset. */
-  aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ);
-  while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
-    mdelay(5);
-
-  /*
-   * Some of the new Ultra2 chipsets need a longer delay after a chip
-   * reset than just the init setup creates, so we have to delay here
-   * before we go into a reset in order to make the chips happy.
-   */
-  if (p->features & AHC_ULTRA2)
-    mdelay(250);
-  else
-    mdelay(50);
-
-  /* Turn off the bus reset. */
-  aic_outb(p, 0, SCSISEQ);
-  mdelay(10);
-
-  aic7xxx_clear_intstat(p);
-  /* Re-enable reset interrupts. */
-  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
-
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_reset_channel
- *
- * Description:
- *   Reset the channel.
- *-F*************************************************************************/
-static void
-aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
-{
-  unsigned long offset_min, offset_max;
-  unsigned char sblkctl;
-  int cur_channel;
-
-  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
-      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
-
-
-  if (channel == 1)
-  {
-    p->needsdtr |= (p->needsdtr_copy & 0xFF00);
-    p->dtr_pending &= 0x00FF;
-    offset_min = 8;
-    offset_max = 16;
-  }
-  else
-  {
-    if (p->features & AHC_TWIN)
-    {
-      /* Channel A */
-      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
-      p->dtr_pending &= 0xFF00;
-      offset_min = 0;
-      offset_max = 8;
-    }
-    else
-    {
-      p->needppr = p->needppr_copy;
-      p->needsdtr = p->needsdtr_copy;
-      p->needwdtr = p->needwdtr_copy;
-      p->dtr_pending = 0x0;
-      offset_min = 0;
-      if (p->features & AHC_WIDE)
-      {
-        offset_max = 16;
-      }
-      else
-      {
-        offset_max = 8;
-      }
-    }
-  }
-
-  while (offset_min < offset_max)
-  {
-    /*
-     * Revert to async/narrow transfers until we renegotiate.
-     */
-    aic_outb(p, 0, TARG_SCSIRATE + offset_min);
-    if (p->features & AHC_ULTRA2)
-    {
-      aic_outb(p, 0, TARG_OFFSET + offset_min);
-    }
-    offset_min++;
-  }
-
-  /*
-   * Reset the bus and unpause/restart the controller
-   */
-  sblkctl = aic_inb(p, SBLKCTL);
-  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
-    cur_channel = (sblkctl & SELBUSB) >> 3;
-  else
-    cur_channel = 0;
-  if ( (cur_channel != channel) && (p->features & AHC_TWIN) )
-  {
-    /*
-     * Case 1: Command for another bus is active
-     */
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
-        channel, -1, -1);
-    /*
-     * Stealthily reset the other bus without upsetting the current bus.
-     */
-    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
-    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
-    if (initiate_reset)
-    {
-      aic7xxx_reset_current_bus(p);
-    }
-    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
-    aic7xxx_clear_intstat(p);
-    aic_outb(p, sblkctl, SBLKCTL);
-  }
-  else
-  {
-    /*
-     * Case 2: A command from this bus is active or we're idle.
-     */
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
-        channel, -1, -1);
-    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
-      SIMODE1);
-    p->flags &= ~AHC_HANDLING_REQINITS;
-    p->msg_type = MSG_TYPE_NONE;
-    p->msg_len = 0;
-    if (initiate_reset)
-    {
-      aic7xxx_reset_current_bus(p);
-    }
-    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
-    aic7xxx_clear_intstat(p);
-  }
-  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
-  /*
-   * Clean up all the state information for the pending transactions
-   * on this bus.
-   */
-  aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
-
-  if ( !(p->features & AHC_TWIN) )
-  {
-    restart_sequencer(p);
-  }
-
-  return;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_run_waiting_queues
- *
- * Description:
- *   Scan the awaiting_scbs queue downloading and starting as many
- *   scbs as we can.
- *-F*************************************************************************/
-static void
-aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
-{
-  struct aic7xxx_scb *scb;
-  int tindex;
-  int sent;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
-
-
-  if (p->waiting_scbs.head == NULL)
-    return;
-
-  sent = 0;
-
-  /*
-   * First handle SCBs that are waiting but have been assigned a slot.
-   */
-  DRIVER_LOCK
-  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
-  {
-    tindex = TARGET_INDEX(scb->cmd);
-    if ( !scb->tag_action && (p->tagenable & (1<<tindex)) )
-    {
-      p->dev_temp_queue_depth[tindex] = 1;
-    }
-    if ( (p->dev_active_cmds[tindex] >=
-          p->dev_temp_queue_depth[tindex]) ||
-         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) ||
-         (p->flags & AHC_RESET_DELAY) )
-    {
-      scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-    }
-    else
-    {
-        scb->flags &= ~SCB_WAITINGQ;
-        p->dev_active_cmds[tindex]++;
-        p->activescbs++;
-        if ( !(scb->tag_action) )
-        {
-          aic7xxx_busy_target(p, scb);
-        }
-        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
-        sent++;
-    }
-  }
-  if (sent)
-  {
-    if (p->features & AHC_QUEUE_REGS)
-      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
-    else
-    {
-      pause_sequencer(p);
-      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-      unpause_sequencer(p, FALSE);
-    }
-    if (p->activescbs > p->max_activescbs)
-      p->max_activescbs = p->activescbs;
-  }
-  DRIVER_UNLOCK
-}
-
-#ifdef CONFIG_PCI
-
-#define  DPE 0x80
-#define  SSE 0x40
-#define  RMA 0x20
-#define  RTA 0x10
-#define  STA 0x08
-#define  DPR 0x01
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_pci_intr
- *
- * Description:
- *   Check the scsi card for PCI errors and clear the interrupt
- *
- *   NOTE: If you don't have this function and a 2940 card encounters
- *         a PCI error condition, the machine will end up locked as the
- *         interrupt handler gets slammed with non-stop PCI error interrupts
- *-F*************************************************************************/
-static void
-aic7xxx_pci_intr(struct aic7xxx_host *p)
-{
-  unsigned char status1;
-
-  pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1);
-
-  if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
-      "phase.\n", p->host_no, -1, -1, -1);
-  if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
-      -1, -1, -1);
-  if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
-    printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
-      "PERR#\n", p->host_no, -1, -1, -1);
-  
-  pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1);
-  if (status1 & (DPR|RMA|RTA))
-    aic_outb(p,  CLRPARERR, CLRINT);
-
-  if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) )
-    aic7xxx_panic_abort(p, NULL);
-
-}
-#endif /* CONFIG_PCI */
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_timer
- *
- * Description:
- *   Take expired extries off of delayed queues and place on waiting queue
- *   then run waiting queue to start commands.
- ***************************************************************************/
-static void
-aic7xxx_timer(struct aic7xxx_host *p)
-{
-  int i, j;
-  unsigned long cpu_flags = 0;
-  struct aic7xxx_scb *scb;
-
-  spin_lock_irqsave(&io_request_lock, cpu_flags);
-  p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
-  if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
-       time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
-  {
-    p->flags &= ~AHC_RESET_DELAY;
-    p->dev_timer_active &= ~(0x01 << p->scsi_id);
-  }
-  for(i=0; i<MAX_TARGETS; i++)
-  {
-    if ( (i != p->scsi_id) &&
-         (p->dev_timer_active & (0x01 << i)) &&
-         time_after_eq(jiffies, p->dev_expires[i]) )
-    {
-      p->dev_timer_active &= ~(0x01 << i);
-      p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY);
-      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
-      j = 0;
-      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
-              (j++ < p->scb_data->numscbs) )
-      {
-        scbq_insert_tail(&p->waiting_scbs, scb);
-      }
-      if (j == p->scb_data->numscbs)
-      {
-        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
-          p->host_no, 0, i, -1);
-        scbq_init(&p->delayed_scbs[i]);
-        scbq_init(&p->waiting_scbs);
-        /*
-         * Well, things are screwed now, wait for a reset to clean the junk
-         * out.
-         */
-      }
-    }
-    else if ( p->dev_timer_active & (0x01 << i) )
-    {
-      if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
-      {
-        if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
-        {
-          p->dev_timer.expires = p->dev_expires[i];
-        }
-      }
-      else
-      {
-        p->dev_timer.expires = p->dev_expires[i];
-        p->dev_timer_active |= (0x01 << MAX_TARGETS);
-      }
-    }
-  }
-  if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
-  {
-    add_timer(&p->dev_timer);
-  }
-
-  aic7xxx_run_waiting_queues(p);
-  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_construct_ppr
- *
- * Description:
- *   Build up a Parallel Protocol Request message for use with SCSI-3
- *   devices.
- *-F*************************************************************************/
-static void
-aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int tindex = TARGET_INDEX(scb->cmd);
-
-  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
-  p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
-  p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
-  p->msg_buf[p->msg_index++] = 0;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
-  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
-  p->msg_len += 8;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_construct_sdtr
- *
- * Description:
- *   Constucts a synchronous data transfer message in the message
- *   buffer on the sequencer.
- *-F*************************************************************************/
-static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
-        unsigned char offset)
-{
-  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
-  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
-  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
-  p->msg_buf[p->msg_index++] = period;
-  p->msg_buf[p->msg_index++] = offset;
-  p->msg_len += 5;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_construct_wdtr
- *
- * Description:
- *   Constucts a wide data transfer message in the message buffer
- *   on the sequencer.
- *-F*************************************************************************/
-static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
-{
-  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
-  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
-  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
-  p->msg_buf[p->msg_index++] = bus_width;
-  p->msg_len += 4;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_calc_residual
- *
- * Description:
- *   Calculate the residual data not yet transferred.
- *-F*************************************************************************/
-static void
-aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  struct aic7xxx_hwscb *hscb;
-  Scsi_Cmnd *cmd;
-  int actual, i;
-
-  cmd = scb->cmd;
-  hscb = scb->hscb;
-
-  /*
-   *  Don't destroy valid residual information with
-   *  residual coming from a check sense operation.
-   */
-  if (((scb->hscb->control & DISCONNECTED) == 0) &&
-      (scb->flags & SCB_SENSE) == 0)
-  {
-    /*
-     *  We had an underflow. At this time, there's only
-     *  one other driver that bothers to check for this,
-     *  and cmd->underflow seems to be set rather half-
-     *  heartedly in the higher-level SCSI code.
-     */
-    actual = scb->sg_length;
-    for (i=1; i < hscb->residual_SG_segment_count; i++)
-    {
-      actual -= scb->sg_list[scb->sg_count - i].length;
-    }
-    actual -= (hscb->residual_data_count[2] << 16) |
-              (hscb->residual_data_count[1] <<  8) |
-              hscb->residual_data_count[0];
-
-    if (actual < cmd->underflow)
-    {
-      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
-        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
-          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
-          (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
-          hscb->residual_SG_segment_count);
-      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-      aic7xxx_status(cmd) = hscb->target_status;
-    }
-  }
-
-  /*
-   * Clean out the residual information in the SCB for the
-   * next consumer.
-   */
-  hscb->residual_data_count[2] = 0;
-  hscb->residual_data_count[1] = 0;
-  hscb->residual_data_count[0] = 0;
-  hscb->residual_SG_segment_count = 0;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_device_reset
- *
- * Description:
- *   Interrupt handler for sequencer interrupts (SEQINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
-{
-  unsigned short targ_mask;
-  unsigned char tindex = target;
-
-  tindex |= ((channel & 0x01) << 3);
-
-  targ_mask = (0x01 << tindex);
-  /*
-   * Go back to async/narrow transfers and renegotiate.
-   */
-  p->needppr |= (p->needppr_copy & targ_mask);
-  p->needsdtr |= (p->needsdtr_copy & targ_mask);
-  p->needwdtr |= (p->needwdtr_copy & targ_mask);
-  p->dtr_pending &= ~targ_mask;
-  aic_outb(p, 0, TARG_SCSIRATE + tindex);
-  if (p->features & AHC_ULTRA2)
-    aic_outb(p, 0, TARG_OFFSET + tindex);
-  aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
-      target, -1);
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_seqint
- *
- * Description:
- *   Interrupt handler for sequencer interrupts (SEQINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
-{
-  struct aic7xxx_scb *scb;
-  unsigned short target_mask;
-  unsigned char target, lun, tindex;
-  unsigned char queue_flag = FALSE;
-  char channel;
-
-  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
-  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
-    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
-  else
-    channel = 0;
-  tindex = target + (channel << 3);
-  lun = aic_inb(p, SAVED_TCL) & 0x07;
-  target_mask = (0x01 << tindex);
-
-  /*
-   * Go ahead and clear the SEQINT now, that avoids any interrupt race
-   * conditions later on in case we enable some other interrupt.
-   */
-  aic_outb(p, CLRSEQINT, CLRINT);
-  switch (intstat & SEQINT_MASK)
-  {
-    case NO_MATCH:
-      {
-        aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
-                 SCSISEQ);
-        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
-               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
-        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
-               p->host_no, channel, target, lun,
-               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
-               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
-        if (aic7xxx_panic_on_abort)
-          aic7xxx_panic_abort(p, NULL);
-      }
-      break;
-
-    case SEND_REJECT:
-      {
-        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
-          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
-            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
-            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
-      }
-      break;
-
-    case NO_IDENT:
-      {
-        /*
-         * The reconnecting target either did not send an identify
-         * message, or did, but we didn't find an SCB to match and
-         * before it could respond to our ATN/abort, it hit a dataphase.
-         * The only safe thing to do is to blow it away with a bus
-         * reset.
-         */
-        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
-          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
-            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
-            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
-
-        aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
-        aic7xxx_run_done_queue(p, TRUE);
-
-      }
-      break;
-
-    case BAD_PHASE:
-      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
-      {
-        if (aic7xxx_verbose & VERBOSE_SEQINT)
-          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
-            target, lun);
-        restart_sequencer(p);
-      }
-      else
-      {
-        if (aic7xxx_verbose & VERBOSE_SEQINT)
-          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
-            channel, target, lun);
-      }
-      break;
-
-    case EXTENDED_MSG:
-      {
-        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
-        p->msg_len = 0;
-        p->msg_index = 0;
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if (aic7xxx_verbose > 0xffff)
-          printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no,
-                 channel, target, lun);
-#endif
-
-       /*      
-        * To actually receive the message, simply turn on
-        * REQINIT interrupts and let our interrupt handler
-        * do the rest (REQINIT should already be true).
-        */
-        p->flags |= AHC_HANDLING_REQINITS;
-        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
-
-       /*
-        * We don't want the sequencer unpaused yet so we return early
-        */
-        return;
-      }
-
-    case REJECT_MSG:
-      {
-        /*
-         * What we care about here is if we had an outstanding SDTR
-         * or WDTR message for this target. If we did, this is a
-         * signal that the target is refusing negotiation.
-         */
-        unsigned char scb_index;
-        unsigned char last_msg;
-
-        scb_index = aic_inb(p, SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-        last_msg = aic_inb(p, LAST_MSG);
-
-        if ( (last_msg == MSG_IDENTIFYFLAG) &&
-             (scb->tag_action) &&
-            !(scb->flags & SCB_MSGOUT_BITS) )
-        {
-          if (scb->tag_action == MSG_ORDERED_Q_TAG)
-          {
-            /*
-             * OK...the device seems able to accept tagged commands, but
-             * not ordered tag commands, only simple tag commands.  So, we
-             * disable ordered tag commands and go on with life just like
-             * normal.
-             */
-            p->orderedtag &= ~target_mask;
-            scb->tag_action = MSG_SIMPLE_Q_TAG;
-            scb->hscb->control &= ~SCB_TAG_TYPE;
-            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
-            aic_outb(p, scb->hscb->control, SCB_CONTROL);
-            /*
-             * OK..we set the tag type to simple tag command, now we re-assert
-             * ATNO and hope this will take us into the identify phase again
-             * so we can resend the tag type and info to the device.
-             */
-            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
-          }
-          else if (scb->tag_action == MSG_SIMPLE_Q_TAG)
-          {
-            unsigned char i, reset = 0;
-            struct aic7xxx_scb *scbp;
-            int old_verbose;
-            /*
-             * Hmmmm....the device is flaking out on tagged commands.  The
-             * bad thing is that we already have tagged commands enabled in
-             * the device struct in the mid level code.  We also have a queue
-             * set according to the tagged queue depth.  Gonna have to live
-             * with it by controlling our queue depth internally and making
-             * sure we don't set the tagged command flag any more.
-             */
-            p->tagenable &= ~target_mask;
-            p->orderedtag &= ~target_mask;
-            p->dev_max_queue_depth[tindex] =
-               p->dev_temp_queue_depth[tindex] = 1;
-            /*
-             * We set this command up as a bus device reset.  However, we have
-             * to clear the tag type as it's causing us problems.  We shouldnt
-             * have to worry about any other commands being active, since if
-             * the device is refusing tagged commands, this should be the
-             * first tagged command sent to the device, however, we do have
-             * to worry about any other tagged commands that may already be
-             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
-             * send all the commands back to the mid level code, then let them
-             * come back and get rebuilt as untagged commands.
-             */
-            scb->tag_action = 0;
-            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
-            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
-
-            old_verbose = aic7xxx_verbose;
-            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
-            for (i=0; i!=p->scb_data->numscbs; i++)
-            {
-              scbp = p->scb_data->scb_array[i];
-              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
-              {
-                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
-                {
-                  aic7xxx_reset_device(p, target, channel, lun, i);
-                  reset++;
-                }
-                aic7xxx_run_done_queue(p, TRUE);
-              }
-            }
-            aic7xxx_verbose = old_verbose;
-            /*
-             * Wait until after the for loop to set the busy index since
-             * aic7xxx_reset_device will clear the busy index during its
-             * operation.
-             */
-            aic7xxx_busy_target(p, scb);
-            printk(INFO_LEAD "Device is refusing tagged commands, using "
-              "untagged I/O.\n", p->host_no, channel, target, lun);
-            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
-          }
-        }
-        else if (scb->flags & SCB_MSGOUT_PPR)
-        {
-          /*
-           * As per the draft specs, any device capable of supporting any of
-           * the option values other than 0 are not allowed to reject the
-           * PPR message.  Instead, they must negotiate out what they do
-           * support instead of rejecting our offering or else they cause
-           * a parity error during msg_out phase to signal that they don't
-           * like our settings.
-           */
-          p->needppr &= ~target_mask;
-          p->needppr_copy &= ~target_mask;
-          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
-            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-          p->transinfo[tindex].goal_options = 0;
-          p->dtr_pending &= ~target_mask;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Device is rejecting PPR messages, falling "
-              "back.\n", p->host_no, channel, target, lun);
-          }
-          if ( p->transinfo[tindex].goal_width )
-          {
-            p->needwdtr |= target_mask;
-            p->needwdtr_copy |= target_mask;
-            p->dtr_pending |= target_mask;
-            scb->flags |= SCB_MSGOUT_WDTR;
-          }
-          if ( p->transinfo[tindex].goal_offset )
-          {
-            p->needsdtr |= target_mask;
-            p->needsdtr_copy |= target_mask;
-            if( !(p->dtr_pending & target_mask) )
-            {
-              p->dtr_pending |= target_mask;
-              scb->flags |= SCB_MSGOUT_SDTR;
-            }
-          }
-          if ( p->dtr_pending & target_mask )
-          {
-            aic_outb(p, HOST_MSG, MSG_OUT);
-            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
-          }
-        }
-        else if (scb->flags & SCB_MSGOUT_WDTR)
-        {
-          /*
-           * note 8bit xfers and clear flag
-           */
-          p->needwdtr &= ~target_mask;
-          p->needwdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
-            (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Device is rejecting WDTR messages, using "
-              "narrow transfers.\n", p->host_no, channel, target, lun);
-          }
-          p->needsdtr |= (p->needsdtr_copy & target_mask);
-        }
-        else if (scb->flags & SCB_MSGOUT_SDTR)
-        {
-         /*
-          * note asynch xfers and clear flag
-          */
-          p->needsdtr &= ~target_mask;
-          p->needsdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
-          scb->flags &= ~SCB_MSGOUT_SDTR;
-          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-            (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
-          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Device is rejecting SDTR messages, using "
-              "async transfers.\n", p->host_no, channel, target, lun);
-          }
-        }
-        else if (aic7xxx_verbose & VERBOSE_SEQINT)
-        {
-          /*
-           * Otherwise, we ignore it.
-           */
-          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
-            "Ignoring.\n", p->host_no, channel, target, lun);
-        }
-      }
-      break;
-
-    case BAD_STATUS:
-      {
-        unsigned char scb_index;
-        struct aic7xxx_hwscb *hscb;
-        Scsi_Cmnd *cmd;
-
-        /* The sequencer will notify us when a command has an error that
-         * would be of interest to the kernel.  This allows us to leave
-         * the sequencer running in the common case of command completes
-         * without error.  The sequencer will have DMA'd the SCB back
-         * up to us, so we can reference the drivers SCB array.
-         *
-         * Set the default return value to 0 indicating not to send
-         * sense.  The sense code will change this if needed and this
-         * reduces code duplication.
-         */
-        aic_outb(p, 0, RETURN_1);
-        scb_index = aic_inb(p, SCB_TAG);
-        if (scb_index > p->scb_data->numscbs)
-        {
-          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
-            p->host_no, channel, target, lun, intstat, scb_index);
-          break;
-        }
-        scb = p->scb_data->scb_array[scb_index];
-        hscb = scb->hscb;
-
-        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-        {
-          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
-            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
-            scb_index, scb->flags, (unsigned long) scb->cmd);
-        }
-        else
-        {
-          cmd = scb->cmd;
-          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
-          aic7xxx_status(cmd) = hscb->target_status;
-
-          cmd->result = hscb->target_status;
-
-          switch (status_byte(hscb->target_status))
-          {
-            case GOOD:
-              if (aic7xxx_verbose & VERBOSE_SEQINT)
-                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
-                  p->host_no, CTL_OF_SCB(scb));
-              break;
-
-            case COMMAND_TERMINATED:
-            case CHECK_CONDITION:
-              if ( !(scb->flags & SCB_SENSE) )
-              {
-                /*
-                 * Send a sense command to the requesting target.
-                 * XXX - revisit this and get rid of the memcopys.
-                 */
-                memcpy(scb->sense_cmd, &generic_sense[0],
-                       sizeof(generic_sense));
-
-                scb->sense_cmd[1] = (cmd->lun << 5);
-                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
-                scb->sg_list[0].length = 
-                  cpu_to_le32(sizeof(cmd->sense_buffer));
-		scb->sg_list[0].address =
-                        cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
-                                                   sizeof(cmd->sense_buffer),
-                                                   PCI_DMA_FROMDEVICE));
-
-                /*
-                 * XXX - We should allow disconnection, but can't as it
-                 * might allow overlapped tagged commands.
-                 */
-                /* hscb->control &= DISCENB; */
-                hscb->control = 0;
-                hscb->target_status = 0;
-                hscb->SG_list_pointer = 
-		  cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
-                hscb->SCSI_cmd_pointer = 
-                  cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
-                hscb->data_count = scb->sg_list[0].length;
-                hscb->data_pointer = scb->sg_list[0].address;
-                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-                hscb->residual_SG_segment_count = 0;
-                hscb->residual_data_count[0] = 0;
-                hscb->residual_data_count[1] = 0;
-                hscb->residual_data_count[2] = 0;
-
-                scb->sg_count = hscb->SG_segment_count = 1;
-                scb->sg_length = sizeof(cmd->sense_buffer);
-                scb->tag_action = 0;
-                scb->flags |= SCB_SENSE;
-                /*
-                 * Ensure the target is busy since this will be an
-                 * an untagged request.
-                 */
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-                if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-                {
-                  if (scb->flags & SCB_MSGOUT_BITS)
-                    printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
-                           CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ?
-                           "SDTR" : "WDTR");
-                  else
-                    printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no,
-                           CTL_OF_SCB(scb));
-                }
-#endif
-                aic7xxx_busy_target(p, scb);
-                aic_outb(p, SEND_SENSE, RETURN_1);
-                aic7xxx_error(cmd) = DID_OK;
-                break;
-              }  /* first time sense, no errors */
-              aic7xxx_error(cmd) = DID_ERROR;
-              scb->flags &= ~SCB_SENSE;
-              break;
-
-            case QUEUE_FULL:
-              queue_flag = TRUE;    /* Mark that this is a QUEUE_FULL and */
-            case BUSY:              /* drop through to here */
-            {
-              struct aic7xxx_scb *next_scbp, *prev_scbp;
-              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
-              /*
-               * We have to look three places for queued commands:
-               *  1: QINFIFO
-               *  2: p->waiting_scbs queue
-               *  3: WAITING_SCBS list on card (for commands that are started
-               *     but haven't yet made it to the device)
-               */
-              aic7xxx_search_qinfifo(p, target, channel, lun,
-                SCB_LIST_NULL, 0, TRUE,
-                &p->delayed_scbs[tindex]);
-              next_scbp = p->waiting_scbs.head;
-              while ( next_scbp != NULL )
-              {
-                prev_scbp = next_scbp;
-                next_scbp = next_scbp->q_next;
-                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
-                     SCB_LIST_NULL) )
-                {
-                  scbq_remove(&p->waiting_scbs, prev_scbp);
-                  scbq_insert_tail(&p->delayed_scbs[tindex],
-                    prev_scbp);
-                }
-              }
-              next_scbp = NULL;
-              active_hscb = aic_inb(p, SCBPTR);
-              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
-              next_hscb = aic_inb(p, WAITING_SCBH);
-              while (next_hscb != SCB_LIST_NULL)
-              {
-                aic_outb(p, next_hscb, SCBPTR);
-                scb_index = aic_inb(p, SCB_TAG);
-                if (scb_index < p->scb_data->numscbs)
-                {
-                  next_scbp = p->scb_data->scb_array[scb_index];
-                  if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
-                      SCB_LIST_NULL) )
-                  {
-                    if (next_scbp->flags & SCB_WAITINGQ)
-                    {
-                      p->dev_active_cmds[tindex]++;
-                      p->activescbs--;
-                      scbq_remove(&p->delayed_scbs[tindex], next_scbp);
-                      scbq_remove(&p->waiting_scbs, next_scbp);
-                    }
-                    scbq_insert_head(&p->delayed_scbs[tindex],
-                      next_scbp);
-                    next_scbp->flags |= SCB_WAITINGQ;
-                    p->dev_active_cmds[tindex]--;
-                    p->activescbs--;
-                    next_hscb = aic_inb(p, SCB_NEXT);
-                    aic_outb(p, 0, SCB_CONTROL);
-                    aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-                    aic7xxx_add_curscb_to_free_list(p);
-                    if (prev_hscb == SCB_LIST_NULL)
-                    {
-                      /* We were first on the list,
-                       * so we kill the selection
-                       * hardware.  Let the sequencer
-                       * re-init the hardware itself
-                       */
-                      aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
-                      aic_outb(p, CLRSELTIMEO, CLRSINT1);
-                      aic_outb(p, next_hscb, WAITING_SCBH);
-                    }
-                    else
-                    {
-                      aic_outb(p, prev_hscb, SCBPTR);
-                      aic_outb(p, next_hscb, SCB_NEXT);
-                    }
-                  }
-                  else
-                  {
-                    prev_hscb = next_hscb;
-                    next_hscb = aic_inb(p, SCB_NEXT);
-                  }
-                } /* scb_index >= p->scb_data->numscbs */
-              }
-              aic_outb(p, active_hscb, SCBPTR);
-              if (scb->flags & SCB_WAITINGQ)
-              {
-                scbq_remove(&p->delayed_scbs[tindex], scb);
-                scbq_remove(&p->waiting_scbs, scb);
-                p->dev_active_cmds[tindex]++;
-                p->activescbs++;
-              }
-              scbq_insert_head(&p->delayed_scbs[tindex], scb);
-              p->dev_active_cmds[tindex]--;
-              p->activescbs--;
-              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
-                  
-              if ( !(p->dev_timer_active & (0x01 << tindex)) ) 
-              {
-                p->dev_timer_active |= (0x01 << tindex);
-                if ( p->dev_active_cmds[tindex] )
-                {
-                  p->dev_expires[tindex] = jiffies + HZ;
-                }
-                else
-                {
-                  p->dev_expires[tindex] = jiffies + (HZ / 10);
-                }
-                if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) )
-                {
-                  p->dev_timer.expires = p->dev_expires[tindex];
-                  p->dev_timer_active |= (0x01 << MAX_TARGETS);
-                  add_timer(&p->dev_timer);
-                }
-                else if ( time_after_eq(p->dev_timer.expires,
-                                        p->dev_expires[tindex]) )
-                  mod_timer(&p->dev_timer, p->dev_expires[tindex]);
-              }
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-              if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
-                  (aic7xxx_verbose > 0xffff) )
-              {
-                if (queue_flag)
-                  printk(INFO_LEAD "Queue full received; queue depth %d, "
-                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
-                    p->dev_max_queue_depth[tindex],
-                    p->dev_active_cmds[tindex]);
-                else
-                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
-
-              }
-#endif
-              if (queue_flag)
-              {
-                if ( p->dev_last_queue_full[tindex] !=
-                     p->dev_active_cmds[tindex] )
-                {
-                  p->dev_last_queue_full[tindex] = 
-                      p->dev_active_cmds[tindex];
-                  p->dev_last_queue_full_count[tindex] = 0;
-                }
-                else
-                {
-                  p->dev_last_queue_full_count[tindex]++;
-                }
-                if ( (p->dev_last_queue_full_count[tindex] > 14) &&
-                     (p->dev_active_cmds[tindex] > 4) )
-                {
-                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
-                      CTL_OF_SCB(scb), p->dev_active_cmds[tindex]);
-                  p->dev_max_queue_depth[tindex] = 
-                      p->dev_active_cmds[tindex];
-                  p->dev_last_queue_full[tindex] = 0;
-                  p->dev_last_queue_full_count[tindex] = 0;
-                  p->dev_temp_queue_depth[tindex] = 
-                    p->dev_active_cmds[tindex];
-                }
-                else if (p->dev_active_cmds[tindex] == 0)
-                {
-                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
-                  {
-                    printk(INFO_LEAD "QUEUE_FULL status received with 0 "
-                           "commands active.\n", p->host_no, CTL_OF_SCB(scb));
-                    printk(INFO_LEAD "Tagged Command Queueing disabled\n",
-                           p->host_no, CTL_OF_SCB(scb));
-                  }
-                  p->dev_max_queue_depth[tindex] = 1;
-                  p->dev_temp_queue_depth[tindex] = 1;
-                  scb->tag_action = 0;
-                  scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG);
-                }
-                else
-                {
-                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
-                  p->dev_temp_queue_depth[tindex] = 
-                    p->dev_active_cmds[tindex];
-                }
-              }
-              break;
-            }
-            
-            default:
-              if (aic7xxx_verbose & VERBOSE_SEQINT)
-                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
-                     CTL_OF_SCB(scb), scb->hscb->target_status);
-              if (!aic7xxx_error(cmd))
-              {
-                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-              }
-              break;
-          }  /* end switch */
-        }  /* end else of */
-      }
-      break;
-
-    case AWAITING_MSG:
-      {
-        unsigned char scb_index, msg_out;
-
-        scb_index = aic_inb(p, SCB_TAG);
-        msg_out = aic_inb(p, MSG_OUT);
-        scb = p->scb_data->scb_array[scb_index];
-        p->msg_index = p->msg_len = 0;
-        /*
-         * This SCB had a MK_MESSAGE set in its control byte informing
-         * the sequencer that we wanted to send a special message to
-         * this target.
-         */
-
-        if ( !(scb->flags & SCB_DEVICE_RESET) &&
-              (msg_out == MSG_IDENTIFYFLAG) &&
-              (scb->hscb->control & TAG_ENB) )
-        {
-          p->msg_buf[p->msg_index++] = scb->tag_action;
-          p->msg_buf[p->msg_index++] = scb->hscb->tag;
-          p->msg_len += 2;
-        }
-
-        if (scb->flags & SCB_DEVICE_RESET)
-        {
-          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
-          p->msg_len++;
-          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-            printk(INFO_LEAD "Bus device reset mailed.\n",
-                 p->host_no, CTL_OF_SCB(scb));
-        }
-        else if (scb->flags & SCB_ABORT)
-        {
-          if (scb->tag_action)
-          {
-            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
-          }
-          else
-          {
-            p->msg_buf[p->msg_index++] = MSG_ABORT;
-          }
-          p->msg_len++;
-          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
-              CTL_OF_SCB(scb));
-        }
-        else if (scb->flags & SCB_MSGOUT_PPR)
-        {
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   p->transinfo[tindex].goal_period,
-                   p->transinfo[tindex].goal_offset,
-                   p->transinfo[tindex].goal_width,
-                   p->transinfo[tindex].goal_options);
-          }
-          aic7xxx_construct_ppr(p, scb);
-        }
-        else if (scb->flags & SCB_MSGOUT_WDTR)
-        {
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
-                   CTL_OF_SCB(scb));
-          }
-          aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
-        }
-        else if (scb->flags & SCB_MSGOUT_SDTR)
-        {
-          unsigned int max_sync, period;
-          unsigned char options = 0;
-          /*
-           * Now that the device is selected, use the bits in SBLKCTL and
-           * SSTAT2 to determine the max sync rate for this device.
-           */
-          if (p->features & AHC_ULTRA2)
-          {
-            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-            {
-              max_sync = AHC_SYNCRATE_ULTRA2;
-            }
-            else
-            {
-              max_sync = AHC_SYNCRATE_ULTRA;
-            }
-          }
-          else if (p->features & AHC_ULTRA)
-          {
-            max_sync = AHC_SYNCRATE_ULTRA;
-          }
-          else
-          {
-            max_sync = AHC_SYNCRATE_FAST;
-          }
-          period = p->transinfo[tindex].goal_period;
-          aic7xxx_find_syncrate(p, &period, max_sync, &options);
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
-                   CTL_OF_SCB(scb), period,
-                   p->transinfo[tindex].goal_offset);
-          }
-          aic7xxx_construct_sdtr(p, period,
-            p->transinfo[tindex].goal_offset);
-        }
-        else 
-        {
-          sti();
-          panic("aic7xxx: AWAITING_MSG for an SCB that does "
-                "not have a waiting message.\n");
-        }
-        /*
-         * We've set everything up to send our message, now to actually do
-         * so we need to enable reqinit interrupts and let the interrupt
-         * handler do the rest.  We don't want to unpause the sequencer yet
-         * though so we'll return early.  We also have to make sure that
-         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
-         * or else it's possible on VLB cards to loose the first REQINIT
-         * interrupt.  Edge triggered EISA cards could also loose this
-         * interrupt, although PCI and level triggered cards should not
-         * have this problem since they continually interrupt the kernel
-         * until we take care of the situation.
-         */
-        scb->flags |= SCB_MSGOUT_SENT;
-        p->msg_index = 0;
-        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
-        p->flags |= AHC_HANDLING_REQINITS;
-        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
-        return;
-      }
-      break;
-
-    case DATA_OVERRUN:
-      {
-        unsigned char scb_index = aic_inb(p, SCB_TAG);
-        unsigned char lastphase = aic_inb(p, LASTPHASE);
-        unsigned int i;
-
-        scb = (p->scb_data->scb_array[scb_index]);
-        /*
-         * XXX - What do we really want to do on an overrun?  The
-         *       mid-level SCSI code should handle this, but for now,
-         *       we'll just indicate that the command should retried.
-         *    If we retrieved sense info on this target, then the 
-         *    base SENSE info should have been saved prior to the
-         *    overrun error.  In that case, we return DID_OK and let
-         *    the mid level code pick up on the sense info.  Otherwise
-         *    we return DID_ERROR so the command will get retried.
-         */
-        if ( !(scb->flags & SCB_SENSE) )
-        {
-          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
-            p->host_no, CTL_OF_SCB(scb), 
-            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
-          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
-            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
-            scb->sg_length, scb->sg_count);
-          for (i = 0; i < scb->sg_count; i++)
-          {
-            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
-                 i, 
-                 le32_to_cpu(scb->sg_list[i].address),
-                 le32_to_cpu(scb->sg_list[i].length) );
-          }
-          aic7xxx_error(scb->cmd) = DID_ERROR;
-        }
-        else
-          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
-            p->host_no, CTL_OF_SCB(scb));
-      }
-      break;
-
-    case WIDE_RESIDUE:
-      {
-        unsigned char resid_sgcnt, index;
-        unsigned char scb_index = aic_inb(p, SCB_TAG);
-        unsigned int cur_addr, resid_dcnt;
-        unsigned int native_addr, native_length;
-        int i;
-
-        if(scb_index > p->scb_data->numscbs)
-        {
-          printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n",
-            p->host_no, -1, -1, -1);
-          /*
-           * XXX: Add error handling here
-           */
-          break;
-        }
-        scb = p->scb_data->scb_array[scb_index];
-        if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-        {
-          printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x "
-                 "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb),
-                 scb->flags, (unsigned long)scb->cmd);
-          break;
-        }
-
-        /*
-         * We have a valid scb to use on this WIDE_RESIDUE message, so
-         * we need to walk the sg list looking for this particular sg
-         * segment, then see if we happen to be at the very beginning of
-         * the segment.  If we are, then we have to back things up to
-         * the previous segment.  If not, then we simply need to remove
-         * one byte from this segments address and add one to the byte
-         * count.
-         */
-        cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
-          (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
-        resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
-        resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
-          (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
-          (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
-        index = scb->sg_count - (resid_sgcnt + 1);
-        native_addr = le32_to_cpu(scb->sg_list[index].address);
-        native_length = le32_to_cpu(scb->sg_list[index].length);
-        /*
-         * Make sure this is a valid sg_seg for the given pointer
-         */
-        if(cur_addr < native_addr ||
-           cur_addr > (native_addr + native_length + 1))
-        {
-          printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
-                 p->host_no, CTL_OF_SCB(scb), cur_addr);
-          if(index > 0)
-            printk(WARN_LEAD "  sg_address[-1]:0x%x sg_length[-1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index - 1].address),
-                   le32_to_cpu(scb->sg_list[index - 1].length));
-          printk(WARN_LEAD "  sg_address:0x%x sg_length:%d\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 native_addr, native_length);
-          if(resid_sgcnt > 1)
-            printk(WARN_LEAD "  sg_address[1]:0x%x sg_length[1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index + 1].address),
-                   le32_to_cpu(scb->sg_list[index + 1].length));
-          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 cur_addr, resid_dcnt);
-          break;
-        }
-
-        if( (resid_sgcnt == 0) &&
-            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
-        {
-          /*
-           * We are at the end of the transfer and this is about a byte
-           * we ignored already (because the sequencer knew this was
-           * the last segment and set the adapter to ignore any wide
-           * residue bytes that might come through, which is only done
-           * on the last scatter gather segment of transfers).
-           */
-          break;
-        }
-        else if(cur_addr == native_addr)
-        {
-          /*
-           * If our current address matches the sg_seg->address then we
-           * have to back up the sg array to the previous segment and set
-           * it up to have only one byte of transfer left to go.
-           */
-          if(index == 0)
-          {
-            printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
-                   "transferred.\n", p->host_no, CTL_OF_SCB(scb));
-            break;
-          }
-          resid_sgcnt++;
-          index--;
-          cur_addr = le32_to_cpu(scb->sg_list[index].address) + 
-            le32_to_cpu(scb->sg_list[index].length) - 1;
-          native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
-            | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
-          native_addr -= SG_SIZEOF;
-          aic_outb(p, resid_sgcnt, SG_COUNT);
-          aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
-          aic_outb(p, native_addr & 0xff, SG_NEXT);
-          aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
-          aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
-          aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
-          aic_outb(p, 1, SCB_RESID_DCNT); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 1); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 2); 
-          aic_outb(p, 1, HCNT); 
-          aic_outb(p, 0, HCNT + 1); 
-          aic_outb(p, 0, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
-        }
-        else
-        {
-          /*
-           * Back the data pointer up by one and add one to the remaining
-           * byte count.  Then store that in the HCNT and HADDR registers.
-           */
-          cur_addr--;
-          resid_dcnt++;
-          aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); 
-          aic_outb(p, resid_dcnt & 0xff, HCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
-        }
-        /*
-         * The sequencer actually wants to find the new address and byte
-         * count in the SHCNT and SHADDR register sets.  These registers
-         * are a shadow of the regular HCNT and HADDR registers.  On the
-         * Ultra2 controllers, these registers are read only and the way
-         * we have to set their values is to put the values we want into
-         * the HCNT and HADDR registers and then output PRELOADEN into
-         * the DFCNTRL register which causes the card to latch the current
-         * values in the HADDR and HCNT registers and drop it through to
-         * the shadow registers.  On older cards we copy them directly
-         * across by hand.
-         */
-        if(p->features & AHC_ULTRA2)
-        {
-          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-          i=0;
-          udelay(1);
-          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
-          {
-            udelay(1);
-          }
-          aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
-          i=0;
-          udelay(1);
-          while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
-          {
-            udelay(1);
-          }
-        }
-        else
-        {
-          aic_outb(p, resid_dcnt & 0xff, STCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, SHADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
-        }
-      }
-      break;
-
-        
-#if AIC7XXX_NOT_YET 
-    case TRACEPOINT:
-      {
-        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
-               channel, target, lun);
-      }
-      break;
-
-    case TRACEPOINT2:
-      {
-        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
-               channel, target, lun);
-      }
-      break;
-
-    /* XXX Fill these in later */
-    case MSG_BUFFER_BUSY:
-      printk("aic7xxx: Message buffer busy.\n");
-      break;
-    case MSGIN_PHASEMIS:
-      printk("aic7xxx: Message-in phasemis.\n");
-      break;
-#endif
-
-    default:                   /* unknown */
-      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-             p->host_no, channel, target, lun, intstat,
-             aic_inb(p, SCSISIGI));
-      break;
-  }
-
-  /*
-   * Clear the sequencer interrupt and unpause the sequencer.
-   */
-  unpause_sequencer(p, /* unpause always */ TRUE);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_parse_msg
- *
- * Description:
- *   Parses incoming messages into actions on behalf of
- *   aic7xxx_handle_reqinit
- *_F*************************************************************************/
-static int
-aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int reject, reply, done;
-  unsigned char target_scsirate, tindex;
-  unsigned short target_mask;
-  unsigned char target, channel, lun;
-
-  target = scb->cmd->target;
-  channel = scb->cmd->channel;
-  lun = scb->cmd->lun;
-  reply = reject = done = FALSE;
-  tindex = TARGET_INDEX(scb->cmd);
-  target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
-  target_mask = (0x01 << tindex);
-
-  /*
-   * Parse as much of the message as is availible,
-   * rejecting it if we don't support it.  When
-   * the entire message is availible and has been
-   * handled, return TRUE indicating that we have
-   * parsed an entire message.
-   */
-
-  if (p->msg_buf[0] != MSG_EXTENDED)
-  {
-    reject = TRUE;
-  }
-
-  /*
-   * Just accept the length byte outright and perform
-   * more checking once we know the message type.
-   */
-
-  if ( !reject && (p->msg_len > 2) )
-  {
-    switch(p->msg_buf[2])
-    {
-      case MSG_EXT_SDTR:
-      {
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset, options;
-        struct aic7xxx_syncrate *syncrate;
-        
-        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
-        {
-          reject = TRUE;
-          break;
-        }
-
-        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
-        {
-          break;
-        }
-
-        period = p->msg_buf[3];
-        saved_offset = offset = p->msg_buf[4];
-        options = 0;
-
-        /*
-         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
-         * using the SDTR messages.  We need the PPR messages to enable the
-         * higher speeds that include things like Dual Edge clocking.
-         */
-        if (p->features & AHC_ULTRA2)
-        {
-          if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-               !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA;
-          }
-        }
-        else if (p->features & AHC_ULTRA)
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_FAST;
-        }
-        /*
-         * We might have a device that is starting negotiation with us
-         * before we can start up negotiation with it....be prepared to
-         * have a device ask for a higher speed then we want to give it
-         * in that case
-         */
-        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-             (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
-        {
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
-              !(p->needsdtr_copy & target_mask) &&
-               (p->transinfo[tindex].user_offset) )
-          {
-            /*
-             * Not only is the device starting this up, but it also hasn't
-             * been scanned yet, so this would likely be our TUR or our
-             * INQUIRY command at scan time, so we need to use the
-             * settings from the SEEPROM if they existed.  Of course, even
-             * if we didn't find a SEEPROM, we stuffed default values into
-             * the user settings anyway, so use those in all cases.
-             */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            if(p->features & AHC_ULTRA2)
-            {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-            }
-            else if (p->transinfo[tindex].cur_width)
-            {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-            }
-            else
-            {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-            }
-            p->needsdtr_copy |= target_mask;
-          }
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Received pre-emptive SDTR message from "
-                   "target.\n", p->host_no, CTL_OF_SCB(scb));
-          }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
-        }
-  
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
-        aic7xxx_validate_offset(p, syncrate, &offset,
-                                target_scsirate & WIDEXFER);
-        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-
-        /*
-         * Did we drop to async?  Or are we sending a reply?  If we are,
-         * then we have to make sure that the reply value reflects the proper
-         * settings so we need to set the goal values according to what
-         * we need to send.
-         */
-        if ( (offset != saved_offset) ||
-             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
-        {
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
-                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-        }
-        
-        /*
-         * Did we start this, if not, or if we went to low and had to
-         * go async, then send an SDTR back to the target
-         */
-        p->needsdtr &= ~target_mask;
-        p->dtr_pending &= ~target_mask;
-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
-             (offset != saved_offset) )
-        {
-          reply = TRUE;
-          p->dtr_pending |= target_mask;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_SDTR;
-          aic_outb(p, HOST_MSG, MSG_OUT);
-          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
-        }
-        done = TRUE;
-        break;
-      }
-      case MSG_EXT_WDTR:
-      {
-        unsigned char bus_width;
-          
-        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
-        {
-          reject = TRUE;
-          break;
-        }
-
-        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
-        {
-          break;
-        }
-
-        bus_width = p->msg_buf[3];
-        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
-             (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
-        {
-          switch(bus_width)
-          {
-            default:
-            {
-              reject = TRUE;
-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
-                    (aic7xxx_verbose > 0xffff)) )
-              {
-                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
-                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-              }
-            } /* We fall through on purpose */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              p->needwdtr_copy &= ~target_mask;
-              break;
-            }
-            case MSG_EXT_WDTR_BUS_16_BIT:
-            {
-              break;
-            }
-          }
-          p->dtr_pending &= ~target_mask;
-          p->needwdtr &= ~target_mask;
-        }
-        else
-        {
-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
-          {
-            /* 
-             * Well, we now know the WDTR and SYNC caps of this device since
-             * it contacted us first, mark it as such and copy the user stuff
-             * over to the goal stuff.
-             */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            if(p->transinfo[tindex].user_offset)
-            {
-              if(p->features & AHC_ULTRA2)
-              {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-              }
-              else if( p->transinfo[tindex].user_width &&
-                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
-                       p->features & AHC_WIDE )
-              {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-              }
-              else
-              {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-              }
-            }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->needwdtr_copy |= target_mask;
-            p->needsdtr_copy |= target_mask;
-          }
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Received pre-emptive WDTR message from "
-                   "target.\n", p->host_no, CTL_OF_SCB(scb));
-          }
-          switch(bus_width)
-          {
-            default:
-            {
-              if ( (p->features & AHC_WIDE) &&
-                   (p->transinfo[tindex].goal_width ==
-                    MSG_EXT_WDTR_BUS_16_BIT) )
-              {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
-                break;
-              }
-            } /* Fall through if we aren't a wide card */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-              break;
-            }
-          }
-          reply = TRUE;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_WDTR;
-          p->needwdtr &= ~target_mask;
-          p->dtr_pending |= target_mask;
-          aic_outb(p, HOST_MSG, MSG_OUT);
-          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
-        }
-        aic7xxx_set_width(p, target, channel, lun, bus_width,
-                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-        
-        /*
-         * By virtue of the SCSI spec, a WDTR message negates any existing
-         * SDTR negotiations.  So, even if needsdtr isn't marked for this
-         * device, we still have to do a new SDTR message if the device
-         * supports SDTR at all.  Therefore, we check needsdtr_copy instead
-         * of needstr.
-         */
-        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
-                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-        p->needsdtr |= (p->needsdtr_copy & target_mask);
-        done = TRUE;
-        break;
-      }
-      case MSG_EXT_PPR:
-      {
-        unsigned char bus_width, trans_options, new_trans_options;
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset;
-        struct aic7xxx_syncrate *syncrate;
-        
-        if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
-        {
-          reject = TRUE;
-          break;
-        }
-
-        if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
-        {
-          break;
-        }
-
-        period = p->msg_buf[3];
-        offset = saved_offset = p->msg_buf[5];
-        bus_width = p->msg_buf[6];
-        trans_options = new_trans_options = p->msg_buf[7] & 0xf;
-
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-        {
-          printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
-                 trans_options);
-        }
-
-        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-        {
-          if(p->features & AHC_ULTRA3)
-          {
-            maxsync = AHC_SYNCRATE_ULTRA3;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
-        /*
-         * We might have a device that is starting negotiation with us
-         * before we can start up negotiation with it....be prepared to
-         * have a device ask for a higher speed then we want to give it
-         * in that case
-         */
-        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
-             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
-        {
-          reply = TRUE;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_PPR;
-	  p->dev_flags[tindex] |= DEVICE_SCSI_3;
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
-          {
-            /*
-             * Not only is the device starting this up, but it also hasn't
-             * been scanned yet, so this would likely be our TUR or our
-             * INQUIRY command at scan time, so we need to use the
-             * settings from the SEEPROM if they existed.  Of course, even
-             * if we didn't find a SEEPROM, we stuffed default values into
-             * the user settings anyway, so use those in all cases.
-             */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            if(p->transinfo[tindex].user_offset)
-            {
-              if(p->features & AHC_ULTRA2)
-              {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-              }
-              else if( p->transinfo[tindex].user_width &&
-                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
-                       p->features & AHC_WIDE )
-              {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-              }
-              else
-              {
-                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-              }
-            }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
-          }
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-          {
-            printk(INFO_LEAD "Received pre-emptive PPR message from "
-                   "target.\n", p->host_no, CTL_OF_SCB(scb));
-          }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
-          if ( p->transinfo[tindex].goal_options == 0 )
-            new_trans_options = 0;
-          switch(bus_width)
-          {
-            default:
-            {
-              if ( (p->features & AHC_WIDE) &&
-                   (p->transinfo[tindex].goal_width ==
-                    MSG_EXT_WDTR_BUS_16_BIT) )
-              {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
-                break;
-              }
-            } /* Fall through if we aren't a wide card */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-              break;
-            }
-          }
-          if ( (p->transinfo[tindex].goal_period > 9) ||
-               (p->transinfo[tindex].goal_options == 0) )
-          {
-            scb->flags &= ~SCB_MSGOUT_BITS;
-            reject = TRUE;
-            reply = FALSE;
-            p->needppr &= ~(1 << tindex);
-            p->needppr_copy &= ~(1 << tindex);
-            if ( p->transinfo[tindex].goal_offset )
-            {
-              p->needsdtr |= (1 << tindex);
-              p->needsdtr_copy |= (1 << tindex);
-            }
-            if ( p->transinfo[tindex].goal_width )
-            {
-              p->needwdtr |= (1 << tindex);
-              p->needwdtr_copy |= (1 << tindex);
-            }
-          }
-        }
-        else
-        {
-          switch(bus_width)
-          {
-            default:
-            {
-              reject = TRUE;
-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
-                    (aic7xxx_verbose > 0xffff)) )
-              {
-                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
-                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-              }
-            } /* We fall through on purpose */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              /*
-               * According to the spec, if we aren't wide, we also can't be
-               * Dual Edge so clear the options byte
-               */
-              new_trans_options = 0;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              break;
-            }
-            case MSG_EXT_WDTR_BUS_16_BIT:
-            {
-              break;
-            }
-          }
-        }
-
-        if ( !reject )
-        {
-          aic7xxx_set_width(p, target, channel, lun, bus_width,
-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
-                                           &new_trans_options);
-          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, new_trans_options,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-        }
-
-        p->dtr_pending &= ~target_mask;
-        p->needppr &= ~target_mask;
-        if(reply)
-        {
-          p->dtr_pending |= target_mask;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_PPR;
-          aic_outb(p, HOST_MSG, MSG_OUT);
-          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
-        }
-        done = TRUE;
-        break;
-      }
-      default:
-      {
-        reject = TRUE;
-        break;
-      }
-    } /* end of switch(p->msg_type) */
-  } /* end of if (!reject && (p->msg_len > 2)) */
-
-  if (!reply && reject)
-  {
-    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
-    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
-    done = TRUE;
-  }
-  return(done);
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_reqinit
- *
- * Description:
- *   Interrupt handler for REQINIT interrupts (used to transfer messages to
- *    and from devices).
- *_F*************************************************************************/
-static void
-aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  unsigned char lastbyte;
-  unsigned char phasemis;
-  int done = FALSE;
-
-  switch(p->msg_type)
-  {
-    case MSG_TYPE_INITIATOR_MSGOUT:
-      {
-        if (p->msg_len == 0)
-          panic("aic7xxx: REQINIT with no active message!\n");
-
-        lastbyte = (p->msg_index == (p->msg_len - 1));
-        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
-
-        if (lastbyte || phasemis)
-        {
-          /* Time to end the message */
-          p->msg_len = 0;
-          p->msg_type = MSG_TYPE_NONE;
-          /*
-           * NOTE-TO-MYSELF: If you clear the REQINIT after you
-           * disable REQINITs, then cases of REJECT_MSG stop working
-           * and hang the bus
-           */
-          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
-          aic_outb(p, CLRSCSIINT, CLRINT);
-          p->flags &= ~AHC_HANDLING_REQINITS;
-
-          if (phasemis == 0)
-          {
-            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
-            aic_outb(p, 0, RETURN_1);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-            if (aic7xxx_verbose > 0xffff)
-              printk(INFO_LEAD "Completed sending of REQINIT message.\n",
-                     p->host_no, CTL_OF_SCB(scb));
-#endif
-          }
-          else
-          {
-            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-            if (aic7xxx_verbose > 0xffff)
-              printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n",
-                     p->host_no, CTL_OF_SCB(scb));
-#endif
-          }
-          unpause_sequencer(p, TRUE);
-        }
-        else
-        {
-          /*
-           * Present the byte on the bus (clearing REQINIT) but don't
-           * unpause the sequencer.
-           */
-          aic_outb(p, CLRREQINIT, CLRSINT1);
-          aic_outb(p, CLRSCSIINT, CLRINT);
-          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
-        }
-        break;
-      }
-    case MSG_TYPE_INITIATOR_MSGIN:
-      {
-        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
-
-        if (phasemis == 0)
-        {
-          p->msg_len++;
-          /* Pull the byte in without acking it */
-          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
-          done = aic7xxx_parse_msg(p, scb);
-          /* Ack the byte */
-          aic_outb(p, CLRREQINIT, CLRSINT1);
-          aic_outb(p, CLRSCSIINT, CLRINT);
-          aic_inb(p, SCSIDATL);
-          p->msg_index++;
-        }
-        if (phasemis || done)
-        {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-          if (aic7xxx_verbose > 0xffff)
-          {
-            if (phasemis)
-              printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n",
-                     p->host_no, CTL_OF_SCB(scb));
-            else
-              printk(INFO_LEAD "Completed receipt of REQINIT message.\n",
-                     p->host_no, CTL_OF_SCB(scb));
-          }
-#endif
-          /* Time to end our message session */
-          p->msg_len = 0;
-          p->msg_type = MSG_TYPE_NONE;
-          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
-          aic_outb(p, CLRSCSIINT, CLRINT);
-          p->flags &= ~AHC_HANDLING_REQINITS;
-          unpause_sequencer(p, TRUE);
-        }
-        break;
-      }
-    default:
-      {
-        panic("aic7xxx: Unknown REQINIT message type.\n");
-        break;
-      }
-  } /* End of switch(p->msg_type) */
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_scsiint
- *
- * Description:
- *   Interrupt handler for SCSI interrupts (SCSIINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
-{
-  unsigned char scb_index;
-  unsigned char status;
-  struct aic7xxx_scb *scb;
-
-  scb_index = aic_inb(p, SCB_TAG);
-  status = aic_inb(p, SSTAT1);
-
-  if (scb_index < p->scb_data->numscbs)
-  {
-    scb = p->scb_data->scb_array[scb_index];
-    if ((scb->flags & SCB_ACTIVE) == 0)
-    {
-      scb = NULL;
-    }
-  }
-  else
-  {
-    scb = NULL;
-  }
-
-
-  if ((status & SCSIRSTI) != 0)
-  {
-    int channel;
-
-    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
-      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
-    else
-      channel = 0;
-
-    if (aic7xxx_verbose & VERBOSE_RESET)
-      printk(WARN_LEAD "Someone else reset the channel!!\n",
-           p->host_no, channel, -1, -1);
-    if (aic7xxx_panic_on_abort)
-      aic7xxx_panic_abort(p, NULL);
-    /*
-     * Go through and abort all commands for the channel, but do not
-     * reset the channel again.
-     */
-    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
-    aic7xxx_run_done_queue(p, TRUE);
-    scb = NULL;
-  }
-  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
-  {
-    /*
-     * First look at what phase we were last in.  If it's message-out,
-     * chances are pretty good that the bus free was in response to
-     * one of our abort requests.
-     */
-    unsigned char lastphase = aic_inb(p, LASTPHASE);
-    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
-    unsigned char target = (saved_tcl >> 4) & 0x0F;
-    int channel;
-    int printerror = TRUE;
-
-    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
-      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
-    else
-      channel = 0;
-
-    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
-             SCSISEQ);
-    if (lastphase == P_MESGOUT)
-    {
-      unsigned char message;
-
-      message = aic_inb(p, SINDEX);
-
-      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
-      {
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
-            CTL_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
-                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
-        aic7xxx_run_done_queue(p, TRUE);
-        scb = NULL;
-        printerror = 0;
-      }
-      else if (message == MSG_BUS_DEV_RESET)
-      {
-        aic7xxx_handle_device_reset(p, target, channel);
-        scb = NULL;
-        printerror = 0;
-      }
-    }
-    if ( (scb != NULL) &&
-         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
-    {
-      /*
-       * This might be a SCSI-3 device that is dropping the bus due to
-       * errors and signalling that we should reduce the transfer speed.
-       * All we have to do is complete this command (since it's a negotiation
-       * command already) and the checksum routine should flag an error and
-       * reduce the speed setting and renegotiate.  We call the reset routing
-       * just to clean out the hardware from this scb.
-       */
-      printerror = 0;
-      aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
-      aic7xxx_run_done_queue(p, TRUE);
-      scb = NULL;
-    }
-    if (printerror != 0)
-    {
-      if (scb != NULL)
-      {
-        unsigned char tag;
-
-        if ((scb->hscb->control & TAG_ENB) != 0)
-        {
-          tag = scb->hscb->tag;
-        }
-        else
-        {
-          tag = SCB_LIST_NULL;
-        }
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
-        aic7xxx_run_done_queue(p, TRUE);
-      }
-      else
-      {
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-        aic7xxx_run_done_queue(p, TRUE);
-      }
-      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
-             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
-             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
-      scb = NULL;
-    }
-    aic_outb(p, MSG_NOOP, MSG_OUT);
-    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
-      SIMODE1);
-    p->flags &= ~AHC_HANDLING_REQINITS;
-    aic_outb(p, CLRBUSFREE, CLRSINT1);
-    aic_outb(p, CLRSCSIINT, CLRINT);
-    restart_sequencer(p);
-    unpause_sequencer(p, TRUE);
-  }
-  else if ((status & SELTO) != 0)
-  {
-    unsigned char scbptr;
-    unsigned char nextscb;
-    Scsi_Cmnd *cmd;
-
-    scbptr = aic_inb(p, WAITING_SCBH);
-    if (scbptr > p->scb_data->maxhscbs)
-    {
-      /*
-       * I'm still trying to track down exactly how this happens, but until
-       * I find it, this code will make sure we aren't passing bogus values
-       * into the SCBPTR register, even if that register will just wrap
-       * things around, we still don't like having out of range variables.
-       *
-       * NOTE: Don't check the aic7xxx_verbose variable, I want this message
-       * to always be displayed.
-       */
-      printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n",
-             p->host_no, -1, -1, -1, scbptr);
-      if (p->scb_data->maxhscbs > 4)
-        scbptr &= (p->scb_data->maxhscbs - 1);
-      else
-        scbptr &= 0x03;
-    }
-    aic_outb(p, scbptr, SCBPTR);
-    scb_index = aic_inb(p, SCB_TAG);
-
-    scb = NULL;
-    if (scb_index < p->scb_data->numscbs)
-    {
-      scb = p->scb_data->scb_array[scb_index];
-      if ((scb->flags & SCB_ACTIVE) == 0)
-      {
-        scb = NULL;
-      }
-    }
-    if (scb == NULL)
-    {
-      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
-             p->host_no, -1, -1, -1, scb_index);
-      printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
-             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
-             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
-             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
-      if (aic7xxx_panic_on_abort)
-        aic7xxx_panic_abort(p, NULL);
-    }
-    else
-    {
-      cmd = scb->cmd;
-      cmd->result = (DID_TIME_OUT << 16);
-
-      /*
-       * Clear out this hardware SCB
-       */
-      aic_outb(p, 0, SCB_CONTROL);
-
-      /*
-       * Clear out a few values in the card that are in an undetermined
-       * state.
-       */
-      aic_outb(p, MSG_NOOP, MSG_OUT);
-
-      /*
-       * Shift the waiting for selection queue forward
-       */
-      nextscb = aic_inb(p, SCB_NEXT);
-      aic_outb(p, nextscb, WAITING_SCBH);
-
-      /*
-       * Put this SCB back on the free list.
-       */
-      aic7xxx_add_curscb_to_free_list(p);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
-#endif
-      if (scb->flags & SCB_QUEUED_ABORT)
-      {
-        /*
-         * We know that this particular SCB had to be the queued abort since
-         * the disconnected SCB would have gotten a reconnect instead.
-         * What we need to do then is to let the command timeout again so
-         * we get a reset since this abort just failed.
-         */
-        cmd->result = 0;
-        scb = NULL;
-      }
-      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
-      {
-        /*
-         * Turn off the needsdtr, needwdtr, and needppr bits since this device
-         * doesn't seem to exist.
-         */
-        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-      }
-    }
-    /*
-     * Keep the sequencer from trying to restart any selections
-     */
-    aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
-    /*
-     * Make sure the data bits on the bus are released
-     * Don't do this on 7770 chipsets, it makes them give us
-     * a BRKADDRINT and kills the card.
-     */
-    if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
-      aic_outb(p, 0, SCSIBUSL);
-
-    /*
-     * Delay for the selection timeout delay period then stop the selection
-     */
-    udelay(301);
-    aic_outb(p, CLRSELINGO, CLRSINT0);
-    /*
-     * Clear out all the interrupt status bits
-     */
-    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
-    p->flags &= ~AHC_HANDLING_REQINITS;
-    aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
-    aic_outb(p, CLRSCSIINT, CLRINT);
-    /*
-     * Restarting the sequencer will stop the selection and make sure devices
-     * are allowed to reselect in.
-     */
-    restart_sequencer(p);
-    unpause_sequencer(p, TRUE);
-  }
-  else if (scb == NULL)
-  {
-    printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
-           "during scsiint 0x%x scb(%d)\n"
-           "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
-           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
-           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
-           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
-    /*
-     * Turn off the interrupt and set status to zero, so that it
-     * falls through the rest of the SCSIINT code.
-     */
-    aic_outb(p, status, CLRSINT1);
-    aic_outb(p, CLRSCSIINT, CLRINT);
-    unpause_sequencer(p, /* unpause always */ TRUE);
-    scb = NULL;
-  }
-  else if (status & SCSIPERR)
-  {
-    /*
-     * Determine the bus phase and queue an appropriate message.
-     */
-    char  *phase;
-    Scsi_Cmnd *cmd;
-    unsigned char mesg_out = MSG_NOOP;
-    unsigned char lastphase = aic_inb(p, LASTPHASE);
-    unsigned char sstat2 = aic_inb(p, SSTAT2);
-    unsigned char tindex = TARGET_INDEX(scb->cmd);
-
-    cmd = scb->cmd;
-    switch (lastphase)
-    {
-      case P_DATAOUT:
-        phase = "Data-Out";
-        break;
-      case P_DATAIN:
-        phase = "Data-In";
-        mesg_out = MSG_INITIATOR_DET_ERR;
-        break;
-      case P_COMMAND:
-        phase = "Command";
-        break;
-      case P_MESGOUT:
-        phase = "Message-Out";
-        break;
-      case P_STATUS:
-        phase = "Status";
-        mesg_out = MSG_INITIATOR_DET_ERR;
-        break;
-      case P_MESGIN:
-        phase = "Message-In";
-        mesg_out = MSG_PARITY_ERROR;
-        break;
-      default:
-        phase = "unknown";
-        break;
-    }
-
-    /*
-     * A parity error has occurred during a data
-     * transfer phase. Flag it and continue.
-     */
-    if( (p->features & AHC_ULTRA3) && 
-        (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) &&
-        (lastphase == P_DATAIN) )
-    {
-      printk(WARN_LEAD "CRC error during %s phase.\n",
-             p->host_no, CTL_OF_SCB(scb), phase);
-      if(sstat2 & CRCVALERR)
-      {
-        printk(WARN_LEAD "  CRC error in intermediate CRC packet.\n",
-               p->host_no, CTL_OF_SCB(scb));
-      }
-      if(sstat2 & CRCENDERR)
-      {
-        printk(WARN_LEAD "  CRC error in ending CRC packet.\n",
-               p->host_no, CTL_OF_SCB(scb));
-      }
-      if(sstat2 & CRCREQERR)
-      {
-        printk(WARN_LEAD "  Target incorrectly requested a CRC packet.\n",
-               p->host_no, CTL_OF_SCB(scb));
-      }
-      if(sstat2 & DUAL_EDGE_ERROR)
-      {
-        printk(WARN_LEAD "  Dual Edge transmission error.\n",
-               p->host_no, CTL_OF_SCB(scb));
-      }
-    }
-    else if( (lastphase == P_MESGOUT) &&
-             (cmd == p->dev_dtr_cmnd[tindex]) &&
-             (scb->flags & SCB_MSGOUT_PPR) )
-    {
-      /*
-       * As per the draft specs, any device capable of supporting any of
-       * the option values other than 0 are not allowed to reject the
-       * PPR message.  Instead, they must negotiate out what they do
-       * support instead of rejecting our offering or else they cause
-       * a parity error during msg_out phase to signal that they don't
-       * like our settings.
-       */
-      p->needppr &= ~(1 << tindex);
-      p->needppr_copy &= ~(1 << tindex);
-      aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
-                        MSG_EXT_WDTR_BUS_8_BIT,
-                        (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
-      aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
-                           0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
-      p->transinfo[tindex].goal_options = 0;
-      p->dtr_pending &= ~(1 << tindex);
-      scb->flags &= ~SCB_MSGOUT_BITS;
-      if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-      {
-        printk(INFO_LEAD "parity error during PPR message, reverting "
-               "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
-      }
-      if ( p->transinfo[tindex].goal_width )
-      {
-        p->needwdtr |= (1 << tindex);
-        p->needwdtr_copy |= (1 << tindex);
-      }
-      if ( p->transinfo[tindex].goal_offset )
-      {
-        if( p->transinfo[tindex].goal_period <= 9 )
-        {
-          p->transinfo[tindex].goal_period = 10;
-        }
-        p->needsdtr |= (1 << tindex);
-        p->needsdtr_copy |= (1 << tindex);
-      }
-      scb = NULL;
-    }
-    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
-    {
-      struct aic7xxx_syncrate *syncrate;
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-      /*
-       * oops, we had a failure, lower the transfer rate and try again.  It's
-       * worth noting here that it might be wise to also check for typical
-       * wide setting on narrow cable type problems and try disabling wide
-       * instead of slowing down if those exist.  That's hard to do with simple
-       * checksums though.
-       */
-      printk(WARN_LEAD "Parity error during %s phase.\n",
-             p->host_no, CTL_OF_SCB(scb), phase);
-      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-      {
-        syncrate++;
-        if( (syncrate->rate[0] != NULL) &&
-            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-        {
-          p->transinfo[tindex].goal_period = syncrate->period;
-          if( p->transinfo[tindex].goal_period > 9 )
-          {
-            p->transinfo[tindex].goal_options = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-            if (p->transinfo[tindex].goal_width)
-            {
-              p->needwdtr |= (1<<tindex);
-              p->needwdtr_copy |= (1<<tindex);
-            }
-          }
-        }
-        else if (p->transinfo[tindex].goal_width)
-        {
-          p->transinfo[tindex].goal_width = 0;
-          p->needwdtr &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-          p->transinfo[tindex].goal_offset =
-            p->transinfo[tindex].user_offset;
-          p->transinfo[tindex].goal_period =
-            p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_options =
-            p->transinfo[tindex].user_options;
-          if( p->transinfo[tindex].goal_period <= 9 )
-          {
-            p->needppr |= (1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needppr_copy |= (1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-          }
-          else
-          {
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-          }
-        }
-        else
-        {
-          p->transinfo[tindex].goal_offset = 0;
-          p->transinfo[tindex].goal_period = 255;
-          p->transinfo[tindex].goal_options = 0;
-          p->transinfo[tindex].goal_width = 0;
-          p->needppr &= ~(1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needwdtr &= ~(1<<tindex);
-          p->needppr_copy &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-        }
-      }
-      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
-    }
-    else
-    {
-      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
-    }
-
-    /*
-     * We've set the hardware to assert ATN if we get a parity
-     * error on "in" phases, so all we need to do is stuff the
-     * message buffer with the appropriate message.  "In" phases
-     * have set mesg_out to something other than MSG_NOP.
-     */
-    if (mesg_out != MSG_NOOP)
-    {
-      aic_outb(p, mesg_out, MSG_OUT);
-      aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
-      scb = NULL;
-    }
-    aic_outb(p, CLRSCSIPERR, CLRSINT1);
-    aic_outb(p, CLRSCSIINT, CLRINT);
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-  }
-  else if ( (status & REQINIT) &&
-            (p->flags & AHC_HANDLING_REQINITS) )
-  {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if (aic7xxx_verbose > 0xffff)
-      printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no,
-             CTL_OF_SCB(scb), aic_inb(p, SSTAT1));
-#endif
-    aic7xxx_handle_reqinit(p, scb);
-    return;
-  }
-  else
-  {
-    /*
-     * We don't know what's going on. Turn off the
-     * interrupt source and try to continue.
-     */
-    if (aic7xxx_verbose & VERBOSE_SCSIINT)
-      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
-        p->host_no, -1, -1, -1, status);
-    aic_outb(p, status, CLRSINT1);
-    aic_outb(p, CLRSCSIINT, CLRINT);
-    unpause_sequencer(p, /* unpause always */ TRUE);
-    scb = NULL;
-  }
-  if (scb != NULL)
-  {
-    aic7xxx_done(p, scb);
-  }
-}
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-static void
-aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
-{
-  unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp;
-  int i, bogus, lost;
-  static unsigned char scb_status[AIC7XXX_MAXSCB];
-
-#define SCB_NO_LIST 0
-#define SCB_FREE_LIST 1
-#define SCB_WAITING_LIST 2
-#define SCB_DISCONNECTED_LIST 4
-#define SCB_CURRENTLY_ACTIVE 8
-
-  /*
-   * Note, these checks will fail on a regular basis once the machine moves
-   * beyond the bus scan phase.  The problem is race conditions concerning
-   * the scbs and where they are linked in.  When you have 30 or so commands
-   * outstanding on the bus, and run this twice with every interrupt, the
-   * chances get pretty good that you'll catch the sequencer with an SCB
-   * only partially linked in.  Therefore, once we pass the scan phase
-   * of the bus, we really should disable this function.
-   */
-  bogus = FALSE;
-  memset(&scb_status[0], 0, sizeof(scb_status));
-  pause_sequencer(p);
-  saved_scbptr = aic_inb(p, SCBPTR);
-  if (saved_scbptr >= p->scb_data->maxhscbs)
-  {
-    printk("Bogus SCBPTR %d\n", saved_scbptr);
-    bogus = TRUE;
-  }
-  scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE;
-  free_scbh = aic_inb(p, FREE_SCBH);
-  if ( (free_scbh != SCB_LIST_NULL) &&
-       (free_scbh >= p->scb_data->maxhscbs) )
-  {
-    printk("Bogus FREE_SCBH %d\n", free_scbh);
-    bogus = TRUE;
-  }
-  else
-  {
-    temp = free_scbh;
-    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
-    {
-      if(scb_status[temp] & 0x07)
-      {
-        printk("HSCB %d on multiple lists, status 0x%02x", temp,
-               scb_status[temp] | SCB_FREE_LIST);
-        bogus = TRUE;
-      }
-      scb_status[temp] |= SCB_FREE_LIST;
-      aic_outb(p, temp, SCBPTR);
-      temp = aic_inb(p, SCB_NEXT);
-    }
-  }
-
-  dis_scbh = aic_inb(p, DISCONNECTED_SCBH);
-  if ( (dis_scbh != SCB_LIST_NULL) &&
-       (dis_scbh >= p->scb_data->maxhscbs) )
-  {
-    printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh);
-    bogus = TRUE;
-  }
-  else
-  {
-    temp = dis_scbh;
-    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
-    {
-      if(scb_status[temp] & 0x07)
-      {
-        printk("HSCB %d on multiple lists, status 0x%02x", temp,
-               scb_status[temp] | SCB_DISCONNECTED_LIST);
-        bogus = TRUE;
-      }
-      scb_status[temp] |= SCB_DISCONNECTED_LIST;
-      aic_outb(p, temp, SCBPTR);
-      temp = aic_inb(p, SCB_NEXT);
-    }
-  }
-  
-  wait_scbh = aic_inb(p, WAITING_SCBH);
-  if ( (wait_scbh != SCB_LIST_NULL) &&
-       (wait_scbh >= p->scb_data->maxhscbs) )
-  {
-    printk("Bogus WAITING_SCBH %d\n", wait_scbh);
-    bogus = TRUE;
-  }
-  else
-  {
-    temp = wait_scbh;
-    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
-    {
-      if(scb_status[temp] & 0x07)
-      {
-        printk("HSCB %d on multiple lists, status 0x%02x", temp,
-               scb_status[temp] | SCB_WAITING_LIST);
-        bogus = TRUE;
-      }
-      scb_status[temp] |= SCB_WAITING_LIST;
-      aic_outb(p, temp, SCBPTR);
-      temp = aic_inb(p, SCB_NEXT);
-    }
-  }
-
-  lost=0;
-  for(i=0; i < p->scb_data->maxhscbs; i++)
-  {
-    aic_outb(p, i, SCBPTR);
-    temp = aic_inb(p, SCB_NEXT);
-    if ( ((temp != SCB_LIST_NULL) &&
-          (temp >= p->scb_data->maxhscbs)) )
-    {
-      printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp);
-      bogus = TRUE;
-    }
-    if ( temp == i )
-    {
-      printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
-      bogus = TRUE;
-    }
-    if (scb_status[i] == 0)
-      lost++;
-    if (lost > 1)
-    {
-      printk("Too many lost scbs.\n");
-      bogus=TRUE;
-    }
-  }
-  aic_outb(p, saved_scbptr, SCBPTR);
-  unpause_sequencer(p, FALSE);
-  if (bogus)
-  {
-    printk("Bogus parameters found in card SCB array structures.\n");
-    printk("%s\n", buffer);
-    aic7xxx_panic_abort(p, NULL);
-  }
-  return;
-}
-#endif
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_command_completion_intr
- *
- * Description:
- *   SCSI command completion interrupt handler.
- *-F*************************************************************************/
-static void
-aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
-{
-  struct aic7xxx_scb *scb = NULL;
-  Scsi_Cmnd *cmd;
-  unsigned char scb_index, tindex;
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
-    printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
-#endif
-    
-  /*
-   * Read the INTSTAT location after clearing the CMDINT bit.  This forces
-   * any posted PCI writes to flush to memory.  Gerard Roudier suggested
-   * this fix to the possible race of clearing the CMDINT bit but not
-   * having all command bytes flushed onto the qoutfifo.
-   */
-  aic_outb(p, CLRCMDINT, CLRINT);
-  aic_inb(p, INTSTAT);
-  /*
-   * The sequencer will continue running when it
-   * issues this interrupt. There may be >1 commands
-   * finished, so loop until we've processed them all.
-   */
-
-  while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
-  {
-    scb_index = p->qoutfifo[p->qoutfifonext];
-    p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
-    if ( scb_index >= p->scb_data->numscbs )
-    {
-      printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
-        -1, -1, -1, scb_index);
-      continue;
-    }
-    scb = p->scb_data->scb_array[scb_index];
-    if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-    {
-      printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
-        "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
-        (unsigned long) scb->cmd);
-      continue;
-    }
-    tindex = TARGET_INDEX(scb->cmd);
-    if (scb->flags & SCB_QUEUED_ABORT)
-    {
-      pause_sequencer(p);
-      if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
-           (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
-      {
-        unpause_sequencer(p, FALSE);
-        continue;
-      }
-      aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
-        scb->cmd->lun, scb->hscb->tag);
-      scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
-        SCB_QUEUED_ABORT);
-      unpause_sequencer(p, FALSE);
-    }
-    else if (scb->flags & SCB_ABORT)
-    {
-      /*
-       * We started to abort this, but it completed on us, let it
-       * through as successful
-       */
-      scb->flags &= ~(SCB_ABORT|SCB_RESET);
-    }
-    else if (scb->flags & SCB_SENSE)
-    {
-      char *buffer = &scb->cmd->sense_buffer[0];
-      if (scb->cmd == p->dev_dtr_cmnd[tindex])
-      {
-        struct aic7xxx_scb *old_scb;
-        /*
-         * We have valid sense data, send it back immediately.
-         */
-        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
-        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
-        old_scb->hscb->target_status = scb->hscb->target_status;
-        old_scb->cmd->result = scb->hscb->target_status;
-        old_scb->cmd->result |= (DID_ERROR << 16);
-        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
-        scbq_remove(&p->waiting_scbs, old_scb);
-        scbq_remove(&p->delayed_scbs[tindex], old_scb);
-        scb->cmd->next = NULL;
-	aic7xxx_done(p, scb);
-        aic7xxx_done(p, old_scb);
-	continue;
-      } 
-      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
-      {
-        /*
-         * SCSI errors, run domain validation and re-run negotiation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
-         */
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
-      }
-    }
-    switch (status_byte(scb->hscb->target_status))
-    {
-      case QUEUE_FULL:
-      case BUSY:
-        scb->hscb->target_status = 0;
-        scb->cmd->result = 0;
-        aic7xxx_error(scb->cmd) = DID_OK;
-        break;
-      default:
-        cmd = scb->cmd;
-        if (scb->hscb->residual_SG_segment_count != 0)
-        {
-          aic7xxx_calculate_residual(p, scb);
-        }
-        cmd->result |= (aic7xxx_error(cmd) << 16);
-        aic7xxx_done(p, scb);
-        break;
-    }      
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_isr
- *
- * Description:
- *   SCSI controller interrupt handler.
- *-F*************************************************************************/
-static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
-{
-  struct aic7xxx_host *p;
-  unsigned char intstat;
-
-  p = (struct aic7xxx_host *)dev_id;
-
-  /*
-   * Just a few sanity checks.  Make sure that we have an int pending.
-   * Also, if PCI, then we are going to check for a PCI bus error status
-   * should we get too many spurious interrupts.
-   */
-  if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND))
-  {
-#ifdef CONFIG_PCI
-    if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) &&
-        !(p->flags & AHC_HANDLING_REQINITS) )
-    {
-      if ( aic_inb(p, ERROR) & PCIERRSTAT )
-      {
-        aic7xxx_pci_intr(p);
-      }
-      p->spurious_int = 0;
-    }
-    else if ( !(p->flags & AHC_HANDLING_REQINITS) )
-    {
-      p->spurious_int++;
-    }
-#endif
-    return;
-  }
-
-  p->spurious_int = 0;
-
-  /*
-   * Keep track of interrupts for /proc/scsi
-   */
-  p->isr_count++;
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
-       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
-    aic7xxx_check_scbs(p, "Bogus settings at start of interrupt.");
-#endif
-
-  /*
-   * Handle all the interrupt sources - especially for SCSI
-   * interrupts, we won't get a second chance at them.
-   */
-  if (intstat & CMDCMPLT)
-  {
-    aic7xxx_handle_command_completion_intr(p);
-  }
-
-  if (intstat & BRKADRINT)
-  {
-    int i;
-    unsigned char errno = aic_inb(p, ERROR);
-
-    printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
-    for (i = 0; i < NUMBER(hard_error); i++)
-    {
-      if (errno & hard_error[i].errno)
-      {
-        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
-      }
-    }
-    printk(KERN_ERR "(scsi%d)   SEQADDR=0x%x\n", p->host_no,
-      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
-    if (aic7xxx_panic_on_abort)
-      aic7xxx_panic_abort(p, NULL);
-#ifdef CONFIG_PCI
-    if (errno & PCIERRSTAT)
-      aic7xxx_pci_intr(p);
-#endif
-    if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
-    {
-      sti();
-      panic("aic7xxx: unrecoverable BRKADRINT.\n");
-    }
-    if (errno & ILLHADDR)
-    {
-      printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first "
-             "pausing controller!\n", p->host_no);
-    }
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if (errno & DPARERR)
-    {
-      if (aic_inb(p, DMAPARAMS) & DIRECTION)
-        printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no);
-      else
-        printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no);
-    }
-#endif
-    aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT);
-    unpause_sequencer(p, FALSE);
-  }
-
-  if (intstat & SEQINT)
-  {
-    /*
-     * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
-     */
-    if(p->features & AHC_ULTRA2)
-    {
-      aic_inb(p, CCSCBCTL);
-    }
-    aic7xxx_handle_seqint(p, intstat);
-  }
-
-  if (intstat & SCSIINT)
-  {
-    aic7xxx_handle_scsiint(p, intstat);
-  }
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
-       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
-    aic7xxx_check_scbs(p, "Bogus settings at end of interrupt.");
-#endif
-
-}
-
-/*+F*************************************************************************
- * Function:
- *   do_aic7xxx_isr
- *
- * Description:
- *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
- *   above.  Please, children, do not try this at home, and if you ever see
- *   anything like it, please inform the Gross Hack Police immediately
- *-F*************************************************************************/
-static void
-do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
-{
-  unsigned long cpu_flags;
-  struct aic7xxx_host *p;
-  
-  p = (struct aic7xxx_host *)dev_id;
-  if(!p)
-    return;
-  spin_lock_irqsave(&io_request_lock, cpu_flags);
-  if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
-  {
-    spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-    return;
-  }
-  do
-  {
-    aic7xxx_isr(irq, dev_id, regs);
-  } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
-  aic7xxx_done_cmds_complete(p);
-  aic7xxx_run_waiting_queues(p);
-  clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
-  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_device_queue_depth
- *
- * Description:
- *   Determines the queue depth for a given device.  There are two ways
- *   a queue depth can be obtained for a tagged queueing device.  One
- *   way is the default queue depth which is determined by whether
- *   AIC7XXX_CMDS_PER_DEVICE is defined.  If it is defined, then it is used
- *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
- *   default queue depth (dependent on the number of hardware SCBs).
- *   The other way we determine queue depth is through the use of the
- *   aic7xxx_tag_info array which is enabled by defining
- *   AIC7XXX_TAGGED_QUEUEING_BY_DEVICE.  This array can be initialized
- *   with queue depths for individual devices.  It also allows tagged
- *   queueing to be [en|dis]abled for a specific adapter.
- *-F*************************************************************************/
-static int
-aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
-{
-  int default_depth = 3;
-  unsigned char tindex;
-  unsigned short target_mask;
-
-  tindex = device->id | (device->channel << 3);
-  target_mask = (1 << tindex);
-
-  if (p->dev_max_queue_depth[tindex] > 1)
-  {
-    /*
-     * We've already scanned this device, leave it alone
-     */
-    return(p->dev_max_queue_depth[tindex]);
-  }
-
-  device->queue_depth = default_depth;
-  p->dev_temp_queue_depth[tindex] = 1;
-  p->dev_max_queue_depth[tindex] = 1;
-  p->tagenable &= ~target_mask;
-
-  if (device->tagged_supported)
-  {
-    int tag_enabled = TRUE;
-
-    default_depth = AIC7XXX_CMDS_PER_DEVICE;
- 
-    if (!(p->discenable & target_mask))
-    {
-      if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-        printk(INFO_LEAD "Disconnection disabled, unable to "
-             "enable tagged queueing.\n",
-             p->host_no, device->channel, device->id, device->lun);
-    }
-    else
-    {
-      if (p->instance >= NUMBER(aic7xxx_tag_info))
-      {
-        static int print_warning = TRUE;
-        if(print_warning)
-        {
-          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
-                           " installed controllers.\n");
-          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
-                           " the aic7xxx.c source file.\n");
-          print_warning = FALSE;
-        }
-        device->queue_depth = default_depth;
-      }
-      else
-      {
-
-        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
-        {
-          tag_enabled = FALSE;
-          device->queue_depth = 3;  /* Tagged queueing is disabled. */
-        }
-        else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
-        {
-          device->queue_depth = default_depth;
-        }
-        else
-        {
-          device->queue_depth =
-            aic7xxx_tag_info[p->instance].tag_commands[tindex];
-        }
-      }
-      if ((device->tagged_queue == 0) && tag_enabled)
-      {
-        if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-        {
-              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
-                p->host_no, device->channel, device->id,
-                device->lun, device->queue_depth);
-        }
-        p->dev_max_queue_depth[tindex] = device->queue_depth;
-        p->dev_temp_queue_depth[tindex] = device->queue_depth;
-        p->tagenable |= target_mask;
-        p->orderedtag |= target_mask;
-        device->tagged_queue = 1;
-        device->current_tag = SCB_LIST_NULL;
-      }
-    }
-  }
-  return(p->dev_max_queue_depth[tindex]);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_select_queue_depth
- *
- * Description:
- *   Sets the queue depth for each SCSI device hanging off the input
- *   host adapter.  We use a queue depth of 2 for devices that do not
- *   support tagged queueing.  If AIC7XXX_CMDS_PER_LUN is defined, we
- *   use that for tagged queueing devices; otherwise we use our own
- *   algorithm for determining the queue depth based on the maximum
- *   SCBs for the controller.
- *-F*************************************************************************/
-static void
-aic7xxx_select_queue_depth(struct Scsi_Host *host,
-    Scsi_Device *scsi_devs)
-{
-  Scsi_Device *device;
-  struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
-  int scbnum;
-
-  scbnum = 0;
-  for (device = scsi_devs; device != NULL; device = device->next)
-  {
-    if (device->host == host)
-    {
-      scbnum += aic7xxx_device_queue_depth(p, device);
-    }
-  }
-  while (scbnum > p->scb_data->numscbs)
-  {
-    /*
-     * Pre-allocate the needed SCBs to get around the possibility of having
-     * to allocate some when memory is more or less exhausted and we need
-     * the SCB in order to perform a swap operation (possible deadlock)
-     */
-    if ( aic7xxx_allocate_scb(p) == 0 )
-      return;
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_probe
- *
- * Description:
- *   Probing for EISA boards: it looks like the first two bytes
- *   are a manufacturer code - three characters, five bits each:
- *
- *               BYTE 0   BYTE 1   BYTE 2   BYTE 3
- *              ?1111122 22233333 PPPPPPPP RRRRRRRR
- *
- *   The characters are baselined off ASCII '@', so add that value
- *   to each to get the real ASCII code for it. The next two bytes
- *   appear to be a product and revision number, probably vendor-
- *   specific. This is what is being searched for at each port,
- *   and what should probably correspond to the ID= field in the
- *   ECU's .cfg file for the card - if your card is not detected,
- *   make sure your signature is listed in the array.
- *
- *   The fourth byte's lowest bit seems to be an enabled/disabled
- *   flag (rest of the bits are reserved?).
- *
- * NOTE:  This function is only needed on Intel and Alpha platforms,
- *   the other platforms we support don't have EISA/VLB busses.  So,
- *   we #ifdef this entire function to avoid compiler warnings about
- *   an unused function.
- *-F*************************************************************************/
-#if defined(__i386__) || defined(__alpha__)
-static int
-aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
-{
-  int i;
-  unsigned char buf[4];
-
-  static struct {
-    int n;
-    unsigned char signature[sizeof(buf)];
-    ahc_chip type;
-    int bios_disabled;
-  } AIC7xxx[] = {
-    { 4, { 0x04, 0x90, 0x77, 0x70 },
-      AHC_AIC7770|AHC_EISA, FALSE },  /* mb 7770  */
-    { 4, { 0x04, 0x90, 0x77, 0x71 },
-      AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */
-    { 4, { 0x04, 0x90, 0x77, 0x56 },
-      AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */
-    { 4, { 0x04, 0x90, 0x77, 0x57 },
-      AHC_AIC7770|AHC_VL, TRUE }   /* 284x BIOS disabled */
-  };
-
-  /*
-   * The VL-bus cards need to be primed by
-   * writing before a signature check.
-   */
-  for (i = 0; i < sizeof(buf); i++)
-  {
-    outb(0x80 + i, base);
-    buf[i] = inb(base + i);
-  }
-
-  for (i = 0; i < NUMBER(AIC7xxx); i++)
-  {
-    /*
-     * Signature match on enabled card?
-     */
-    if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n))
-    {
-      if (inb(base + 4) & 1)
-      {
-        if (AIC7xxx[i].bios_disabled)
-        {
-          *flags |= AHC_USEDEFAULTS;
-        }
-        else
-        {
-          *flags |= AHC_BIOS_ENABLED;
-        }
-        return (i);
-      }
-
-      printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
-             "disabled at slot %d, ignored.\n", slot);
-    }
-  }
-
-  return (-1);
-}
-#endif /* (__i386__) || (__alpha__) */
-
-
-/*+F*************************************************************************
- * Function:
- *   read_2840_seeprom
- *
- * Description:
- *   Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
- *   not successful.
- *
- *   See read_seeprom (for the 2940) for the instruction set of the 93C46
- *   chip.
- *
- *   The 2840 interface to the 93C46 serial EEPROM is through the
- *   STATUS_2840 and SEECTL_2840 registers.  The CS_2840, CK_2840, and
- *   DO_2840 bits of the SEECTL_2840 register are connected to the chip
- *   select, clock, and data out lines respectively of the serial EEPROM.
- *   The DI_2840 bit of the STATUS_2840 is connected to the data in line
- *   of the serial EEPROM.  The EEPROM_TF bit of STATUS_2840 register is
- *   useful in that it gives us an 800 nsec timer.  After a read from the
- *   SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
- *   later.
- *-F*************************************************************************/
-static int
-read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
-{
-  int i = 0, k = 0;
-  unsigned char temp;
-  unsigned short checksum = 0;
-  unsigned short *seeprom = (unsigned short *) sc;
-  struct seeprom_cmd {
-    unsigned char len;
-    unsigned char bits[3];
-  };
-  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
-
-#define CLOCK_PULSE(p) \
-  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
-  {                                                \
-    ;  /* Do nothing */                                \
-  }                                                \
-  (void) aic_inb(p, SEECTL_2840);
-
-  /*
-   * Read the first 32 registers of the seeprom.  For the 2840,
-   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
-   * but only the first 32 are used by Adaptec BIOS.  The loop
-   * will range from 0 to 31.
-   */
-  for (k = 0; k < (sizeof(*sc) / 2); k++)
-  {
-    /*
-     * Send chip select for one clock cycle.
-     */
-    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
-    CLOCK_PULSE(p);
-
-    /*
-     * Now we're ready to send the read command followed by the
-     * address of the 16-bit register we want to read.
-     */
-    for (i = 0; i < seeprom_read.len; i++)
-    {
-      temp = CS_2840 | seeprom_read.bits[i];
-      aic_outb(p, temp, SEECTL_2840);
-      CLOCK_PULSE(p);
-      temp = temp ^ CK_2840;
-      aic_outb(p, temp, SEECTL_2840);
-      CLOCK_PULSE(p);
-    }
-    /*
-     * Send the 6 bit address (MSB first, LSB last).
-     */
-    for (i = 5; i >= 0; i--)
-    {
-      temp = k;
-      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
-      temp = CS_2840 | temp;
-      aic_outb(p, temp, SEECTL_2840);
-      CLOCK_PULSE(p);
-      temp = temp ^ CK_2840;
-      aic_outb(p, temp, SEECTL_2840);
-      CLOCK_PULSE(p);
-    }
-
-    /*
-     * Now read the 16 bit register.  An initial 0 precedes the
-     * register contents which begins with bit 15 (MSB) and ends
-     * with bit 0 (LSB).  The initial 0 will be shifted off the
-     * top of our word as we let the loop run from 0 to 16.
-     */
-    for (i = 0; i <= 16; i++)
-    {
-      temp = CS_2840;
-      aic_outb(p, temp, SEECTL_2840);
-      CLOCK_PULSE(p);
-      temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
-      aic_outb(p, temp, SEECTL_2840);
-      CLOCK_PULSE(p);
-    }
-    /*
-     * The serial EEPROM has a checksum in the last word.  Keep a
-     * running checksum for all words read except for the last
-     * word.  We'll verify the checksum after all words have been
-     * read.
-     */
-    if (k < (sizeof(*sc) / 2) - 1)
-    {
-      checksum = checksum + seeprom[k];
-    }
-
-    /*
-     * Reset the chip select for the next command cycle.
-     */
-    aic_outb(p, 0, SEECTL_2840);
-    CLOCK_PULSE(p);
-    aic_outb(p, CK_2840, SEECTL_2840);
-    CLOCK_PULSE(p);
-    aic_outb(p, 0, SEECTL_2840);
-    CLOCK_PULSE(p);
-  }
-
-#if 0
-  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
-  printk("Serial EEPROM:");
-  for (k = 0; k < (sizeof(*sc) / 2); k++)
-  {
-    if (((k % 8) == 0) && (k != 0))
-    {
-      printk("\n              ");
-    }
-    printk(" 0x%x", seeprom[k]);
-  }
-  printk("\n");
-#endif
-
-  if (checksum != sc->checksum)
-  {
-    printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
-    return (0);
-  }
-
-  return (1);
-#undef CLOCK_PULSE
-}
-
-#define CLOCK_PULSE(p)                                               \
-  do {                                                               \
-    int limit = 0;                                                   \
-    do {                                                             \
-      mb();                                                          \
-      pause_sequencer(p);  /* This is just to generate some PCI */   \
-                           /* traffic so the PCI read is flushed */  \
-                           /* it shouldn't be needed, but some */    \
-                           /* chipsets do indeed appear to need */   \
-                           /* something to force PCI reads to get */ \
-                           /* flushed */                             \
-      udelay(1);           /* Do nothing */                          \
-    } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \
-  } while(0)
-
-/*+F*************************************************************************
- * Function:
- *   acquire_seeprom
- *
- * Description:
- *   Acquires access to the memory port on PCI controllers.
- *-F*************************************************************************/
-static int
-acquire_seeprom(struct aic7xxx_host *p)
-{
-
-  /*
-   * Request access of the memory port.  When access is
-   * granted, SEERDY will go high.  We use a 1 second
-   * timeout which should be near 1 second more than
-   * is needed.  Reason: after the 7870 chip reset, there
-   * should be no contention.
-   */
-  aic_outb(p, SEEMS, SEECTL);
-  CLOCK_PULSE(p);
-  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
-  {
-    aic_outb(p, 0, SEECTL);
-    return (0);
-  }
-  return (1);
-}
-
-/*+F*************************************************************************
- * Function:
- *   release_seeprom
- *
- * Description:
- *   Releases access to the memory port on PCI controllers.
- *-F*************************************************************************/
-static void
-release_seeprom(struct aic7xxx_host *p)
-{
-  /*
-   * Make sure the SEEPROM is ready before we release it.
-   */
-  CLOCK_PULSE(p);
-  aic_outb(p, 0, SEECTL);
-}
-
-/*+F*************************************************************************
- * Function:
- *   read_seeprom
- *
- * Description:
- *   Reads the serial EEPROM and returns 1 if successful and 0 if
- *   not successful.
- *
- *   The instruction set of the 93C46/56/66 chips is as follows:
- *
- *               Start  OP
- *     Function   Bit  Code  Address    Data     Description
- *     -------------------------------------------------------------------
- *     READ        1    10   A5 - A0             Reads data stored in memory,
- *                                               starting at specified address
- *     EWEN        1    00   11XXXX              Write enable must precede
- *                                               all programming modes
- *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
- *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
- *     ERAL        1    00   10XXXX              Erase all registers
- *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
- *     EWDS        1    00   00XXXX              Disables all programming
- *                                               instructions
- *     *Note: A value of X for address is a don't care condition.
- *     *Note: The 93C56 and 93C66 have 8 address bits.
- * 
- *
- *   The 93C46 has a four wire interface: clock, chip select, data in, and
- *   data out.  In order to perform one of the above functions, you need
- *   to enable the chip select for a clock period (typically a minimum of
- *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
- *   respectively.  While the chip select remains high, you can clock in
- *   the instructions (above) starting with the start bit, followed by the
- *   OP code, Address, and Data (if needed).  For the READ instruction, the
- *   requested 16-bit register contents is read from the data out line but
- *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
- *   first).  The clock cycling from low to high initiates the next data
- *   bit to be sent from the chip.
- *
- *   The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
- *   register.  After successful arbitration for the memory port, the
- *   SEECS bit of the SEECTL register is connected to the chip select.
- *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
- *   and data in lines respectively.  The SEERDY bit of SEECTL is useful
- *   in that it gives us an 800 nsec timer.  After a write to the SEECTL
- *   register, the SEERDY goes high 800 nsec later.  The one exception
- *   to this is when we first request access to the memory port.  The
- *   SEERDY goes high to signify that access has been granted and, for
- *   this case, has no implied timing.
- *-F*************************************************************************/
-static int
-read_seeprom(struct aic7xxx_host *p, int offset, 
-    unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
-{
-  int i = 0, k;
-  unsigned char temp;
-  unsigned short checksum = 0;
-  struct seeprom_cmd {
-    unsigned char len;
-    unsigned char bits[3];
-  };
-  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
-
-  /*
-   * Request access of the memory port.
-   */
-  if (acquire_seeprom(p) == 0)
-  {
-    return (0);
-  }
-
-  /*
-   * Read 'len' registers of the seeprom.  For the 7870, the 93C46
-   * SEEPROM is a 1024-bit device with 64 16-bit registers but only
-   * the first 32 are used by Adaptec BIOS.  Some adapters use the
-   * 93C56 SEEPROM which is a 2048-bit device.  The loop will range
-   * from 0 to 'len' - 1.
-   */
-  for (k = 0; k < len; k++)
-  {
-    /*
-     * Send chip select for one clock cycle.
-     */
-    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
-    CLOCK_PULSE(p);
-
-    /*
-     * Now we're ready to send the read command followed by the
-     * address of the 16-bit register we want to read.
-     */
-    for (i = 0; i < seeprom_read.len; i++)
-    {
-      temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      aic_outb(p, temp, SEECTL);
-      CLOCK_PULSE(p);
-      temp = temp ^ SEECK;
-      aic_outb(p, temp, SEECTL);
-      CLOCK_PULSE(p);
-    }
-    /*
-     * Send the 6 or 8 bit address (MSB first, LSB last).
-     */
-    for (i = ((int) chip - 1); i >= 0; i--)
-    {
-      temp = k + offset;
-      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
-      temp = SEEMS | SEECS | (temp << 1);
-      aic_outb(p, temp, SEECTL);
-      CLOCK_PULSE(p);
-      temp = temp ^ SEECK;
-      aic_outb(p, temp, SEECTL);
-      CLOCK_PULSE(p);
-    }
-
-    /*
-     * Now read the 16 bit register.  An initial 0 precedes the
-     * register contents which begins with bit 15 (MSB) and ends
-     * with bit 0 (LSB).  The initial 0 will be shifted off the
-     * top of our word as we let the loop run from 0 to 16.
-     */
-    for (i = 0; i <= 16; i++)
-    {
-      temp = SEEMS | SEECS;
-      aic_outb(p, temp, SEECTL);
-      CLOCK_PULSE(p);
-      temp = temp ^ SEECK;
-      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
-      aic_outb(p, temp, SEECTL);
-      CLOCK_PULSE(p);
-    }
-
-    /*
-     * The serial EEPROM should have a checksum in the last word.
-     * Keep a running checksum for all words read except for the
-     * last word.  We'll verify the checksum after all words have
-     * been read.
-     */
-    if (k < (len - 1))
-    {
-      checksum = checksum + scarray[k];
-    }
-
-    /*
-     * Reset the chip select for the next command cycle.
-     */
-    aic_outb(p, SEEMS, SEECTL);
-    CLOCK_PULSE(p);
-    aic_outb(p, SEEMS | SEECK, SEECTL);
-    CLOCK_PULSE(p);
-    aic_outb(p, SEEMS, SEECTL);
-    CLOCK_PULSE(p);
-  }
-
-  /*
-   * Release access to the memory port and the serial EEPROM.
-   */
-  release_seeprom(p);
-
-#if 0
-  printk("Computed checksum 0x%x, checksum read 0x%x\n",
-         checksum, scarray[len - 1]);
-  printk("Serial EEPROM:");
-  for (k = 0; k < len; k++)
-  {
-    if (((k % 8) == 0) && (k != 0))
-    {
-      printk("\n              ");
-    }
-    printk(" 0x%x", scarray[k]);
-  }
-  printk("\n");
-#endif
-  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
-  {
-    return (0);
-  }
-
-  return (1);
-}
-
-/*+F*************************************************************************
- * Function:
- *   read_brdctl
- *
- * Description:
- *   Reads the BRDCTL register.
- *-F*************************************************************************/
-static unsigned char
-read_brdctl(struct aic7xxx_host *p)
-{
-  unsigned char brdctl, value;
-
-  /*
-   * Make sure the SEEPROM is ready before we access it
-   */
-  CLOCK_PULSE(p);
-  if (p->features & AHC_ULTRA2)
-  {
-    brdctl = BRDRW_ULTRA2;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    value = aic_inb(p, BRDCTL);
-    CLOCK_PULSE(p);
-    return(value);
-  }
-  brdctl = BRDRW;
-  if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
-        (p->flags & AHC_CHNLB) )
-  {
-    brdctl |= BRDCS;
-  }
-  aic_outb(p, brdctl, BRDCTL);
-  CLOCK_PULSE(p);
-  value = aic_inb(p, BRDCTL);
-  CLOCK_PULSE(p);
-  aic_outb(p, 0, BRDCTL);
-  CLOCK_PULSE(p);
-  return (value);
-}
-
-/*+F*************************************************************************
- * Function:
- *   write_brdctl
- *
- * Description:
- *   Writes a value to the BRDCTL register.
- *-F*************************************************************************/
-static void
-write_brdctl(struct aic7xxx_host *p, unsigned char value)
-{
-  unsigned char brdctl;
-
-  /*
-   * Make sure the SEEPROM is ready before we access it
-   */
-  CLOCK_PULSE(p);
-  if (p->features & AHC_ULTRA2)
-  {
-    brdctl = value;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    brdctl |= BRDSTB_ULTRA2;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    brdctl &= ~BRDSTB_ULTRA2;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    read_brdctl(p);
-    CLOCK_PULSE(p);
-  }
-  else
-  {
-    brdctl = BRDSTB;
-    if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
-          (p->flags & AHC_CHNLB) )
-    {
-      brdctl |= BRDCS;
-    }
-    brdctl = BRDSTB | BRDCS;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    brdctl |= value;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    brdctl &= ~BRDSTB;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-    brdctl &= ~BRDCS;
-    aic_outb(p, brdctl, BRDCTL);
-    CLOCK_PULSE(p);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic785x_cable_detect
- *
- * Description:
- *   Detect the cables that are present on aic785x class controller chips
- *-F*************************************************************************/
-static void
-aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
-    int *ext_present, int *eeprom)
-{
-  unsigned char brdctl;
-
-  aic_outb(p, BRDRW | BRDCS, BRDCTL);
-  CLOCK_PULSE(p);
-  aic_outb(p, 0, BRDCTL);
-  CLOCK_PULSE(p);
-  brdctl = aic_inb(p, BRDCTL);
-  CLOCK_PULSE(p);
-  *int_50 = !(brdctl & BRDDAT5);
-  *ext_present = !(brdctl & BRDDAT6);
-  *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
-}
-
-#undef CLOCK_PULSE
-
-/*+F*************************************************************************
- * Function:
- *   aic2940_uwpro_cable_detect
- *
- * Description:
- *   Detect the cables that are present on the 2940-UWPro cards
- *
- * NOTE: This function assumes the SEEPROM will have already been acquired
- *       prior to invocation of this function.
- *-F*************************************************************************/
-static void
-aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68,
-    int *ext_68, int *eeprom)
-{
-  unsigned char brdctl;
-
-  /*
-   * First read the status of our cables.  Set the rom bank to
-   * 0 since the bank setting serves as a multiplexor for the
-   * cable detection logic.  BRDDAT5 controls the bank switch.
-   */
-  write_brdctl(p, 0);
-
-  /*
-   * Now we read the state of the internal 68 connector.  BRDDAT6
-   * is don't care, BRDDAT7 is internal 68.  The cable is
-   * present if the bit is 0
-   */
-  brdctl = read_brdctl(p);
-  *int_68 = !(brdctl & BRDDAT7);
-
-  /*
-   * Set the bank bit in brdctl and then read the external cable state
-   * and the EEPROM status
-   */
-  write_brdctl(p, BRDDAT5);
-  brdctl = read_brdctl(p);
-
-  *ext_68 = !(brdctl & BRDDAT6);
-  *eeprom = !(brdctl & BRDDAT7);
-
-  /*
-   * We're done, the calling function will release the SEEPROM for us
-   */
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic787x_cable_detect
- *
- * Description:
- *   Detect the cables that are present on aic787x class controller chips
- *
- * NOTE: This function assumes the SEEPROM will have already been acquired
- *       prior to invocation of this function.
- *-F*************************************************************************/
-static void
-aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
-    int *ext_present, int *eeprom)
-{
-  unsigned char brdctl;
-
-  /*
-   * First read the status of our cables.  Set the rom bank to
-   * 0 since the bank setting serves as a multiplexor for the
-   * cable detection logic.  BRDDAT5 controls the bank switch.
-   */
-  write_brdctl(p, 0);
-
-  /*
-   * Now we read the state of the two internal connectors.  BRDDAT6
-   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
-   * present if the bit is 0
-   */
-  brdctl = read_brdctl(p);
-  *int_50 = !(brdctl & BRDDAT6);
-  *int_68 = !(brdctl & BRDDAT7);
-
-  /*
-   * Set the bank bit in brdctl and then read the external cable state
-   * and the EEPROM status
-   */
-  write_brdctl(p, BRDDAT5);
-  brdctl = read_brdctl(p);
-
-  *ext_present = !(brdctl & BRDDAT6);
-  *eeprom = !(brdctl & BRDDAT7);
-
-  /*
-   * We're done, the calling function will release the SEEPROM for us
-   */
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic787x_ultra2_term_detect
- *
- * Description:
- *   Detect the termination settings present on ultra2 class controllers
- *
- * NOTE: This function assumes the SEEPROM will have already been acquired
- *       prior to invocation of this function.
- *-F*************************************************************************/
-static void
-aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low,
-                           int *enableSE_high, int *enableLVD_low,
-                           int *enableLVD_high, int *eprom_present)
-{
-  unsigned char brdctl;
-
-  brdctl = read_brdctl(p);
-
-  *eprom_present  = (brdctl & BRDDAT7);
-  *enableSE_high  = (brdctl & BRDDAT6);
-  *enableSE_low   = (brdctl & BRDDAT5);
-  *enableLVD_high = (brdctl & BRDDAT4);
-  *enableLVD_low  = (brdctl & BRDDAT3);
-}
-
-/*+F*************************************************************************
- * Function:
- *   configure_termination
- *
- * Description:
- *   Configures the termination settings on PCI adapters that have
- *   SEEPROMs available.
- *-F*************************************************************************/
-static void
-configure_termination(struct aic7xxx_host *p)
-{
-  int internal50_present = 0;
-  int internal68_present = 0;
-  int external_present = 0;
-  int eprom_present = 0;
-  int enableSE_low = 0;
-  int enableSE_high = 0;
-  int enableLVD_low = 0;
-  int enableLVD_high = 0;
-  unsigned char brddat = 0;
-  unsigned char max_target = 0;
-  unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1);
-
-  if (acquire_seeprom(p))
-  {
-    if (p->features & (AHC_WIDE|AHC_TWIN))
-      max_target = 16;
-    else
-      max_target = 8;
-    aic_outb(p, SEEMS | SEECS, SEECTL);
-    sxfrctl1 &= ~STPWEN;
-    /*
-     * The termination/cable detection logic is split into three distinct
-     * groups.  Ultra2 and later controllers, 2940UW-Pro controllers, and
-     * older 7850, 7860, 7870, 7880, and 7895 controllers.  Each has its
-     * own unique way of detecting their cables and writing the results
-     * back to the card.
-     */
-    if (p->features & AHC_ULTRA2)
-    {
-      /*
-       * As long as user hasn't overridden term settings, always check the
-       * cable detection logic
-       */
-      if (aic7xxx_override_term == -1)
-      {
-        aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
-                                   &enableLVD_low, &enableLVD_high,
-                                   &eprom_present);
-      }
-      
-      /*
-       * If the user is overriding settings, then they have been preserved
-       * to here as fake adapter_control entries.  Parse them and allow
-       * them to override the detected settings (if we even did detection).
-       */
-      if (!(p->adapter_control & CFSEAUTOTERM))
-      {
-        enableSE_low = (p->adapter_control & CFSTERM);
-        enableSE_high = (p->adapter_control & CFWSTERM);
-      }
-      if (!(p->adapter_control & CFAUTOTERM))
-      {
-        enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
-      }
-
-      /*
-       * Now take those settings that we have and translate them into the
-       * values that must be written into the registers.
-       *
-       * Flash Enable = BRDDAT7
-       * Secondary High Term Enable = BRDDAT6
-       * Secondary Low Term Enable = BRDDAT5
-       * LVD/Primary High Term Enable = BRDDAT4
-       * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1
-       */
-      if (enableLVD_low != 0)
-      {
-        sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_LVD;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination "
-                 "Enabled\n", p->host_no);
-      }
-          
-      if (enableLVD_high != 0)
-      {
-        brddat |= BRDDAT4;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination "
-                 "Enabled\n", p->host_no);
-      }
-
-      if (enableSE_low != 0)
-      {
-        brddat |= BRDDAT5;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) Secondary Low byte termination "
-                 "Enabled\n", p->host_no);
-      }
-
-      if (enableSE_high != 0)
-      {
-        brddat |= BRDDAT6;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) Secondary High byte termination "
-                 "Enabled\n", p->host_no);
-      }
-    }
-    else if (p->features & AHC_NEW_AUTOTERM)
-    {
-      /*
-       * The 50 pin connector termination is controlled by STPWEN in the
-       * SXFRCTL1 register.  Since the Adaptec docs typically say the
-       * controller is not allowed to be in the middle of a cable and
-       * this is the only connection on that stub of the bus, there is
-       * no need to even check for narrow termination, it's simply
-       * always on.
-       */
-      sxfrctl1 |= STPWEN;
-      if (aic7xxx_verbose & VERBOSE_PROBE2)
-        printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n",
-               p->host_no);
-
-      if (p->adapter_control & CFAUTOTERM)
-      {
-        aic2940_uwpro_wide_cable_detect(p, &internal68_present,
-                                        &external_present,
-                                        &eprom_present);
-        printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
-               "Ext-68 %s)\n", p->host_no,
-               "Don't Care",
-               internal68_present ? "YES" : "NO",
-               external_present ? "YES" : "NO");
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
-               eprom_present ? "is" : "is not");
-        if (internal68_present && external_present)
-        {
-          brddat = 0;
-          p->flags &= ~AHC_TERM_ENB_SE_HIGH;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n",
-                   p->host_no);
-        }
-        else
-        {
-          brddat = BRDDAT6;
-          p->flags |= AHC_TERM_ENB_SE_HIGH;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
-                   p->host_no);
-        }
-      }
-      else
-      {
-        /*
-         * The termination of the Wide channel is done more like normal
-         * though, and the setting of this termination is done by writing
-         * either a 0 or 1 to BRDDAT6 of the BRDDAT register
-         */
-        if (p->adapter_control & CFWSTERM)
-        {
-          brddat = BRDDAT6;
-          p->flags |= AHC_TERM_ENB_SE_HIGH;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
-                   p->host_no);
-        }
-        else
-        {
-          brddat = 0;
-        }
-      }
-    }
-    else
-    {
-      if (p->adapter_control & CFAUTOTERM)
-      {
-        if (p->flags & AHC_MOTHERBOARD)
-        {
-          printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
-                 p->host_no);
-          printk(KERN_INFO "(scsi%d) Please verify driver detected settings "
-            "are correct.\n", p->host_no);
-          printk(KERN_INFO "(scsi%d) If not, then please properly set the "
-            "device termination\n", p->host_no);
-          printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting "
-            "CTRL-A when prompted\n", p->host_no);
-          printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no);
-        }
-        /* Configure auto termination. */
-
-        if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
-        {
-          aic787x_cable_detect(p, &internal50_present, &internal68_present,
-            &external_present, &eprom_present);
-        }
-        else
-        {
-          aic785x_cable_detect(p, &internal50_present, &external_present,
-            &eprom_present);
-        }
-
-        if (max_target <= 8)
-          internal68_present = 0;
-
-        if (max_target > 8)
-        {
-          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
-                 "Ext-68 %s)\n", p->host_no,
-                 internal50_present ? "YES" : "NO",
-                 internal68_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        else
-        {
-          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n",
-                 p->host_no,
-                 internal50_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
-        }
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
-               eprom_present ? "is" : "is not");
-
-        /*
-         * Now set the termination based on what we found.  BRDDAT6
-         * controls wide termination enable.
-         * Flash Enable = BRDDAT7
-         * SE High Term Enable = BRDDAT6
-         */
-        if (internal50_present && internal68_present && external_present)
-        {
-          printk(KERN_INFO "(scsi%d) Illegal cable configuration!!  Only two\n",
-                 p->host_no);
-          printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
-                 "in use at a time!\n", p->host_no);
-          /*
-           * Force termination (low and high byte) on.  This is safer than
-           * leaving it completely off, especially since this message comes
-           * most often from motherboard controllers that don't even have 3
-           * connectors, but instead are failing the cable detection.
-           */
-          internal50_present = external_present = 0;
-          enableSE_high = enableSE_low = 1;
-        }
-
-        if ((max_target > 8) &&
-            ((external_present == 0) || (internal68_present == 0)) )
-        {
-          brddat |= BRDDAT6;
-          p->flags |= AHC_TERM_ENB_SE_HIGH;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
-                   p->host_no);
-        }
-
-        if ( ((internal50_present ? 1 : 0) +
-              (internal68_present ? 1 : 0) +
-              (external_present   ? 1 : 0)) <= 1 )
-        {
-          sxfrctl1 |= STPWEN;
-          p->flags |= AHC_TERM_ENB_SE_LOW;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
-                   p->host_no);
-        }
-      }
-      else /* p->adapter_control & CFAUTOTERM */
-      {
-        if (p->adapter_control & CFSTERM)
-        {
-          sxfrctl1 |= STPWEN;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
-                   p->host_no);
-        }
-
-        if (p->adapter_control & CFWSTERM)
-        {
-          brddat |= BRDDAT6;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
-                   p->host_no);
-        }
-      }
-    }
-
-    aic_outb(p, sxfrctl1, SXFRCTL1);
-    write_brdctl(p, brddat);
-    release_seeprom(p);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   detect_maxscb
- *
- * Description:
- *   Detects the maximum number of SCBs for the controller and returns
- *   the count and a mask in p (p->maxscbs, p->qcntmask).
- *-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host *p)
-{
-  int i;
-
-  /*
-   * It's possible that we've already done this for multichannel
-   * adapters.
-   */
-  if (p->scb_data->maxhscbs == 0)
-  {
-    /*
-     * We haven't initialized the SCB settings yet.  Walk the SCBs to
-     * determince how many there are.
-     */
-    aic_outb(p, 0, FREE_SCBH);
-
-    for (i = 0; i < AIC7XXX_MAXSCB; i++)
-    {
-      aic_outb(p, i, SCBPTR);
-      aic_outb(p, i, SCB_CONTROL);
-      if (aic_inb(p, SCB_CONTROL) != i)
-        break;
-      aic_outb(p, 0, SCBPTR);
-      if (aic_inb(p, SCB_CONTROL) != 0)
-        break;
-
-      aic_outb(p, i, SCBPTR);
-      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
-      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
-      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
-      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS);  /* no busy untagged */
-      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
-      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2);
-      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3);
-    }
-
-    /* Make sure the last SCB terminates the free list. */
-    aic_outb(p, i - 1, SCBPTR);
-    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
-
-    /* Ensure we clear the first (0) SCBs control byte. */
-    aic_outb(p, 0, SCBPTR);
-    aic_outb(p, 0, SCB_CONTROL);
-
-    p->scb_data->maxhscbs = i;
-    /*
-     * Use direct indexing instead for speed
-     */
-    if ( i == AIC7XXX_MAXSCB )
-      p->flags &= ~AHC_PAGESCBS;
-  }
-
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_register
- *
- * Description:
- *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
- *-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
-  int reset_delay)
-{
-  int i, result;
-  int max_targets;
-  int found = 1;
-  unsigned char term, scsi_conf;
-  struct Scsi_Host *host;
-
-  host = p->host;
-
-  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
-  host->can_queue = AIC7XXX_MAXSCB;
-  host->cmd_per_lun = 3;
-  host->sg_tablesize = AIC7XXX_MAX_SG;
-  host->select_queue_depths = aic7xxx_select_queue_depth;
-  host->this_id = p->scsi_id;
-  host->io_port = p->base;
-  host->n_io_port = 0xFF;
-  host->base = p->mbase;
-  host->irq = p->irq;
-  if (p->features & AHC_WIDE)
-  {
-    host->max_id = 16;
-  }
-  if (p->features & AHC_TWIN)
-  {
-    host->max_channel = 1;
-  }
-
-  p->host = host;
-  p->host_no = host->host_no;
-  host->unique_id = p->instance;
-  p->isr_count = 0;
-  p->next = NULL;
-  p->completeq.head = NULL;
-  p->completeq.tail = NULL;
-  scbq_init(&p->scb_data->free_scbs);
-  scbq_init(&p->waiting_scbs);
-  init_timer(&p->dev_timer);
-  p->dev_timer.data = (unsigned long)p;
-  p->dev_timer.function = (void *)aic7xxx_timer;
-  p->dev_timer_active = 0;
-
-  /*
-   * We currently have no commands of any type
-   */
-  p->qinfifonext = 0;
-  p->qoutfifonext = 0;
-
-  for (i = 0; i < MAX_TARGETS; i++)
-  {
-    p->dev_commands_sent[i] = 0;
-    p->dev_flags[i] = 0;
-    p->dev_active_cmds[i] = 0;
-    p->dev_last_queue_full[i] = 0;
-    p->dev_last_queue_full_count[i] = 0;
-    p->dev_max_queue_depth[i] = 1;
-    p->dev_temp_queue_depth[i] = 1;
-    p->dev_expires[i] = 0;
-    scbq_init(&p->delayed_scbs[i]);
-  }
-
-  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
-    board_names[p->board_name_index]);
-  switch(p->chip)
-  {
-    case (AHC_AIC7770|AHC_EISA):
-      printk("EISA slot %d\n", p->pci_device_fn);
-      break;
-    case (AHC_AIC7770|AHC_VL):
-      printk("VLB slot %d\n", p->pci_device_fn);
-      break;
-    default:
-      printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
-        PCI_FUNC(p->pci_device_fn));
-      break;
-  }
-  if (p->features & AHC_TWIN)
-  {
-    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
-           p->host_no, p->scsi_id, p->scsi_id_b);
-  }
-  else
-  {
-    char *channel;
-
-    channel = "";
-
-    if ((p->flags & AHC_MULTI_CHANNEL) != 0)
-    {
-      channel = " A";
-
-      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
-      {
-        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
-      }
-    }
-    if (p->features & AHC_WIDE)
-    {
-      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
-    }
-    else
-    {
-      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
-    }
-    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
-  }
-  aic_outb(p, 0, SEQ_FLAGS);
-
-  detect_maxscb(p);
-
-  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  if (aic7xxx_verbose & VERBOSE_PROBE2)
-  {
-    printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
-      p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
-      p->base, p->irq);
-    printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
-      p->host_no, p->mbase, (unsigned long)p->maddr);
-  }
-
-#ifdef CONFIG_PCI
-  /*
-   * Now that we know our instance number, we can set the flags we need to
-   * force termination if need be.
-   */
-  if (aic7xxx_stpwlev != -1)
-  {
-    /*
-     * This option only applies to PCI controllers.
-     */
-    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
-    {
-      unsigned char devconfig;
-
-      pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig);
-      if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
-      {
-        devconfig |= STPWLEVEL;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no);
-      }
-      else
-      {
-        devconfig &= ~STPWLEVEL;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
-      }
-      pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
-    }
-  }
-#endif
-
-  /*
-   * That took care of devconfig and stpwlev, now for the actual termination
-   * settings.
-   */
-  if (aic7xxx_override_term != -1)
-  {
-    /*
-     * Again, this only applies to PCI controllers.  We don't have problems
-     * with the termination on 274x controllers to the best of my knowledge.
-     */
-    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
-    {
-      unsigned char term_override;
-
-      term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f);
-      p->adapter_control &= 
-        ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM);
-      if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) )
-      {
-        p->adapter_control |= CFLVDSTERM;
-      }
-      if (term_override & 0x02)
-      {
-        p->adapter_control |= CFWSTERM;
-      }
-      if (term_override & 0x01)
-      {
-        p->adapter_control |= CFSTERM;
-      }
-    }
-  }
-
-  if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) )
-  {
-    if (p->features & AHC_SPIOCAP)
-    {
-      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
-      /*
-       * Update the settings in sxfrctl1 to match the termination
-       * settings.
-       */
-        configure_termination(p);
-    }
-    else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870)
-    {
-      configure_termination(p);
-    }
-  }
-
-  /*
-   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
-   */
-  if (p->features & AHC_TWIN)
-  {
-    /* Select channel B */
-    aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
-
-    if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
-      term = (aic_inb(p, SXFRCTL1) & STPWEN);
-    else
-      term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0);
-
-    aic_outb(p, p->scsi_id_b, SCSIID);
-    scsi_conf = aic_inb(p, SCSICONF + 1);
-    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-    aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
-         ENSTIMER | ACTNEGEN, SXFRCTL1);
-    aic_outb(p, 0, SIMODE0);
-    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
-    aic_outb(p, 0, SCSIRATE);
-
-    /* Select channel A */
-    aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
-  }
-
-  if (p->features & AHC_ULTRA2)
-  {
-    aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
-  }
-  else
-  {
-    aic_outb(p, p->scsi_id, SCSIID);
-  }
-  if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
-    term = (aic_inb(p, SXFRCTL1) & STPWEN);
-  else
-    term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0);
-  scsi_conf = aic_inb(p, SCSICONF);
-  aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-  aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
-       ENSTIMER | ACTNEGEN, SXFRCTL1);
-  aic_outb(p, 0, SIMODE0);
-  /*
-   * If we are a cardbus adapter then don't enable SCSI reset detection.
-   * We shouldn't likely be sharing SCSI busses with someone else, and
-   * if we don't have a cable currently plugged into the controller then
-   * we won't have a power source for the SCSI termination, which means
-   * we'll see infinite incoming bus resets.
-   */
-  if(p->flags & AHC_NO_STPWEN)
-    aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
-  else
-    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
-  aic_outb(p, 0, SCSIRATE);
-  if ( p->features & AHC_ULTRA2)
-    aic_outb(p, 0, SCSIOFFSET);
-
-  /*
-   * Look at the information that board initialization or the board
-   * BIOS has left us. In the lower four bits of each target's
-   * scratch space any value other than 0 indicates that we should
-   * initiate synchronous transfers. If it's zero, the user or the
-   * BIOS has decided to disable synchronous negotiation to that
-   * target so we don't activate the needsdtr flag.
-   */
-  if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0)
-  {
-    max_targets = 8;
-  }
-  else
-  {
-    max_targets = 16;
-  }
-
-  if (!(aic7xxx_no_reset))
-  {
-    /*
-     * If we reset the bus, then clear the transfer settings, else leave
-     * them be
-     */
-    for (i = 0; i < max_targets; i++)
-    {
-      aic_outb(p, 0, TARG_SCSIRATE + i);
-      if (p->features & AHC_ULTRA2)
-      {
-        aic_outb(p, 0, TARG_OFFSET + i);
-      }
-      p->transinfo[i].cur_offset = 0;
-      p->transinfo[i].cur_period = 0;
-      p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT;
-    }
-
-    /*
-     * If we reset the bus, then clear the transfer settings, else leave
-     * them be.
-     */
-    aic_outb(p, 0, ULTRA_ENB);
-    aic_outb(p, 0, ULTRA_ENB + 1);
-    p->ultraenb = 0;
-  }
-
-  /*
-   * Allocate enough hardware scbs to handle the maximum number of
-   * concurrent transactions we can have.  We have to make sure that
-   * the allocated memory is contiguous memory.  The Linux kmalloc
-   * routine should only allocate contiguous memory, but note that
-   * this could be a problem if kmalloc() is changed.
-   */
-  {
-    size_t array_size;
-    unsigned int hscb_physaddr;
-
-    array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
-    if (p->scb_data->hscbs == NULL)
-    {
-      /* pci_alloc_consistent enforces the alignment already and
-       * clears the area as well.
-       */
-      p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size,
-						&p->scb_data->hscbs_dma);
-      /* We have to use pci_free_consistent, not kfree */
-      p->scb_data->hscb_kmalloc_ptr = NULL;
-      p->scb_data->hscbs_dma_len = array_size;
-    }
-    if (p->scb_data->hscbs == NULL)
-    {
-      printk("(scsi%d) Unable to allocate hardware SCB array; "
-             "failing detection.\n", p->host_no);
-      aic_outb(p, 0, SIMODE1);
-      p->irq = 0;
-      return(0);
-    }
-
-    hscb_physaddr = p->scb_data->hscbs_dma;
-    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
-    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
-    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
-    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
-
-    /* Set up the fifo areas at the same time */
-    p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma);
-    if (p->untagged_scbs == NULL)
-    {
-      printk("(scsi%d) Unable to allocate hardware FIFO arrays; "
-             "failing detection.\n", p->host_no);
-      p->irq = 0;
-      return(0);
-    }
-
-    p->qoutfifo = p->untagged_scbs + 256;
-    p->qinfifo = p->qoutfifo + 256;
-    for (i = 0; i < 256; i++)
-    {
-      p->untagged_scbs[i] = SCB_LIST_NULL;
-      p->qinfifo[i] = SCB_LIST_NULL;
-      p->qoutfifo[i] = SCB_LIST_NULL;
-    }
-
-    hscb_physaddr = p->fifo_dma;
-    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
-    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
-    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
-    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
-  }
-
-  /* The Q-FIFOs we just set up are all empty */
-  aic_outb(p, 0, QINPOS);
-  aic_outb(p, 0, KERNEL_QINPOS);
-  aic_outb(p, 0, QOUTPOS);
-
-  if(p->features & AHC_QUEUE_REGS)
-  {
-    aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA);
-    aic_outb(p, 0, SDSCB_QOFF);
-    aic_outb(p, 0, SNSCB_QOFF);
-    aic_outb(p, 0, HNSCB_QOFF);
-  }
-
-  /*
-   * We don't have any waiting selections or disconnected SCBs.
-   */
-  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
-  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
-
-  /*
-   * Message out buffer starts empty
-   */
-  aic_outb(p, MSG_NOOP, MSG_OUT);
-  aic_outb(p, MSG_NOOP, LAST_MSG);
-
-  /*
-   * Set all the other asundry items that haven't been set yet.
-   * This includes just dumping init values to a lot of registers simply
-   * to make sure they've been touched and are ready for use parity wise
-   * speaking.
-   */
-  aic_outb(p, 0, TMODE_CMDADDR);
-  aic_outb(p, 0, TMODE_CMDADDR + 1);
-  aic_outb(p, 0, TMODE_CMDADDR + 2);
-  aic_outb(p, 0, TMODE_CMDADDR + 3);
-  aic_outb(p, 0, TMODE_CMDADDR_NEXT);
-
-  /*
-   * Link us into the list of valid hosts
-   */
-  p->next = first_aic7xxx;
-  first_aic7xxx = p;
-
-  /*
-   * Allocate the first set of scbs for this controller.  This is to stream-
-   * line code elsewhere in the driver.  If we have to check for the existence
-   * of scbs in certain code sections, it slows things down.  However, as
-   * soon as we register the IRQ for this card, we could get an interrupt that
-   * includes possibly the SCSI_RSTI interrupt.  If we catch that interrupt
-   * then we are likely to segfault if we don't have at least one chunk of
-   * SCBs allocated or add checks all through the reset code to make sure
-   * that the SCBs have been allocated which is an invalid running condition
-   * and therefore I think it's preferable to simply pre-allocate the first
-   * chunk of SCBs.
-   */
-  aic7xxx_allocate_scb(p);
-
-  /*
-   * Load the sequencer program, then re-enable the board -
-   * resetting the AIC-7770 disables it, leaving the lights
-   * on with nobody home.
-   */
-  aic7xxx_loadseq(p);
-
-  /*
-   * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
-   */
-  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
-
-  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
-  {
-    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
-  }
-
-  if ( !(aic7xxx_no_reset) )
-  {
-    if (p->features & AHC_TWIN)
-    {
-      if (aic7xxx_verbose & VERBOSE_PROBE2)
-        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
-      aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
-      aic7xxx_reset_current_bus(p);
-      aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
-    }
-    /* Reset SCSI bus A. */
-    if (aic7xxx_verbose & VERBOSE_PROBE2)
-    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
-      char *channel = "";
-      if (p->flags & AHC_MULTI_CHANNEL)
-      {
-        channel = " A";
-        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
-          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
-      }
-      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
-    }
-    
-    aic7xxx_reset_current_bus(p);
-
-    /*
-     * Delay for the reset delay by setting the timer, this will delay
-     * future commands sent to any devices.
-     */
-    p->flags |= AHC_RESET_DELAY;
-    for(i=0; i<MAX_TARGETS; i++)
-    {
-      p->dev_expires[i] = jiffies + (4 * HZ);
-      p->dev_timer_active |= (0x01 << i);
-    }
-    p->dev_timer.expires = p->dev_expires[p->scsi_id];
-    add_timer(&p->dev_timer);
-    p->dev_timer_active |= (0x01 << MAX_TARGETS);
-  }
-  else
-  {
-    if (!reset_delay)
-    {
-      printk(KERN_INFO "(scsi%d) Not resetting SCSI bus.  Note: Don't use "
-             "the no_reset\n", p->host_no);
-      printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
-             "for it.\n", p->host_no);
-    }
-  }
-  
-  /*
-   * Register IRQ with the kernel.  Only allow sharing IRQs with
-   * PCI devices.
-   */
-  if (!(p->chip & AHC_PCI))
-  {
-    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
-  }
-  else
-  {
-    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
-              "aic7xxx", p));
-    if (result < 0)
-    {
-      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
-              "aic7xxx", p));
-    }
-  }
-  if (result < 0)
-  {
-    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
-           "controller.\n", p->host_no, p->irq);
-    aic_outb(p, 0, SIMODE1);
-    p->irq = 0;
-    return (0);
-  }
-
-  if(aic_inb(p, INTSTAT) & INT_PEND)
-    printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n",
-      p->host_no, -1, -1 , -1);
-  aic7xxx_clear_intstat(p);
-
-  unpause_sequencer(p, /* unpause_always */ TRUE);
-
-  return (found);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_chip_reset
- *
- * Description:
- *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
- *   is paused upon return.
- *-F*************************************************************************/
-int
-aic7xxx_chip_reset(struct aic7xxx_host *p)
-{
-  unsigned char sblkctl;
-  int wait;
-
-  /*
-   * For some 274x boards, we must clear the CHIPRST bit and pause
-   * the sequencer. For some reason, this makes the driver work.
-   */
-  aic_outb(p, PAUSE | CHIPRST, HCNTRL);
-
-  /*
-   * In the future, we may call this function as a last resort for
-   * error handling.  Let's be nice and not do any unecessary delays.
-   */
-  wait = 1000;  /* 1 msec (1000 * 1 msec) */
-  while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
-  {
-    udelay(1);  /* 1 usec */
-  }
-
-  pause_sequencer(p);
-
-  sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE);
-  if (p->chip & AHC_PCI)
-    sblkctl &= ~SELBUSB;
-  switch( sblkctl )
-  {
-    case 0:  /* normal narrow card */
-      break;
-    case 2:  /* Wide card */
-      p->features |= AHC_WIDE;
-      break;
-    case 8:  /* Twin card */
-      p->features |= AHC_TWIN;
-      p->flags |= AHC_MULTI_CHANNEL;
-      break;
-    default: /* hmmm...we don't know what this is */
-      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
-        aic_inb(p, SBLKCTL) & 0x0a);
-      return(-1);
-  }
-  return(0);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_alloc
- *
- * Description:
- *   Allocate and initialize a host structure.  Returns NULL upon error
- *   and a pointer to a aic7xxx_host struct upon success.
- *-F*************************************************************************/
-static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
-{
-  struct aic7xxx_host *p = NULL;
-  struct Scsi_Host *host;
-  int i;
-
-  /*
-   * Allocate a storage area by registering us with the mid-level
-   * SCSI layer.
-   */
-  host = scsi_register(sht, sizeof(struct aic7xxx_host));
-
-  if (host != NULL)
-  {
-    p = (struct aic7xxx_host *) host->hostdata;
-    memset(p, 0, sizeof(struct aic7xxx_host));
-    *p = *temp;
-    p->host = host;
-
-    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
-    if (p->scb_data != NULL)
-    {
-      memset(p->scb_data, 0, sizeof(scb_data_type));
-      scbq_init (&p->scb_data->free_scbs);
-    }
-    else
-    {
-      /*
-       * For some reason we don't have enough memory.  Free the
-       * allocated memory for the aic7xxx_host struct, and return NULL.
-       */
-      release_region(p->base, MAXREG - MINREG);
-      scsi_unregister(host);
-      return(NULL);
-    }
-    p->host_no = host->host_no;
-    p->tagenable = 0;
-    p->orderedtag = 0;
-    for (i=0; i<MAX_TARGETS; i++)
-    {
-      p->transinfo[i].goal_period = 255;
-      p->transinfo[i].goal_offset = 0;
-      p->transinfo[i].goal_options = 0;
-      p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
-    }
-    DRIVER_LOCK_INIT
-  }
-  return (p);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_free
- *
- * Description:
- *   Frees and releases all resources associated with an instance of
- *   the driver (struct aic7xxx_host *).
- *-F*************************************************************************/
-static void
-aic7xxx_free(struct aic7xxx_host *p)
-{
-  int i;
-
-  /*
-   * Free the allocated hardware SCB space.
-   */
-  if (p->scb_data != NULL)
-  {
-    struct aic7xxx_scb_dma *scb_dma = NULL;
-    if (p->scb_data->hscbs != NULL)
-    {
-      pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len,
-			  p->scb_data->hscbs, p->scb_data->hscbs_dma);
-      p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
-    }
-    /*
-     * Free the driver SCBs.  These were allocated on an as-need
-     * basis.  We allocated these in groups depending on how many
-     * we could fit into a given amount of RAM.  The tail SCB for
-     * these allocations has a pointer to the alloced area.
-     */
-    for (i = 0; i < p->scb_data->numscbs; i++)
-    {
-      if (p->scb_data->scb_array[i]->scb_dma != scb_dma)
-      {
-	scb_dma = p->scb_data->scb_array[i]->scb_dma;
-	pci_free_consistent(p->pdev, scb_dma->dma_len,
-			    (void *)((unsigned long)scb_dma->dma_address
-                                     - scb_dma->dma_offset),
-			    scb_dma->dma_address);
-      }
-      if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
-        kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
-      p->scb_data->scb_array[i] = NULL;
-    }
-  
-    /*
-     * Free the SCB data area.
-     */
-    kfree(p->scb_data);
-  }
-
-  /*
-   * Free any alloced Scsi_Cmnd structures that might be around for
-   * negotiation purposes....
-   */
-  for (i = 0; i < MAX_TARGETS; i++)
-  {
-    if(p->dev_dtr_cmnd[i])
-    {
-      if(p->dev_dtr_cmnd[i]->request_buffer)
-      {
-        kfree(p->dev_dtr_cmnd[i]->request_buffer);
-      }
-      kfree(p->dev_dtr_cmnd[i]);
-    }
-  }
-
-  pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_load_seeprom
- *
- * Description:
- *   Load the seeprom and configure adapter and target settings.
- *   Returns 1 if the load was successful and 0 otherwise.
- *-F*************************************************************************/
-static void
-aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
-{
-  int have_seeprom = 0;
-  int i, max_targets, mask;
-  unsigned char scsirate, scsi_conf;
-  unsigned short scarray[128];
-  struct seeprom_config *sc = (struct seeprom_config *) scarray;
-
-  if (aic7xxx_verbose & VERBOSE_PROBE2)
-  {
-    printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
-  }
-  switch (p->chip)
-  {
-    case (AHC_AIC7770|AHC_EISA):  /* None of these adapters have seeproms. */
-      if (aic_inb(p, SCSICONF) & TERM_ENB)
-        p->flags |= AHC_TERM_ENB_A;
-      if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) )
-        p->flags |= AHC_TERM_ENB_B;
-      break;
-
-    case (AHC_AIC7770|AHC_VL):
-      have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
-      break;
-
-    default:
-      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                  scarray, p->sc_size, p->sc_type);
-      if (!have_seeprom)
-      {
-        if(p->sc_type == C46)
-          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                      scarray, p->sc_size, C56_66);
-        else
-          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                      scarray, p->sc_size, C46);
-      }
-      if (!have_seeprom)
-      {
-        p->sc_size = 128;
-        have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                    scarray, p->sc_size, p->sc_type);
-        if (!have_seeprom)
-        {
-          if(p->sc_type == C46)
-            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                        scarray, p->sc_size, C56_66);
-          else
-            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
-                                        scarray, p->sc_size, C46);
-        }
-      }
-      break;
-  }
-
-  if (!have_seeprom)
-  {
-    if (aic7xxx_verbose & VERBOSE_PROBE2)
-    {
-      printk("\naic7xxx: No SEEPROM available.\n");
-    }
-    p->flags |= AHC_NEWEEPROM_FMT;
-    if (aic_inb(p, SCSISEQ) == 0)
-    {
-      p->flags |= AHC_USEDEFAULTS;
-      p->flags &= ~AHC_BIOS_ENABLED;
-      p->scsi_id = p->scsi_id_b = 7;
-      *sxfrctl1 |= STPWEN;
-      if (aic7xxx_verbose & VERBOSE_PROBE2)
-      {
-        printk("aic7xxx: Using default values.\n");
-      }
-    }
-    else if (aic7xxx_verbose & VERBOSE_PROBE2)
-    {
-      printk("aic7xxx: Using leftover BIOS values.\n");
-    }
-    if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
-    {
-      p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
-      sc->adapter_control &= ~CFAUTOTERM;
-      sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
-    }
-    if (aic7xxx_extended)
-      p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
-    else
-      p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
-  }
-  else
-  {
-    if (aic7xxx_verbose & VERBOSE_PROBE2)
-    {
-      printk("done\n");
-    }
-
-    /*
-     * Note things in our flags
-     */
-    p->flags |= AHC_SEEPROM_FOUND;
-
-    /*
-     * Update the settings in sxfrctl1 to match the termination settings.
-     */
-    *sxfrctl1 = 0;
-
-    /*
-     * Get our SCSI ID from the SEEPROM setting...
-     */
-    p->scsi_id = (sc->brtime_id & CFSCSIID);
-
-    /*
-     * First process the settings that are different between the VLB
-     * and PCI adapter seeproms.
-     */
-    if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770)
-    {
-      /* VLB adapter seeproms */
-      if (sc->bios_control & CF284XEXTEND)
-        p->flags |= AHC_EXTEND_TRANS_A;
-
-      if (sc->adapter_control & CF284XSTERM)
-      {
-        *sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
-      }
-    }
-    else
-    {
-      /* PCI adapter seeproms */
-      if (sc->bios_control & CFEXTEND)
-        p->flags |= AHC_EXTEND_TRANS_A;
-      if (sc->bios_control & CFBIOSEN)
-        p->flags |= AHC_BIOS_ENABLED;
-      else
-        p->flags &= ~AHC_BIOS_ENABLED;
-
-      if (sc->adapter_control & CFSTERM)
-      {
-        *sxfrctl1 |= STPWEN;
-        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
-      }
-    }
-    memcpy(&p->sc, sc, sizeof(struct seeprom_config));
-  }
-
-  p->discenable = 0;
-    
-  /*
-   * Limit to 16 targets just in case.  The 2842 for one is known to
-   * blow the max_targets setting, future cards might also.
-   */
-  max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
-
-  if (have_seeprom)
-  {
-    for (i = 0; i < max_targets; i++)
-    {
-      if( ((p->features & AHC_ULTRA) &&
-          !(sc->adapter_control & CFULTRAEN) &&
-           (sc->device_flags[i] & CFSYNCHISULTRA)) ||
-          (sc->device_flags[i] & CFNEWULTRAFORMAT) )
-      {
-        p->flags |= AHC_NEWEEPROM_FMT;
-        break;
-      }
-    }
-  }
-
-  for (i = 0; i < max_targets; i++)
-  {
-    mask = (0x01 << i);
-    if (!have_seeprom)
-    {
-      if (aic_inb(p, SCSISEQ) != 0)
-      {
-        /*
-         * OK...the BIOS set things up and left behind the settings we need.
-         * Just make our sc->device_flags[i] entry match what the card has
-         * set for this device.
-         */
-        p->discenable = 
-          ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
-        p->ultraenb =
-          (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) );
-        sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
-        if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER)
-          sc->device_flags[i] |= CFWIDEB;
-        if (p->features & AHC_ULTRA2)
-        {
-          if (aic_inb(p, TARG_OFFSET + i))
-          {
-            sc->device_flags[i] |= CFSYNCH;
-            sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07);
-            if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 )
-              sc->device_flags[i] |= CFSYNCHISULTRA;
-          }
-        }
-        else
-        {
-          if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER)
-          {
-            sc->device_flags[i] |= CFSYNCH;
-            if (p->features & AHC_ULTRA)
-              sc->device_flags[i] |= ((p->ultraenb & mask) ?
-                                      CFSYNCHISULTRA : 0);
-          }
-        }
-      }
-      else
-      {
-        /*
-         * Assume the BIOS has NOT been run on this card and nothing between
-         * the card and the devices is configured yet.
-         */
-        sc->device_flags[i] = CFDISC;
-        if (p->features & AHC_WIDE)
-          sc->device_flags[i] |= CFWIDEB;
-        if (p->features & AHC_ULTRA3)
-          sc->device_flags[i] |= 2;
-        else if (p->features & AHC_ULTRA2)
-          sc->device_flags[i] |= 3;
-        else if (p->features & AHC_ULTRA)
-          sc->device_flags[i] |= CFSYNCHISULTRA;
-        sc->device_flags[i] |= CFSYNCH;
-        aic_outb(p, 0, TARG_SCSIRATE + i);
-        if (p->features & AHC_ULTRA2)
-          aic_outb(p, 0, TARG_OFFSET + i);
-      }
-    }
-    if (sc->device_flags[i] & CFDISC)
-    {
-      p->discenable |= mask;
-    }
-    if (p->flags & AHC_NEWEEPROM_FMT)
-    {
-      if ( !(p->features & AHC_ULTRA2) )
-      {
-        /*
-         * I know of two different Ultra BIOSes that do this differently.
-         * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
-         * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s
-         * while on the IBM Netfinity 5000 they want the same thing
-         * to be something else, while flags[i] & CFXFER == 0x03 and
-         * SYNCHISULTRA false should be 40MByte/s.  So, we set both to
-         * 40MByte/s and the lower speeds be damned.  People will have
-         * to select around the conversely mapped lower speeds in order
-         * to select lower speeds on these boards.
-         */
-        if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
-            ((sc->device_flags[i] & CFXFER) == 0x03) )
-        {
-          sc->device_flags[i] &= ~CFXFER;
-          sc->device_flags[i] |= CFSYNCHISULTRA;
-        }
-        if (sc->device_flags[i] & CFSYNCHISULTRA)
-        {
-          p->ultraenb |= mask;
-        }
-      }
-      else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) &&
-                 (p->features & AHC_ULTRA2) &&
-		 (sc->device_flags[i] & CFSYNCHISULTRA) )
-      {
-        p->ultraenb |= mask;
-      }
-    }
-    else if (sc->adapter_control & CFULTRAEN)
-    {
-      p->ultraenb |= mask;
-    }
-    if ( (sc->device_flags[i] & CFSYNCH) == 0)
-    {
-      sc->device_flags[i] &= ~CFXFER;
-      p->ultraenb &= ~mask;
-      p->transinfo[i].user_offset = 0;
-      p->transinfo[i].user_period = 0;
-      p->transinfo[i].user_options = 0;
-      p->transinfo[i].cur_offset = 0;
-      p->transinfo[i].cur_period = 0;
-      p->transinfo[i].cur_options = 0;
-      p->needsdtr_copy &= ~mask;
-    }
-    else
-    {
-      if (p->features & AHC_ULTRA3)
-      {
-        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
-        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
-        if( (sc->device_flags[i] & CFXFER) < 0x03 )
-        {
-          scsirate = (sc->device_flags[i] & CFXFER);
-          p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
-          if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
-          {
-            p->transinfo[i].cur_options = 
-              ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
-                 MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
-          }
-          else
-          {
-            p->transinfo[i].cur_options = 0;
-          }
-        }
-        else
-        {
-          scsirate = (sc->device_flags[i] & CFXFER) |
-                     ((p->ultraenb & mask) ? 0x18 : 0x10);
-          p->transinfo[i].user_options = 0;
-          p->transinfo[i].cur_options = 0;
-        }
-        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
-                                       AHC_SYNCRATE_ULTRA3);
-        p->transinfo[i].cur_period = aic7xxx_find_period(p,
-                                       aic_inb(p, TARG_SCSIRATE + i),
-                                       AHC_SYNCRATE_ULTRA3);
-      }
-      else if (p->features & AHC_ULTRA2)
-      {
-        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
-        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
-        scsirate = (sc->device_flags[i] & CFXFER) |
-                   ((p->ultraenb & mask) ? 0x18 : 0x10);
-        p->transinfo[i].user_options = 0;
-        p->transinfo[i].cur_options = 0;
-        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
-                                       AHC_SYNCRATE_ULTRA2);
-        p->transinfo[i].cur_period = aic7xxx_find_period(p,
-                                       aic_inb(p, TARG_SCSIRATE + i),
-                                       AHC_SYNCRATE_ULTRA2);
-      }
-      else
-      {
-        scsirate = (sc->device_flags[i] & CFXFER) << 4;
-        p->transinfo[i].user_options = 0;
-        p->transinfo[i].cur_options = 0;
-        p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
-        if (p->features & AHC_ULTRA)
-        {
-          short ultraenb;
-          ultraenb = aic_inb(p, ULTRA_ENB) |
-            (aic_inb(p, ULTRA_ENB + 1) << 8);
-          p->transinfo[i].user_period = aic7xxx_find_period(p,
-                                          scsirate,
-                                          (p->ultraenb & mask) ?
-                                          AHC_SYNCRATE_ULTRA :
-                                          AHC_SYNCRATE_FAST);
-          p->transinfo[i].cur_period = aic7xxx_find_period(p,
-                                         aic_inb(p, TARG_SCSIRATE + i),
-                                         (ultraenb & mask) ? 
-                                         AHC_SYNCRATE_ULTRA :
-                                         AHC_SYNCRATE_FAST);
-        }
-        else
-          p->transinfo[i].user_period = aic7xxx_find_period(p,
-                                          scsirate, AHC_SYNCRATE_FAST);
-      }
-      p->needsdtr_copy |= mask;
-    }
-    if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) )
-    {
-      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT;
-      p->needwdtr_copy |= mask;
-    }
-    else
-    {
-      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT;
-      p->needwdtr_copy &= ~mask;
-    }
-    p->transinfo[i].cur_width =
-      (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ?
-      MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT;
-  }
-  aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
-  aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
-  p->needppr = p->needppr_copy = p->needdv = 0;
-  p->needwdtr = p->needwdtr_copy;
-  p->needsdtr = p->needsdtr_copy;
-  p->dtr_pending = 0;
-
-  /*
-   * We set the p->ultraenb from the SEEPROM to begin with, but now we make
-   * it match what is already down in the card.  If we are doing a reset
-   * on the card then this will get put back to a default state anyway.
-   * This allows us to not have to pre-emptively negotiate when using the
-   * no_reset option.
-   */
-  if (p->features & AHC_ULTRA)
-    p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8);
-
-  
-  scsi_conf = (p->scsi_id & HSCSIID);
-
-  if(have_seeprom)
-  {
-    p->adapter_control = sc->adapter_control;
-    p->bios_control = sc->bios_control;
-
-    switch (p->chip & AHC_CHIPID_MASK)
-    {
-      case AHC_AIC7895:
-      case AHC_AIC7896:
-      case AHC_AIC7899:
-        if (p->adapter_control & CFBPRIMARY)
-          p->flags |= AHC_CHANNEL_B_PRIMARY;
-      default:
-        break;
-    }
-
-    if (sc->adapter_control & CFSPARITY)
-      scsi_conf |= ENSPCHK;
-  }
-  else
-  {
-    scsi_conf |= ENSPCHK | RESET_SCSI;
-  }
-
-  /*
-   * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card.
-   * The 2842 and 2742 cards already have these registers set and we don't
-   * want to muck with them since we don't set all the bits they do.
-   */
-  if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
-  {
-    /* Set the host ID */
-    aic_outb(p, scsi_conf, SCSICONF);
-    /* In case we are a wide card */
-    aic_outb(p, p->scsi_id, SCSICONF + 1);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_detect
- *
- * Description:
- *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
- *
- * XXX - This should really be called aic7xxx_probe().  A sequence of
- *       probe(), attach()/detach(), and init() makes more sense than
- *       one do-it-all function.  This may be useful when (and if) the
- *       mid-level SCSI code is overhauled.
- *-F*************************************************************************/
-int
-aic7xxx_detect(Scsi_Host_Template *template)
-{
-  struct aic7xxx_host *temp_p = NULL;
-  struct aic7xxx_host *current_p = NULL;
-  struct aic7xxx_host *list_p = NULL;
-  int found = 0;
-#if defined(__i386__) || defined(__alpha__)
-  ahc_flag_type flags = 0;
-  int type;
-#endif
-  unsigned char sxfrctl1;
-#if defined(__i386__) || defined(__alpha__)
-  unsigned char hcntrl, hostconf;
-  unsigned int slot, base;
-#endif
-
-#ifdef MODULE
-  /*
-   * If we are called as a module, the aic7xxx pointer may not be null
-   * and it would point to our bootup string, just like on the lilo
-   * command line.  IF not NULL, then process this config string with
-   * aic7xxx_setup
-   */
-  if(aic7xxx)
-    aic7xxx_setup(aic7xxx);
-  if(dummy_buffer[0] != 'P')
-    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
-      "/scsi/README.aic7xxx\n"
-      "aic7xxx: to see the proper way to specify options to the aic7xxx "
-      "module\n"
-      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
-      "aic7xxx: insmod or else it might trash certain memory areas.\n");
-#endif
-
-  template->proc_name = "aic7xxx";
-  template->sg_tablesize = AIC7XXX_MAX_SG;
-
-
-#ifdef CONFIG_PCI
-  /*
-   * PCI-bus probe.
-   */
-  if (pci_present())
-  {
-    struct
-    {
-      unsigned short      vendor_id;
-      unsigned short      device_id;
-      ahc_chip            chip;
-      ahc_flag_type       flags;
-      ahc_feature         features;
-      int                 board_name_index;
-      unsigned short      seeprom_size;
-      unsigned short      seeprom_type;
-    } const aic_pdevs[] = {
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
-       AHC_FNONE, AHC_FENONE,                                1,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
-       AHC_PAGESCBS, AHC_AIC7850_FE,                         5,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
-       AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                       7,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                       7,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                       7,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                       7,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
-       AHC_AIC7860_FE,                                       7,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7860_FE,                                       8,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
-       AHC_AIC7870_FE,                                       9,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     10,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7870_FE,                                      11,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7870_FE,                                      12,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     13,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
-       AHC_AIC7880_FE,                                      14,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     15,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7880_FE,                                      16,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7880_FE,                                      17,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
-       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7895_FE,                                      20,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7890_FE,                                      21,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7890_FE,                                      21,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7890_FE,                                      22,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7890_FE,                                      23,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      24,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      25,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      26,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN,
-       AHC_AIC7860_FE,                                      27,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7892_FE,                                      28,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7892_FE,                                      28,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7892_FE,                                      28,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
-       AHC_AIC7892_FE,                                      28,
-       32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7899_FE,                                      29,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7899_FE,                                      29,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7899_FE,                                      29,
-       32, C56_66 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
-       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7899_FE,                                      29,
-       32, C56_66 },
-    };
-
-    unsigned short command;
-    unsigned int  devconfig, i, oldverbose;
-    struct pci_dev *pdev = NULL;
-
-    for (i = 0; i < NUMBER(aic_pdevs); i++)
-    {
-      pdev = NULL;
-      while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
-                                     aic_pdevs[i].device_id,
-                                     pdev))) {
-	if (pci_enable_device(pdev))
-		continue;
-        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
-        {
-          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
-          {
-            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
-              "supported by\n");
-            printk(KERN_INFO "         this driver, we are ignoring it.\n");
-          }
-        }
-        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
-                                    GFP_ATOMIC)) != NULL )
-        {
-          memset(temp_p, 0, sizeof(struct aic7xxx_host));
-          temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
-          temp_p->flags = aic_pdevs[i].flags;
-          temp_p->features = aic_pdevs[i].features;
-          temp_p->board_name_index = aic_pdevs[i].board_name_index;
-          temp_p->sc_size = aic_pdevs[i].seeprom_size;
-          temp_p->sc_type = aic_pdevs[i].seeprom_type;
-
-          /*
-           * Read sundry information from PCI BIOS.
-           */
-          temp_p->irq = pdev->irq;
-          temp_p->pdev = pdev;
-          temp_p->pci_bus = pdev->bus->number;
-          temp_p->pci_device_fn = pdev->devfn;
-          temp_p->base = pci_resource_start(pdev, 0);
-          temp_p->mbase = pci_resource_start(pdev, 1);
-          current_p = list_p;
-	  while(current_p && temp_p)
-	  {
-	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
-	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
-                 (temp_p->base && (current_p->base == temp_p->base)) ||
-                 (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
-	    {
-              /* duplicate PCI entry, skip it */
-	      kfree(temp_p);
-	      temp_p = NULL;
-	    }
-	    current_p = current_p->next;
-	  }
-	  if ( temp_p == NULL )
-            continue;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk("aic7xxx: <%s> at PCI %d/%d\n", 
-              board_names[aic_pdevs[i].board_name_index],
-              PCI_SLOT(pdev->devfn),
-              PCI_FUNC(pdev->devfn));
-          pci_read_config_word(pdev, PCI_COMMAND, &command);
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-          {
-            printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
-              (int)command);
-          }
-#ifdef AIC7XXX_STRICT_PCI_SETUP
-          command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
-            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
-#else
-          command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
-#endif
-          command &= ~PCI_COMMAND_INVALIDATE;
-          if (aic7xxx_pci_parity == 0)
-            command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
-          pci_write_config_word(pdev, PCI_COMMAND, command);
-#ifdef AIC7XXX_STRICT_PCI_SETUP
-          pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-          {
-            printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
-          }
-          devconfig |= 0x80000040;
-          pci_write_config_dword(pdev, DEVCONFIG, devconfig);
-#endif /* AIC7XXX_STRICT_PCI_SETUP */
-
-          if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
-          {
-            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
-              board_names[aic_pdevs[i].board_name_index],
-              temp_p->pci_bus,
-              PCI_SLOT(temp_p->pci_device_fn),
-              PCI_FUNC(temp_p->pci_device_fn));
-            printk("aic7xxx: I/O ports already in use, ignoring.\n");
-            kfree(temp_p);
-            temp_p = NULL;
-            continue;
-          }
-
-          temp_p->unpause = INTEN;
-          temp_p->pause = temp_p->unpause | PAUSE;
-          if ( ((temp_p->base == 0) &&
-                (temp_p->mbase == 0)) ||
-               (temp_p->irq == 0) )
-          {
-            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
-              board_names[aic_pdevs[i].board_name_index],
-              temp_p->pci_bus,
-              PCI_SLOT(temp_p->pci_device_fn),
-              PCI_FUNC(temp_p->pci_device_fn));
-            printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
-            kfree(temp_p);
-            temp_p = NULL;
-            continue;
-          }
-
-#ifdef MMAPIO
-          if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
-               ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
-                (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
-          {
-            unsigned long page_offset, base;
-
-            base = temp_p->mbase & PAGE_MASK;
-            page_offset = temp_p->mbase - base;
-            temp_p->maddr = ioremap_nocache(base, page_offset + 256);
-            if(temp_p->maddr)
-            {
-              temp_p->maddr += page_offset;
-              /*
-               * We need to check the I/O with the MMAPed address.  Some machines
-               * simply fail to work with MMAPed I/O and certain controllers.
-               */
-              if(aic_inb(temp_p, HCNTRL) == 0xff)
-              {
-                /*
-                 * OK.....we failed our test....go back to programmed I/O
-                 */
-                printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
-                  board_names[aic_pdevs[i].board_name_index],
-                  temp_p->pci_bus,
-                  PCI_SLOT(temp_p->pci_device_fn),
-                  PCI_FUNC(temp_p->pci_device_fn));
-                printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
-                                 "Programmed I/O.\n");
-                iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
-                temp_p->maddr = 0;
-                if(temp_p->base == 0)
-                {
-                  printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
-                    board_names[aic_pdevs[i].board_name_index],
-                    temp_p->pci_bus,
-                    PCI_SLOT(temp_p->pci_device_fn),
-                    PCI_FUNC(temp_p->pci_device_fn));
-                  printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
-                  kfree(temp_p);
-                  temp_p = NULL;
-                  continue;
-                }
-              }
-            }
-          }
-#endif
-
-          /*
-           * Lock out other contenders for our i/o space.
-           */
-          if(temp_p->base)
-            request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
-
-          /*
-           * We HAVE to make sure the first pause_sequencer() and all other
-           * subsequent I/O that isn't PCI config space I/O takes place
-           * after the MMAPed I/O region is configured and tested.  The
-           * problem is the PowerPC architecture that doesn't support
-           * programmed I/O at all, so we have to have the MMAP I/O set up
-           * for this pause to even work on those machines.
-           */
-          pause_sequencer(temp_p);
-
-          /*
-           * Clear out any pending PCI error status messages.  Also set
-           * verbose to 0 so that we don't emit strange PCI error messages
-           * while cleaning out the current status bits.
-           */
-          oldverbose = aic7xxx_verbose;
-          aic7xxx_verbose = 0;
-          aic7xxx_pci_intr(temp_p);
-          aic7xxx_verbose = oldverbose;
-
-          temp_p->bios_address = 0;
-
-          /*
-           * Remember how the card was setup in case there is no seeprom.
-           */
-          if (temp_p->features & AHC_ULTRA2)
-            temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID;
-          else
-            temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
-          /*
-           * Get current termination setting
-           */
-          sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
-
-          if (aic7xxx_chip_reset(temp_p) == -1)
-          {
-            release_region(temp_p->base, MAXREG - MINREG);
-            kfree(temp_p);
-            temp_p = NULL;
-            continue;
-          }
-          /*
-           * Very quickly put the term setting back into the register since
-           * the chip reset may cause odd things to happen.  This is to keep
-           * LVD busses with lots of drives from draining the power out of
-           * the diffsense line before we get around to running the
-           * configure_termination() function.  Also restore the STPWLEVEL
-           * bit of DEVCONFIG
-           */
-          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
-          pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
-          sxfrctl1 &= STPWEN;
-
-          /*
-           * We need to set the CHNL? assignments before loading the SEEPROM
-           * The 3940 and 3985 cards (original stuff, not any of the later
-           * stuff) are 7870 and 7880 class chips.  The Ultra2 stuff falls
-           * under 7896 and 7897.  The 7895 is in a class by itself :)
-           */
-          switch (temp_p->chip & AHC_CHIPID_MASK)
-          {
-            case AHC_AIC7870: /* 3840 / 3985 */
-            case AHC_AIC7880: /* 3840 UW / 3985 UW */
-              if(temp_p->flags & AHC_MULTI_CHANNEL)
-              {
-                switch(PCI_SLOT(temp_p->pci_device_fn))
-                {
-                  case 5:
-                    temp_p->flags |= AHC_CHNLB;
-                    break;
-                  case 8:
-                    temp_p->flags |= AHC_CHNLB;
-                    break;
-                  case 12:
-                    temp_p->flags |= AHC_CHNLC;
-                    break;
-                  default:
-                    break;
-                }
-              }
-              break;
-
-            case AHC_AIC7895: /* 7895 */
-            case AHC_AIC7896: /* 7896/7 */
-            case AHC_AIC7899: /* 7899 */
-              if (PCI_FUNC(pdev->devfn) != 0)
-              {
-                temp_p->flags |= AHC_CHNLB;
-              }
-              /*
-               * The 7895 is the only chipset that sets the SCBSIZE32 param
-               * in the DEVCONFIG register.  The Ultra2 chipsets use
-               * the DSCOMMAND0 register instead.
-               */
-              if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
-              {
-                pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-                devconfig |= SCBSIZE32;
-                pci_write_config_dword(pdev, DEVCONFIG, devconfig);
-              }
-              break;
-            default:
-              break;
-          }
-
-          /*
-           * Loading of the SEEPROM needs to come after we've set the flags
-           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
-           * on 394x and 398x cards we'll end up reading the wrong settings
-           * for channels B and C
-           */
-          switch (temp_p->chip & AHC_CHIPID_MASK)
-          {
-            case AHC_AIC7892:
-            case AHC_AIC7899:
-              aic_outb(temp_p, 0, SCAMCTL);
-              /*
-               * Switch to the alt mode of the chip...
-               */
-              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
-              /*
-               * Set our options...the last two items set our CRC after x byte
-	       * count in target mode...
-               */
-              aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
-	      aic_outb(temp_p, 0x00, 0x0b);
-	      aic_outb(temp_p, 0x10, 0x0a);
-              /*
-               * switch back to normal mode...
-               */
-              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
-              aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
-			       TARGCRCENDEN | TARGCRCCNTEN,
-                       CRCCONTROL1);
-              aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
-                                 MPARCKEN | CIOPARCKEN | CACHETHEN) & 
-                               ~DPARCKEN), DSCOMMAND0);
-              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
-              break;
-            case AHC_AIC7890:
-            case AHC_AIC7896:
-              aic_outb(temp_p, 0, SCAMCTL);
-              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
-                                CACHETHEN | MPARCKEN | USCBSIZE32 |
-                                CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
-              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
-              break;
-            case AHC_AIC7850:
-            case AHC_AIC7860:
-              /*
-               * Set the DSCOMMAND0 register on these cards different from
-               * on the 789x cards.  Also, read the SEEPROM as well.
-               */
-              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
-                                CACHETHEN | MPARCKEN) & ~DPARCKEN,
-                       DSCOMMAND0);
-              /* FALLTHROUGH */
-            default:
-              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
-              break;
-            case AHC_AIC7880:
-              /*
-               * Check the rev of the chipset before we change DSCOMMAND0
-               */
-              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-              if ((devconfig & 0xff) >= 1)
-              {
-                aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
-                                  CACHETHEN | MPARCKEN) & ~DPARCKEN,
-                         DSCOMMAND0);
-              }
-              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
-              break;
-          }
-          
-
-          /*
-           * and then we need another switch based on the type in order to
-           * make sure the channel B primary flag is set properly on 7895
-           * controllers....Arrrgggghhh!!!  We also have to catch the fact
-           * that when you disable the BIOS on the 7895 on the Intel DK440LX
-           * motherboard, and possibly others, it only sets the BIOS disabled
-           * bit on the A channel...I think I'm starting to lean towards
-           * going postal....
-           */
-          switch(temp_p->chip & AHC_CHIPID_MASK)
-          {
-            case AHC_AIC7895:
-            case AHC_AIC7896:
-            case AHC_AIC7899:
-              current_p = list_p;
-              while(current_p != NULL)
-              {
-                if ( (current_p->pci_bus == temp_p->pci_bus) &&
-                     (PCI_SLOT(current_p->pci_device_fn) ==
-                      PCI_SLOT(temp_p->pci_device_fn)) )
-                {
-                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
-                  {
-                    temp_p->flags |= 
-                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
-                    temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
-                    temp_p->flags |=
-                      (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
-                  }
-                  else
-                  {
-                    current_p->flags |=
-                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
-                    current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
-                    current_p->flags |=
-                      (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
-                  }
-                }
-                current_p = current_p->next;
-              }
-              break;
-            default:
-              break;
-          }
-
-          /*
-           * We only support external SCB RAM on the 7895/6/7 chipsets.
-           * We could support it on the 7890/1 easy enough, but I don't
-           * know of any 7890/1 based cards that have it.  I do know
-           * of 7895/6/7 cards that have it and they work properly.
-           */
-          switch(temp_p->chip & AHC_CHIPID_MASK)
-          {
-            default:
-              break;
-            case AHC_AIC7895:
-            case AHC_AIC7896:
-            case AHC_AIC7899:
-              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
-              if (temp_p->features & AHC_ULTRA2)
-              {
-                if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
-                     (aic7xxx_scbram) )
-                {
-                  aic_outb(temp_p,
-                           aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
-                           DSCOMMAND0);
-                  temp_p->flags |= AHC_EXTERNAL_SRAM;
-                  devconfig |= EXTSCBPEN;
-                }
-                else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
-                {
-                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
-                    board_names[aic_pdevs[i].board_name_index],
-                    temp_p->pci_bus,
-                    PCI_SLOT(temp_p->pci_device_fn),
-                    PCI_FUNC(temp_p->pci_device_fn));
-                  printk("aic7xxx: external SCB RAM detected, "
-                         "but not enabled\n");
-                }
-              }
-              else
-              {
-                if ((devconfig & RAMPSM) && (aic7xxx_scbram))
-                {
-                  devconfig &= ~SCBRAMSEL;
-                  devconfig |= EXTSCBPEN;
-                  temp_p->flags |= AHC_EXTERNAL_SRAM;
-                }
-                else if (devconfig & RAMPSM)
-                {
-                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
-                    board_names[aic_pdevs[i].board_name_index],
-                    temp_p->pci_bus,
-                    PCI_SLOT(temp_p->pci_device_fn),
-                    PCI_FUNC(temp_p->pci_device_fn));
-                  printk("aic7xxx: external SCB RAM detected, "
-                         "but not enabled\n");
-                }
-              }
-              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
-              if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
-                   (temp_p->flags & AHC_CHNLB) )
-                aic_outb(temp_p, 1, CCSCBBADDR);
-              break;
-          }
-
-          /*
-           * Take the LED out of diagnostic mode
-           */
-          aic_outb(temp_p, 
-            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
-            SBLKCTL);
-
-          /*
-           * We don't know where this is set in the SEEPROM or by the
-           * BIOS, so we default to 100%.  On Ultra2 controllers, use 75%
-           * instead.
-           */
-          if (temp_p->features & AHC_ULTRA2)
-          {
-            aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
-          }
-          else
-          {
-            aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
-          }
-
-          if ( list_p == NULL )
-          {
-            list_p = current_p = temp_p;
-          }
-          else
-          {
-            current_p = list_p;
-            while(current_p->next != NULL)
-              current_p = current_p->next;
-            current_p->next = temp_p;
-          }
-          temp_p->next = NULL;
-          found++;
-        }  /* Found an Adaptec PCI device. */
-        else /* Well, we found one, but we couldn't get any memory */
-        {
-          printk("aic7xxx: Found <%s>\n", 
-            board_names[aic_pdevs[i].board_name_index]);
-          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
-            "skipping.\n");
-        }
-      } /* while(pdev=....) */
-    } /* for PCI_DEVICES */
-  } /* PCI BIOS present */
-#endif CONFIG_PCI
-
-#if defined(__i386__) || defined(__alpha__)
-  /*
-   * EISA/VL-bus card signature probe.
-   */
-  slot = MINSLOT;
-  while ( (slot <= MAXSLOT) && 
-         !(aic7xxx_no_probe) )
-  {
-    base = SLOTBASE(slot) + MINREG;
-
-    if (check_region(base, MAXREG - MINREG))
-    {
-      /*
-       * Some other driver has staked a
-       * claim to this i/o region already.
-       */
-      slot++;
-      continue; /* back to the beginning of the for loop */
-    }
-    flags = 0;
-    type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
-    if (type == -1)
-    {
-      slot++;
-      continue;
-    }
-    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
-    if (temp_p == NULL)
-    {
-      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-      slot++;
-      continue; /* back to the beginning of the while loop */
-    }
-    /*
-     * Lock out other contenders for our i/o space.
-     */
-    request_region(base, MAXREG - MINREG, "aic7xxx");
-
-    /*
-     * Pause the card preserving the IRQ type.  Allow the operator
-     * to override the IRQ trigger.
-     */
-    if (aic7xxx_irq_trigger == 1)
-      hcntrl = IRQMS;  /* Level */
-    else if (aic7xxx_irq_trigger == 0)
-      hcntrl = 0;  /* Edge */
-    else
-      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
-    memset(temp_p, 0, sizeof(struct aic7xxx_host));
-    temp_p->unpause = hcntrl | INTEN;
-    temp_p->pause = hcntrl | PAUSE | INTEN;
-    temp_p->base = base;
-    temp_p->mbase = 0;
-    temp_p->maddr = 0;
-    temp_p->pci_bus = 0;
-    temp_p->pci_device_fn = slot;
-    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
-    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
-    if (aic7xxx_chip_reset(temp_p) == -1)
-      temp_p->irq = 0;
-    else
-      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
-    temp_p->flags |= AHC_PAGESCBS;
-
-    switch (temp_p->irq)
-    {
-      case 9:
-      case 10:
-      case 11:
-      case 12:
-      case 14:
-      case 15:
-        break;
-
-      default:
-        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
-          "level %d, ignoring.\n", temp_p->irq);
-        kfree(temp_p);
-        release_region(base, MAXREG - MINREG);
-        slot++;
-        continue; /* back to the beginning of the while loop */
-    }
-
-    /*
-     * We are commited now, everything has been checked and this card
-     * has been found, now we just set it up
-     */
-
-    /*
-     * Insert our new struct into the list at the end
-     */
-    if (list_p == NULL)
-    {
-      list_p = current_p = temp_p;
-    }
-    else
-    {
-      current_p = list_p;
-      while (current_p->next != NULL)
-        current_p = current_p->next;
-      current_p->next = temp_p;
-    }
-
-    switch (type)
-    {
-      case 0:
-        temp_p->board_name_index = 2;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk("aic7xxx: <%s> at EISA %d\n",
-               board_names[2], slot);
-        /* FALLTHROUGH */
-      case 1:
-      {
-        temp_p->chip = AHC_AIC7770 | AHC_EISA;
-        temp_p->features |= AHC_AIC7770_FE;
-        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
-
-        /*
-         * Get the primary channel information.  Right now we don't
-         * do anything with this, but someday we will be able to inform
-         * the mid-level SCSI code which channel is primary.
-         */
-        if (temp_p->board_name_index == 0)
-        {
-          temp_p->board_name_index = 3;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk("aic7xxx: <%s> at EISA %d\n",
-                 board_names[3], slot);
-        }
-        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
-        {
-          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
-        }
-
-        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
-        {
-          temp_p->flags &= ~AHC_BIOS_ENABLED;
-        }
-        else
-        {
-          temp_p->flags &= ~AHC_USEDEFAULTS;
-          temp_p->flags |= AHC_BIOS_ENABLED;
-          if ( (temp_p->bios_control & 0x20) == 0 )
-          {
-            temp_p->bios_address = 0xcc000;
-            temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
-          }
-          else
-          {
-            temp_p->bios_address = 0xd0000;
-            temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
-          }
-        }
-        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
-        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
-        if (temp_p->features & AHC_WIDE)
-        {
-          temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
-          temp_p->scsi_id_b = temp_p->scsi_id;
-        }
-        else
-        {
-          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
-          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
-        }
-        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
-        break;
-      }
-
-      case 2:
-      case 3:
-        temp_p->chip = AHC_AIC7770 | AHC_VL;
-        temp_p->features |= AHC_AIC7770_FE;
-        if (type == 2)
-          temp_p->flags |= AHC_BIOS_ENABLED;
-        else
-          temp_p->flags &= ~AHC_BIOS_ENABLED;
-        if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
-          sxfrctl1 = STPWEN;
-        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
-        temp_p->board_name_index = 4;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk("aic7xxx: <%s> at VLB %d\n",
-               board_names[2], slot);
-        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
-        {
-          case 0x00:
-            temp_p->bios_address = 0xe0000;
-            break;
-          case 0x20:
-            temp_p->bios_address = 0xc8000;
-            break;
-          case 0x40:
-            temp_p->bios_address = 0xd0000;
-            break;
-          case 0x60:
-            temp_p->bios_address = 0xd8000;
-            break;
-          default:
-            break; /* can't get here */
-        }
-        break;
-
-      default:  /* Won't get here. */
-        break;
-    }
-    if (aic7xxx_verbose & VERBOSE_PROBE2)
-    {
-      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
-        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
-        temp_p->irq,
-        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
-      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
-             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
-    }
-
-    /*
-     * Set the FIFO threshold and the bus off time.
-     */
-    hostconf = aic_inb(temp_p, HOSTCONF);
-    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
-    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
-    slot++;
-    found++;
-  }
-
-#endif /* defined(__i386__) || defined(__alpha__) */
-
-  /*
-   * Now, we re-order the probed devices by BIOS address and BUS class.
-   * In general, we follow this algorithm to make the adapters show up
-   * in the same order under linux that the computer finds them.
-   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
-   *     address, going from lowest to highest.
-   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
-   *     address, going from lowest to highest.
-   *  3: Remaining VLB/EISA controllers going in slot order.
-   *  4: Remaining PCI controllers, going in PCI device order (reversable)
-   */
-
-  {
-    struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL };
-    struct aic7xxx_host *vlb, *pci;
-    struct aic7xxx_host *prev_p;
-    struct aic7xxx_host *p;
-    unsigned char left;
-
-    prev_p = vlb = pci = NULL;
-
-    temp_p = list_p;
-    while (temp_p != NULL)
-    {
-      switch(temp_p->chip & ~AHC_CHIPID_MASK)
-      {
-        case AHC_EISA:
-        case AHC_VL:
-        {
-          p = temp_p;
-          if (p->flags & AHC_BIOS_ENABLED)
-            vlb = sort_list[0];
-          else
-            vlb = sort_list[2];
-
-          if (vlb == NULL)
-          {
-            vlb = temp_p;
-            temp_p = temp_p->next;
-            vlb->next = NULL;
-          }
-          else
-          {
-            current_p = vlb;
-            prev_p = NULL;
-            while ( (current_p != NULL) &&
-                    (current_p->bios_address < temp_p->bios_address))
-            {
-              prev_p = current_p;
-              current_p = current_p->next;
-            }
-            if (prev_p != NULL)
-            {
-              prev_p->next = temp_p;
-              temp_p = temp_p->next;
-              prev_p->next->next = current_p;
-            }
-            else
-            {
-              vlb = temp_p;
-              temp_p = temp_p->next;
-              vlb->next = current_p;
-            }
-          }
-          
-          if (p->flags & AHC_BIOS_ENABLED)
-            sort_list[0] = vlb;
-          else
-            sort_list[2] = vlb;
-          
-          break;
-        }
-        default:  /* All PCI controllers fall through to default */
-        {
-
-          p = temp_p;
-          if (p->flags & AHC_BIOS_ENABLED) 
-            pci = sort_list[1];
-          else
-            pci = sort_list[3];
-
-          if (pci == NULL)
-          {
-            pci = temp_p;
-            temp_p = temp_p->next;
-            pci->next = NULL;
-          }
-          else
-          {
-            current_p = pci;
-            prev_p = NULL;
-            if (!aic7xxx_reverse_scan)
-            {
-              while ( (current_p != NULL) &&
-                      ( (PCI_SLOT(current_p->pci_device_fn) |
-                        (current_p->pci_bus << 8)) < 
-                        (PCI_SLOT(temp_p->pci_device_fn) |
-                        (temp_p->pci_bus << 8)) ) )
-              {
-                prev_p = current_p;
-                current_p = current_p->next;
-              }
-            }
-            else
-            {
-              while ( (current_p != NULL) &&
-                      ( (PCI_SLOT(current_p->pci_device_fn) |
-                        (current_p->pci_bus << 8)) > 
-                        (PCI_SLOT(temp_p->pci_device_fn) |
-                        (temp_p->pci_bus << 8)) ) )
-              {
-                prev_p = current_p;
-                current_p = current_p->next;
-              }
-            }
-            /*
-             * Are we dealing with a 7895/6/7/9 where we need to sort the
-             * channels as well, if so, the bios_address values should
-             * be the same
-             */
-            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
-                 (temp_p->pci_bus == current_p->pci_bus) &&
-                 (PCI_SLOT(temp_p->pci_device_fn) ==
-                  PCI_SLOT(current_p->pci_device_fn)) )
-            {
-              if (temp_p->flags & AHC_CHNLB)
-              {
-                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
-                {
-                  prev_p = current_p;
-                  current_p = current_p->next;
-                }
-              }
-              else
-              {
-                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
-                {
-                  prev_p = current_p;
-                  current_p = current_p->next;
-                }
-              }
-            }
-            if (prev_p != NULL)
-            {
-              prev_p->next = temp_p;
-              temp_p = temp_p->next;
-              prev_p->next->next = current_p;
-            }
-            else
-            {
-              pci = temp_p;
-              temp_p = temp_p->next;
-              pci->next = current_p;
-            }
-          }
-
-          if (p->flags & AHC_BIOS_ENABLED)
-            sort_list[1] = pci;
-          else
-            sort_list[3] = pci;
-
-          break;
-        }
-      }  /* End of switch(temp_p->type) */
-    } /* End of while (temp_p != NULL) */
-    /*
-     * At this point, the cards have been broken into 4 sorted lists, now
-     * we run through the lists in order and register each controller
-     */
-    {
-      int i;
-      
-      left = found;
-      for (i=0; i<NUMBER(sort_list); i++)
-      {
-        temp_p = sort_list[i];
-        while(temp_p != NULL)
-        {
-          template->name = board_names[temp_p->board_name_index];
-          p = aic7xxx_alloc(template, temp_p);
-          if (p != NULL)
-          {
-            p->instance = found - left;
-            if (aic7xxx_register(template, p, (--left)) == 0)
-            {
-              found--;
-              aic7xxx_release(p->host);
-              scsi_unregister(p->host);
-            }
-            else if (aic7xxx_dump_card)
-            {
-              pause_sequencer(p);
-              aic7xxx_print_card(p);
-              aic7xxx_print_scratch_ram(p);
-              unpause_sequencer(p, TRUE);
-            }
-          }
-          current_p = temp_p;
-          temp_p = (struct aic7xxx_host *)temp_p->next;
-          kfree(current_p);
-        }
-      }
-    }
-  }
-  return (found);
-}
-
-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
-                                           Scsi_Cmnd *old_cmd, int tindex);
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_allocate_negotiation_command
- *
- * Description:
- *   allocate the actual command struct and fill in the gaps...
- *-F*************************************************************************/
-static Scsi_Cmnd *
-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
-                                     Scsi_Cmnd *old_cmd, int tindex)
-{
-  Scsi_Cmnd *cmd;
-  char *buffer;
-
-  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
-  {
-    return(NULL);
-  }
-  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
-  {
-    kfree(p->dev_dtr_cmnd[tindex]);
-    p->dev_dtr_cmnd[tindex] = NULL;
-    return(NULL);
-  }
-  cmd = p->dev_dtr_cmnd[tindex];
-  memset(cmd, 0, sizeof(Scsi_Cmnd));
-  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-  cmd->lun = 0;
-  cmd->request_bufflen = 255;
-  cmd->request_buffer = buffer;
-  cmd->sc_data_direction = SCSI_DATA_READ;
-  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-  cmd->bufflen = 0;
-  cmd->buffer = NULL;
-  cmd->underflow = 0;
-  cmd->cmd_len = 6;
-  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
-  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
-  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
-  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
-  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
-  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
-  return(cmd);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_negotiation_complete
- *
- * Description:
- *   Handle completion events for our Negotiation commands.  Clear out the
- *   struct and get it ready for its next use.
- *-F*************************************************************************/
-static void
-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
-{
-  unsigned int checksum;
-  int i;
-  int *ibuffer;
-  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
-  int tindex = TARGET_INDEX(cmd);
-  struct aic7xxx_syncrate *syncrate;
-
-  /*
-   * perform our minimalistic domain validation
-   */
-  if(p->dev_flags[tindex] & DEVICE_SCANNED)
-  {
-    ibuffer = (int *)cmd->request_buffer;
-    checksum = 0;
-    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
-    {
-      checksum += ibuffer[i];
-    }
-    if( (checksum != p->dev_checksum[tindex]) &&
-        (p->transinfo[tindex].cur_offset != 0) )
-    {
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-
-      if (p->needdv & (1<<tindex))
-      {
-        /*
-         * oops, we had a failure, lower the transfer rate and try again.  It's
-         * worth noting here that it might be wise to also check for typical
-         * wide setting on narrow cable type problems and try disabling wide
-         * instead of slowing down if those exist.  That's hard to do with simple
-         * checksums though.
-         */
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
-                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
-        }
-        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-        {
-          syncrate++;
-          if( (syncrate->rate[0] != NULL) &&
-              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-          {
-            p->transinfo[tindex].goal_period = syncrate->period;
-            if( p->transinfo[tindex].goal_period > 9 )
-            {
-              p->transinfo[tindex].goal_options = 0;
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-              if (p->transinfo[tindex].goal_width)
-              {
-                p->needwdtr |= (1<<tindex);
-                p->needwdtr_copy |= (1<<tindex);
-              }
-            }
-          }
-          else if (p->transinfo[tindex].goal_width)
-          {
-            p->transinfo[tindex].goal_width = 0;
-            p->needwdtr &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
-            if( p->transinfo[tindex].goal_period <= 9 )
-            {
-              p->needppr |= (1<<tindex);
-              p->needsdtr &= ~(1<<tindex);
-              p->needppr_copy |= (1<<tindex);
-              p->needsdtr_copy &= ~(1<<tindex);
-            }
-            else
-            {
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-            }
-          }
-          else
-          {
-            p->transinfo[tindex].goal_offset = 0;
-            p->transinfo[tindex].goal_period = 255;
-            p->transinfo[tindex].goal_options = 0;
-            p->transinfo[tindex].goal_width = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needwdtr &= ~(1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-          }
-        }
-        p->needdv &= ~(1<<tindex);
-      }
-      else
-      {
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "Performing Domain validation.\n",
-                 p->host_no, CTL_OF_CMD(cmd));
-        }
-        /*
-         * Update the checksum in case the INQUIRY data has changed, maybe
-         * in relation to a change in the mode pages, or whatever.
-         */
-        p->dev_checksum[tindex] = checksum;
-        /*
-         * Signal that we are trying out the domain validation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
-         */
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
-      }
-    } 
-    else
-    {
-      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-          (p->needdv & (1<<tindex)) )
-      {
-        printk(INFO_LEAD "Successfully completed Domain validation.\n",
-               p->host_no, CTL_OF_CMD(cmd));
-      }
-      /*
-       * We successfully did our checksum, so don't leave the needdv flag set
-       * in case we might have set it last time through.
-       */
-      p->needdv &= ~(1<<tindex);
-    }
-  }
-
-  p->dtr_pending &= ~(0x01 << tindex);
-  /*
-   * This looks recursive in the extreme, but if this was a WDTR negotiation
-   * and we didn't follow up with SDTR yet, then this will get it started.
-   * For all other cases, this should work out to be a no-op, unless we are
-   * doing domain validation and happen to need a new negotiation command.
-   *
-   * In case we don't want this to go any further, the cmdcmplt interrupt
-   * handler will NULL out the cmd->next entry so that the real SCSI command
-   * can be sent back to the mid layer code with SENSE data intact.  We'll
-   * finish things up when the cmd gets sent back down to us, so no worries.
-   */
-  if(cmd->next)
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
-  }
-  return;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_build_negotiation_command
- *
- * Description:
- *   Build a Scsi_Cmnd structure to perform negotiation with or else send
- *   a pre-built command specifically for this purpose.
- *-F*************************************************************************/
-static void
-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
-  int tindex)
-{
-
-  if ( !(p->dtr_pending & (1<<tindex)) &&
-       ( (p->needppr & (1<<tindex)) ||
-         (p->needwdtr & (1<<tindex)) ||
-         (p->needsdtr & (1<<tindex)) ) )
-  {
-    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
-         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
-    {
-      return;
-    }
-    /*
-     * Before sending this thing out, we also make the cmd->next pointer
-     * point to the real command so we can stuff any possible SENSE data
-     * into the real command instead of this fake command.  This has to be
-     * done each time the command is built, not just the first time, hence
-     * it's outside of the above if()...
-     */
-    p->dev_dtr_cmnd[tindex]->next = old_cmd;
-    /*
-     * Clear the buffer so checksums come out right....
-     */
-    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
-           p->dev_dtr_cmnd[tindex]->request_bufflen);
-    /*
-     * Remove any commands for this particular device that might be on the
-     * waiting_scbs queue or qinfifo so that this command goes out first.
-     * This is vital for our implementation of domain validation.
-     */
-    pause_sequencer(p);
-    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
-                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
-    unpause_sequencer(p, FALSE);
-    {
-      struct aic7xxx_scb *scb, *next;
-
-      scb = p->waiting_scbs.head;
-      while(scb != NULL)
-      {
-        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
-                              ALL_LUNS, SCB_LIST_NULL) )
-        {
-          next = scb->q_next;
-          scbq_remove(&p->waiting_scbs, scb);
-          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-          scb = next;
-        }
-        else
-        {
-          scb = scb->q_next;
-        }
-      }
-    }
-    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
-                  aic7xxx_negotiation_complete);
-  }
-}
-
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_print_scb
- *
- * Description:
- *   Dump the byte codes for an about to be sent SCB.
- *-F*************************************************************************/
-static void
-aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int i;
-  unsigned char *x;  
-
-  x = (unsigned char *)&scb->hscb->control;
-
-  for(i=0; i<32; i++)
-  {
-    printk("%02x ", x[i]);
-  }
-  printk("\n");
-}
-#endif
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_buildscb
- *
- * Description:
- *   Build a SCB.
- *-F*************************************************************************/
-static void
-aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
-    struct aic7xxx_scb *scb)
-{
-  unsigned short mask;
-  struct aic7xxx_hwscb *hscb;
-  unsigned char tindex = TARGET_INDEX(cmd);
-
-  mask = (0x01 << tindex);
-  hscb = scb->hscb;
-
-  /*
-   * Setup the control byte if we need negotiation and have not
-   * already requested it.
-   */
-  hscb->control = 0;
-  scb->tag_action = 0;
-  cmd->tag = hscb->tag;
-  if (p->discenable & mask)
-  {
-    hscb->control |= DISCENB;
-    if ( (p->tagenable & mask) &&
-         (cmd->cmnd[0] != TEST_UNIT_READY) )
-    {
-      p->dev_commands_sent[tindex]++;
-      if (p->dev_commands_sent[tindex] < 200)
-      {
-        hscb->control |= MSG_SIMPLE_Q_TAG;
-        scb->tag_action = MSG_SIMPLE_Q_TAG;
-      }
-      else
-      {
-        if (p->orderedtag & mask)
-        {
-          hscb->control |= MSG_ORDERED_Q_TAG;
-          scb->tag_action = MSG_ORDERED_Q_TAG;
-        }
-        else
-        {
-          hscb->control |= MSG_SIMPLE_Q_TAG;
-          scb->tag_action = MSG_SIMPLE_Q_TAG;
-        }
-        p->dev_commands_sent[tindex] = 0;
-      }
-    }
-  }
-  if ( cmd == p->dev_dtr_cmnd[tindex] )
-  {
-    p->dtr_pending |= mask;
-    scb->tag_action = 0;
-    if (p->dev_flags[tindex] & DEVICE_SCANNED)
-    {
-      hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
-      if(p->needppr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_PPR;
-      }
-      else if(p->needwdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_WDTR;
-      }
-      else if(p->needsdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_SDTR;
-      }
-    }
-  }
-  if ( !(p->dtr_pending & mask) &&
-        ( (p->needppr & mask) ||
-          (p->needwdtr & mask) ||
-          (p->needsdtr & mask) ) )
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
-  }
-  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
-        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
-
-  /*
-   * The interpretation of request_buffer and request_bufflen
-   * changes depending on whether or not use_sg is zero; a
-   * non-zero use_sg indicates the number of elements in the
-   * scatter-gather array.
-   */
-
-  /*
-   * XXX - this relies on the host data being stored in a
-   *       little-endian format.
-   */
-  hscb->SCSI_cmd_length = cmd->cmd_len;
-  memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
-  hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
-
-  if (cmd->use_sg)
-  {
-    struct scatterlist *sg;  /* Must be mid-level SCSI code scatterlist */
-
-    /*
-     * We must build an SG list in adapter format, as the kernel's SG list
-     * cannot be used directly because of data field size (__alpha__)
-     * differences and the kernel SG list uses virtual addresses where
-     * we need physical addresses.
-     */
-    int i, use_sg;
-
-    sg = (struct scatterlist *)cmd->request_buffer;
-    scb->sg_length = 0;
-    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
-    /*
-     * Copy the segments into the SG array.  NOTE!!! - We used to
-     * have the first entry both in the data_pointer area and the first
-     * SG element.  That has changed somewhat.  We still have the first
-     * entry in both places, but now we download the address of
-     * scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
-     */
-    for (i = 0; i < use_sg; i++)
-    {
-      unsigned int len = sg_dma_len(sg+i);
-      scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
-      scb->sg_list[i].length = cpu_to_le32(len);
-      scb->sg_length += len;
-    }
-    /* Copy the first SG into the data pointer area. */
-    hscb->data_pointer = scb->sg_list[0].address;
-    hscb->data_count = scb->sg_list[0].length;
-    scb->sg_count = i;
-    hscb->SG_segment_count = i;
-    hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
-  }
-  else
-  {
-    if (cmd->request_bufflen)
-    {
-      unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
-					    cmd->request_bufflen,
-                                            scsi_to_pci_dma_dir(cmd->sc_data_direction));
-      aic7xxx_mapping(cmd) = address;
-      scb->sg_list[0].address = cpu_to_le32(address);
-      scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
-      scb->sg_count = 1;
-      scb->sg_length = cmd->request_bufflen;
-      hscb->SG_segment_count = 1;
-      hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
-      hscb->data_count = scb->sg_list[0].length;
-      hscb->data_pointer = scb->sg_list[0].address;
-    }
-    else
-    {
-      scb->sg_count = 0;
-      scb->sg_length = 0;
-      hscb->SG_segment_count = 0;
-      hscb->SG_list_pointer = 0;
-      hscb->data_count = 0;
-      hscb->data_pointer = 0;
-    }
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_queue
- *
- * Description:
- *   Queue a SCB to the controller.
- *-F*************************************************************************/
-int
-aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
-{
-  struct aic7xxx_host *p;
-  struct aic7xxx_scb *scb;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  int tindex = TARGET_INDEX(cmd);
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
-
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
-  /*
-   * Check to see if channel was scanned.
-   */
-  
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
-  {
-    if (aic7xxx_verbose & VERBOSE_PROBE2)
-      printk(INFO_LEAD "Scanning channel for devices.\n",
-        p->host_no, 0, -1, -1);
-    p->flags |= AHC_A_SCANNED;
-  }
-  else
-  {
-    if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
-    {
-      if (aic7xxx_verbose & VERBOSE_PROBE2)
-        printk(INFO_LEAD "Scanning channel for devices.\n",
-          p->host_no, 1, -1, -1);
-      p->flags |= AHC_B_SCANNED;
-    }
-  }
-
-  if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1))
-  {
-    printk(WARN_LEAD "Commands queued exceeds queue "
-           "depth, active=%d\n",
-           p->host_no, CTL_OF_CMD(cmd), 
-           p->dev_active_cmds[tindex]);
-    if ( p->dev_active_cmds[tindex] > 220 )
-      p->dev_active_cmds[tindex] = 0;
-  }
-#endif
-
-  scb = scbq_remove_head(&p->scb_data->free_scbs);
-  if (scb == NULL)
-  {
-    DRIVER_LOCK
-    aic7xxx_allocate_scb(p);
-    DRIVER_UNLOCK
-    scb = scbq_remove_head(&p->scb_data->free_scbs);
-  }
-  if (scb == NULL)
-  {
-    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
-           CTL_OF_CMD(cmd));
-    cmd->result = (DID_BUS_BUSY << 16);
-    DRIVER_LOCK
-    aic7xxx_queue_cmd_complete(p, cmd);
-    DRIVER_UNLOCK
-    return 0;
-  }
-  else
-  {
-    scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->hscb->tag;
-
-    /*
-     * Construct the SCB beforehand, so the sequencer is
-     * paused a minimal amount of time.
-     */
-    aic7xxx_buildscb(p, cmd, scb);
-
-    /*
-     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
-     * is set up properly, and the parity error flag is reset, then send
-     * the SCB to the sequencer and watch the fun begin.
-     */
-    cmd->scsi_done = fn;
-    cmd->result = DID_OK;
-    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-    aic7xxx_error(cmd) = DID_OK;
-    aic7xxx_status(cmd) = 0;
-    cmd->host_scribble = NULL;
-
-    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
-
-    DRIVER_LOCK
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
-    {
-      aic7xxx_run_waiting_queues(p);
-    }
-    DRIVER_UNLOCK
-  }
-  return (0);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_bus_device_reset
- *
- * Description:
- *   Abort or reset the current SCSI command(s).  If the scb has not
- *   previously been aborted, then we attempt to send a BUS_DEVICE_RESET
- *   message to the target.  If the scb has previously been unsuccessfully
- *   aborted, then we will reset the channel and have all devices renegotiate.
- *   Returns an enumerated type that indicates the status of the operation.
- *-F*************************************************************************/
-static int
-aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
-{
-  struct aic7xxx_scb   *scb;
-  struct aic7xxx_hwscb *hscb;
-  int result = -1;
-  int channel;
-  unsigned char saved_scbptr, lastphase;
-  unsigned char hscb_index;
-  int disconnected;
-
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  hscb = scb->hscb;
-
-  lastphase = aic_inb(p, LASTPHASE);
-  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-  {
-    printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
-         p->host_no, CTL_OF_SCB(scb), scb->flags);
-    switch (lastphase)
-    {
-      case P_DATAOUT:
-        printk("Data-Out phase\n");
-        break;
-      case P_DATAIN:
-        printk("Data-In phase\n");
-        break;
-      case P_COMMAND:
-        printk("Command phase\n");
-        break;
-      case P_MESGOUT:
-        printk("Message-Out phase\n");
-        break;
-      case P_STATUS:
-        printk("Status phase\n");
-        break;
-      case P_MESGIN:
-        printk("Message-In phase\n");
-        break;
-      default:
-      /*
-       * We're not in a valid phase, so assume we're idle.
-       */
-        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
-        break;
-    }
-    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
-         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
-         aic_inb(p, SCSISIGI),
-         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
-         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
-  }
-
-  channel = cmd->channel;
-
-    /*
-     * Send a Device Reset Message:
-     * The target that is holding up the bus may not be the same as
-     * the one that triggered this timeout (different commands have
-     * different timeout lengths).  Our strategy here is to queue an
-     * abort message to the timed out target if it is disconnected.
-     * Otherwise, if we have an active target we stuff the message buffer
-     * with an abort message and assert ATN in the hopes that the target
-     * will let go of the bus and go to the mesgout phase.  If this
-     * fails, we'll get another timeout a few seconds later which will
-     * attempt a bus reset.
-     */
-  saved_scbptr = aic_inb(p, SCBPTR);
-  disconnected = FALSE;
-
-  if (lastphase != P_BUSFREE)
-  {
-    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
-    {
-      printk(WARN_LEAD "Invalid SCB ID %d is active, "
-             "SCB flags = 0x%x.\n", p->host_no,
-            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
-      return(SCSI_RESET_ERROR);
-    }
-    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
-    { 
-      if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
-      {
-        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-          printk(INFO_LEAD "Device reset message in "
-                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
-        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-        aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
-                BUS_DEVICE_RESET_PENDING;
-        /* Send the abort message to the active SCB. */
-        aic_outb(p, HOST_MSG, MSG_OUT);
-        aic_outb(p, lastphase | ATNO, SCSISIGO);
-        return(SCSI_RESET_PENDING);
-      }
-      else
-      {
-        /* We want to send out the message, but it could screw an already */
-        /* in place and being used message.  Instead, we return an error  */
-        /* to try and start the bus reset phase since this command is     */
-        /* probably hung (aborts failed, and now reset is failing).  We   */
-        /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
-        /* any more on this device, but instead will escalate to a bus or */
-        /* host reset (additionally, we won't try to abort any more).     */
-        printk(WARN_LEAD "Device reset, Message buffer "
-                "in use\n", p->host_no, CTL_OF_SCB(scb));
-        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-        aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
-                BUS_DEVICE_RESET_PENDING;
-        return(SCSI_RESET_ERROR);
-      }
-    }
-  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
-  hscb_index = aic7xxx_find_scb(p, scb);
-  if (hscb_index == SCB_LIST_NULL)
-  {
-    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
-  }
-  else
-  {
-    aic_outb(p, hscb_index, SCBPTR);
-    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
-    {
-      disconnected = TRUE;
-    }
-  }
-  if (disconnected)
-  {
-        /*
-         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
-         * the rest on a reconnect.
-         */
-    scb->hscb->control |= MK_MESSAGE;
-    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
-        BUS_DEVICE_RESET_PENDING;
-    if (hscb_index != SCB_LIST_NULL)
-    {
-      unsigned char scb_control;
-
-      aic_outb(p, hscb_index, SCBPTR);
-      scb_control = aic_inb(p, SCB_CONTROL);
-      aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
-    }
-        /*
-         * Actually requeue this SCB in case we can select the
-         * device before it reconnects.  If the transaction we
-         * want to abort is not tagged, then this will be the only
-         * outstanding command and we can simply shove it on the
-         * qoutfifo and be done.  If it is tagged, then it goes right
-         * in with all the others, no problem :)  We need to add it
-         * to the qinfifo and let the sequencer know it is there.
-         * Now, the only problem left to deal with is, *IF* this
-         * command completes, in spite of the MK_MESSAGE bit in the
-         * control byte, then we need to pick that up in the interrupt
-         * routine and clean things up.  This *shouldn't* ever happen.
-         */
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Queueing device reset "
-           "command.\n", p->host_no, CTL_OF_SCB(scb));
-    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
-    if (p->features & AHC_QUEUE_REGS)
-      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
-    else
-      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-    scb->flags |= SCB_QUEUED_ABORT;
-    result = SCSI_RESET_PENDING;
-  }
-  else if (result == -1)
-  {
-    result = SCSI_RESET_ERROR;
-  }
-  aic_outb(p, saved_scbptr, SCBPTR);
-  return (result);
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_panic_abort
- *
- * Description:
- *   Abort the current SCSI command(s).
- *-F*************************************************************************/
-void
-aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
-{
-
-  printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION,
-         UTS_RELEASE);
-  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
-  printk("p->flags=0x%x, p->chip=0x%x, p->features=0x%x, "
-         "sequencer %s paused\n",
-     p->flags, p->chip, p->features,
-    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
-  pause_sequencer(p);
-  disable_irq(p->irq);
-  aic7xxx_print_card(p);
-  aic7xxx_print_scratch_ram(p);
-  spin_unlock_irq(&io_request_lock);
-  for(;;) barrier();
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_abort
- *
- * Description:
- *   Abort the current SCSI command(s).
- *-F*************************************************************************/
-int
-aic7xxx_abort(Scsi_Cmnd *cmd)
-{
-  struct aic7xxx_scb  *scb = NULL;
-  struct aic7xxx_host *p;
-  int    result, found=0;
-  unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
-  Scsi_Cmnd *cmd_next, *cmd_prev;
-
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-
-  /*
-   * I added a new config option to the driver: "panic_on_abort" that will
-   * cause the driver to panic and the machine to stop on the first abort
-   * or reset call into the driver.  At that point, it prints out a lot of
-   * usefull information for me which I can then use to try and debug the
-   * problem.  Simply enable the boot time prompt in order to activate this
-   * code.
-   */
-  if (aic7xxx_panic_on_abort)
-    aic7xxx_panic_abort(p, cmd);
-
-  DRIVER_LOCK
-
-/*
- *  Run the isr to grab any command in the QOUTFIFO and any other misc.
- *  assundry tasks.  This should also set up the bh handler if there is
- *  anything to be done, but it won't run until we are done here since
- *  we are following a straight code path without entering the scheduler
- *  code.
- */
-  pause_sequencer(p);
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
-  {
-    aic7xxx_isr(p->irq, p, (void *)NULL);
-    pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
-  }
-
-  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
-                      /*  Totally bogus cmd since it points beyond our  */
-  {                   /*  valid SCB range or doesn't even match it's own*/
-                      /*  timeout serial number.                        */
-    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
-      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
-        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
-    return(SCSI_ABORT_NOT_RUNNING);
-  }
-  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
-  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
-                        /*  has already been recycled for another command   */
-                        /*  Either way, this SCB has nothing to do with this*/
-                        /*  command and we need to deal with cmd without    */
-                        /*  touching the SCB.                               */
-                        /*  The theory here is to return a value that will  */
-                        /*  make the queued for complete command actually   */
-                        /*  finish successfully, or to indicate that we     */
-                        /*  don't have this cmd any more and the mid level  */
-                        /*  code needs to find it.                          */
-    cmd_next = p->completeq.head;
-    cmd_prev = NULL;
-    while (cmd_next != NULL) 
-    {
-      if (cmd_next == cmd) 
-      {
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "Abort called for command "
-          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        if ( cmd_prev == NULL )
-          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-        else
-          cmd_prev->host_scribble = cmd_next->host_scribble;
-        cmd_next->scsi_done(cmd_next);
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
-                                         * completion */
-      }                                  
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
-    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
-      printk(INFO_LEAD "Abort called for already completed"
-        " command.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
-    return(SCSI_ABORT_NOT_RUNNING);
-  }
-    
-/*   At this point we know the following:
- *     the SCB pointer is valid
- *     the command pointer passed in to us and the scb->cmd pointer match
- *     this then means that the command we need to abort is the same as the
- *     command held by the scb pointer and is a valid abort request.
- *   Now, we just have to figure out what to do from here.  Current plan is:
- *     if we have already been here on this command, escalate to a reset
- *     if scb is on waiting list or QINFIFO, send it back as aborted, but
- *       we also need to be aware of the possibility that we could be using
- *       a faked negotiation command that is holding this command up,  if
- *       so we need to take care of that command instead, which means we
- *       would then treat this one like it was sitting around disconnected
- *       instead.
- *     if scb is on WAITING_SCB list in sequencer, free scb and send back
- *     if scb is disconnected and not completed, abort with abort message
- *     if scb is currently running, then it may be causing the bus to hang
- *       so we want a return value that indicates a reset would be appropriate
- *       if the command does not finish shortly
- *     if scb is already complete but not on completeq, we're screwed because
- *       this can't happen (except if the command is in the QOUTFIFO, in which
- *       case we would like it to complete successfully instead of having to
- *       to be re-done)
- *   All other scenarios already dealt with by previous code.
- */
-
-  if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
-  {
-    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-      printk(INFO_LEAD "SCB aborted once already, "
-        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
-    return(SCSI_ABORT_SNOOZE);
-  }
-  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
-          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
-           BUS_DEVICE_RESET_PENDING) )
-  {
-    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-      printk(INFO_LEAD "Reset/Abort pending for this "
-        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
-    return(SCSI_ABORT_PENDING);
-  }
-
-  found = 0;
-  p->flags |= AHC_IN_ABORT;
-  if (aic7xxx_verbose & VERBOSE_ABORT)
-    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
-         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-
-/*
- *   First, let's check to see if the currently running command is our target
- *    since if it is, the return is fairly easy and quick since we don't want
- *    to touch the command in case it might complete, but we do want a timeout
- *    in case it's actually hung, so we really do nothing, but tell the mid
- *    level code to reset the timeout.
- */
-
-  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
-  {
-   /*
-    *  Check to see if the sequencer is just sitting on this command, or
-    *   if it's actively being run.
-    */
-    result = aic_inb(p, LASTPHASE);
-    switch (result)
-    {
-      case P_DATAOUT:    /*    For any of these cases, we can assume we are */
-      case P_DATAIN:     /*    an active command and act according.  For    */
-      case P_COMMAND:    /*    anything else we are going to fall on through*/
-      case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
-      case P_MESGOUT:    /*    chances to finish and then escalate to a     */
-      case P_MESGIN:     /*    reset call                                   */
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "SCB is currently active.  "
-                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
-        unpause_sequencer(p, FALSE);
-        p->flags &= ~AHC_IN_ABORT;
-        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
-        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
-        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
-        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
-        break;                          /*  out.                           */
-      default:
-        break;
-    }
-  }
-
-  if ((found == 0) && (scb->flags & SCB_WAITINGQ))
-  {
-    int tindex = TARGET_INDEX(cmd);
-    unsigned short mask;
-
-    mask = (1 << tindex);
-
-    if (p->dtr_pending & mask)
-    {
-      if (p->dev_dtr_cmnd[tindex]->next != cmd)
-        found = 1;
-      else
-        found = 0;
-    }
-    else
-    {
-      found = 1;
-    }
-    if (found == 0)
-    {
-      /*
-       * OK..this means the command we are currently getting an abort
-       * for has an outstanding negotiation command in front of it.
-       * We don't really have a way to tie back into the negotiation
-       * commands, so we just send this back as pending, then it
-       * will get reset in 2 seconds.
-       */
-      unpause_sequencer(p, TRUE);
-      scb->flags |= SCB_ABORT;
-      DRIVER_UNLOCK
-      return(SCSI_ABORT_PENDING);
-    }
-    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
-      printk(INFO_LEAD "SCB found on waiting list and "
-          "aborted.\n", p->host_no, CTL_OF_SCB(scb));
-    scbq_remove(&p->waiting_scbs, scb);
-    scbq_remove(&p->delayed_scbs[tindex], scb);
-    p->dev_active_cmds[tindex]++;
-    p->activescbs++;
-    scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
-    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
-    found = 1;
-  }
-
-/*
- *  We just checked the waiting_q, now for the QINFIFO
- */
-  if ( found == 0 )
-  {
-    if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
-                     cmd->channel,
-                     cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
-                     FALSE, NULL)) != 0) &&
-                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
-      printk(INFO_LEAD "SCB found in QINFIFO and "
-        "aborted.\n", p->host_no, CTL_OF_SCB(scb));
-  }
-
-/*
- *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
- */
-
-  if ( found == 0 )
-  {
-    unsigned char scb_next_ptr;
-    prev_hscbptr = SCB_LIST_NULL;
-    saved_hscbptr = aic_inb(p, SCBPTR);
-    next_hscbptr = aic_inb(p, WAITING_SCBH);
-    while ( next_hscbptr != SCB_LIST_NULL )
-    {
-      aic_outb(p,  next_hscbptr, SCBPTR );
-      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
-      {
-        found = 1;
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "SCB found on hardware waiting"
-            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
-        if ( prev_hscbptr == SCB_LIST_NULL )
-        {
-            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
-            /* stop the selection since we just
-             * grabbed the scb out from under the
-             * card
-             */
-            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
-            aic_outb(p, CLRSELTIMEO, CLRSINT1);
-        }
-        else
-        {
-            scb_next_ptr = aic_inb(p, SCB_NEXT);
-            aic_outb(p, prev_hscbptr, SCBPTR);
-            aic_outb(p, scb_next_ptr, SCB_NEXT);
-            aic_outb(p, next_hscbptr, SCBPTR);
-        }
-        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-        aic_outb(p, 0, SCB_CONTROL);
-        aic7xxx_add_curscb_to_free_list(p);
-        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
-        break;
-      }
-      prev_hscbptr = next_hscbptr;
-      next_hscbptr = aic_inb(p, SCB_NEXT);
-    }
-    aic_outb(p,  saved_hscbptr, SCBPTR );
-  }
-        
-/*
- *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
- *  OK...the sequencer's paused, interrupts are off, and we haven't found the
- *  command anyplace where it could be easily aborted.  Time for the hard
- *  work.  We also know the command is valid.  This essentially means the
- *  command is disconnected, or connected but not into any phases yet, which
- *  we know due to the tests we ran earlier on the current active scb phase.
- *  At this point we can queue the abort tag and go on with life.
- */
-
-  if ( found == 0 )
-  {
-    p->flags |= AHC_ABORT_PENDING;
-    scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-    scb->hscb->control |= MK_MESSAGE;
-    result=aic7xxx_find_scb(p, scb);
-    if ( result != SCB_LIST_NULL ) 
-    {
-      saved_hscbptr = aic_inb(p, SCBPTR);
-      aic_outb(p, result, SCBPTR);
-      tmp_char = aic_inb(p, SCB_CONTROL);
-      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
-      aic_outb(p, saved_hscbptr, SCBPTR);
-    }
-    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
-        " SCB.\n", p->host_no, CTL_OF_SCB(scb));
-    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
-    if (p->features & AHC_QUEUE_REGS)
-      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
-    else
-      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-  }
-  if (found)
-  {
-    aic7xxx_run_done_queue(p, TRUE);
-    aic7xxx_run_waiting_queues(p);
-  }
-  p->flags &= ~AHC_IN_ABORT;
-  unpause_sequencer(p, FALSE);
-  DRIVER_UNLOCK
-
-/*
- *  On the return value.  If we found the command and aborted it, then we know
- *  it's already sent back and there is no reason for a further timeout, so
- *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
- *  there hasn't been a bus hang or something that might keep the abort from
- *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time this
- *  is passed back, the timeout on the command gets extended, the second time
- *  we pass this back, the mid level SCSI code calls our reset function, which
- *  would shake loose a hung bus.
- */
-  if ( found != 0 )
-    return(SCSI_ABORT_SUCCESS);
-  else
-    return(SCSI_ABORT_PENDING); 
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_reset
- *
- * Description:
- *   Resetting the bus always succeeds - is has to, otherwise the
- *   kernel will panic! Try a surgical technique - sending a BUS
- *   DEVICE RESET message - on the offending target before pulling
- *   the SCSI bus reset line.
- *-F*************************************************************************/
-int
-aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
-{
-  struct aic7xxx_scb *scb = NULL;
-  struct aic7xxx_host *p;
-  int    tindex;
-  int    result = -1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
-#define DEVICE_RESET 0x01
-#define BUS_RESET    0x02
-#define HOST_RESET   0x04
-#define FAIL         0x08
-#define RESET_DELAY  0x10
-  int        action;
-  Scsi_Cmnd *cmd_prev, *cmd_next;
-
-
-  if ( cmd == NULL )
-  {
-    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
-      "pointer, failing.\n");
-    return(SCSI_RESET_SNOOZE);
-  }
-
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  tindex = TARGET_INDEX(cmd);
-
-  /*
-   * I added a new config option to the driver: "panic_on_abort" that will
-   * cause the driver to panic and the machine to stop on the first abort
-   * or reset call into the driver.  At that point, it prints out a lot of
-   * usefull information for me which I can then use to try and debug the
-   * problem.  Simply enable the boot time prompt in order to activate this
-   * code.
-   */
-  if (aic7xxx_panic_on_abort)
-    aic7xxx_panic_abort(p, cmd);
-
-  DRIVER_LOCK
-
-  pause_sequencer(p);
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
-  {
-    aic7xxx_isr(p->irq, p, (void *)NULL );
-    pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
-  }
-
-  if (scb == NULL)
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
-           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
-    {
-      action = HOST_RESET;
-    }
-    else
-    {
-      action = BUS_RESET;
-    }
-  }
-  else if (scb->cmd != cmd) 
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_MID)
-    printk(INFO_LEAD "Reset called with recycled SCB "
-        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
-    cmd_prev = NULL;
-    cmd_next = p->completeq.head;
-    while ( cmd_next != NULL )
-    {
-      if (cmd_next == cmd)
-      {
-        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-          printk(INFO_LEAD "Reset, found cmd on completeq"
-          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_RESET_NOT_RUNNING);
-      }
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
-    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "Reset, cmd not found,"
-          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_NOT_RUNNING);
-    }
-    else
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_MID)
-        printk(INFO_LEAD "Reset called, no scb, "
-          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
-      scb = NULL;
-      action = HOST_RESET;
-    }
-  }
-  else
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called, scb %d, flags "
-        "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
-    {
-      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
-          CTL_OF_SCB(scb));
-      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
-        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
-          CTL_OF_SCB(scb));
-      aic7xxx_handle_command_completion_intr(p);
-      aic7xxx_done_cmds_complete(p);
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_SUCCESS);
-    }
-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
-    {
-      action = HOST_RESET;
-    }
-    else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
-    {
-      action = BUS_RESET;
-    }
-    else 
-    {
-      action = DEVICE_RESET;
-    }
-  }
-  if ( (action & DEVICE_RESET) && 
-        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Bus device reset already sent to "
-        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = BUS_RESET;
-  }
-  if ( (action & DEVICE_RESET) &&
-       (scb->flags & SCB_QUEUED_ABORT) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-    {
-      printk(INFO_LEAD "Have already attempted to reach "
-        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
-      printk(INFO_LEAD "message, will escalate to bus "
-        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
-    }
-    action = BUS_RESET;
-  }
-  if ( (action & DEVICE_RESET) && 
-       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-     printk(INFO_LEAD "Bus device reset stupid when "
-        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = BUS_RESET;
-  }
-  if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) )
-  {
-    action = HOST_RESET;
-  }
-  if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
-       !(action & (HOST_RESET | BUS_RESET)))
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-    {
-      printk(INFO_LEAD "Reset called too soon after last "
-        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
-      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
-        CTL_OF_CMD(cmd));
-    }
-    action = BUS_RESET;
-  }
-  if ( (p->flags & AHC_RESET_DELAY) &&
-       (action & (HOST_RESET | BUS_RESET)) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Reset called too soon after "
-        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = RESET_DELAY;
-  }
-/*
- *  By this point, we want to already know what we are going to do and
- *  only have the following code implement our course of action.
- */
-  switch (action)
-  {
-    case RESET_DELAY:
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_PENDING);
-      break;
-    case FAIL:
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_ERROR);
-      break;
-    case DEVICE_RESET:
-      p->flags |= AHC_IN_RESET;
-      result = aic7xxx_bus_device_reset(p, cmd);
-      aic7xxx_run_done_queue(p, TRUE);
-      /*  We can't rely on run_waiting_queues to unpause the sequencer for
-       *  PCI based controllers since we use AAP */
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      p->flags &= ~AHC_IN_RESET;
-      DRIVER_UNLOCK
-      return(result);
-      break;
-    case BUS_RESET:
-    case HOST_RESET:
-    default:
-      p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
-      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
-      p->dev_timer_active |= (0x01 << p->scsi_id);
-      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
-            time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
-      {
-        mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]);
-        p->dev_timer_active |= (0x01 << MAX_TARGETS);
-      }
-      aic7xxx_reset_channel(p, cmd->channel, TRUE);
-      if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
-      {
-        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
-        restart_sequencer(p);
-      }
-      if (action != HOST_RESET)
-        result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
-      else
-      {
-        result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
-          SIMODE1);
-        aic7xxx_clear_intstat(p);
-        p->flags &= ~AHC_HANDLING_REQINITS;
-        p->msg_type = MSG_TYPE_NONE;
-        p->msg_index = 0;
-        p->msg_len = 0;
-      }
-      aic7xxx_run_done_queue(p, TRUE);
-      /*
-       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
-       * in need of being re-started, so send it on through to aic7xxx_queue
-       * and let it set until the delay is over.  This keeps it from dying
-       * entirely and avoids getting a bogus dead command back through the
-       * mid-level code due to too many retries.
-       */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
-      if ( flags & SCSI_RESET_SYNCHRONOUS )
-      {
-        cmd->result = DID_BUS_BUSY << 16;
-        cmd->done(cmd);
-      }
-#endif
-      p->flags &= ~AHC_IN_RESET;
-      /*
-       * We can't rely on run_waiting_queues to unpause the sequencer for
-       * PCI based controllers since we use AAP.  NOTE: this also sets
-       * the timer for the one command we might have queued in the case
-       * of a synch reset.
-       */
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(result);
-      break;
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_biosparam
- *
- * Description:
- *   Return the disk geometry for the given SCSI device.
- *-F*************************************************************************/
-int
-aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
-{
-  int heads, sectors, cylinders, ret;
-  struct aic7xxx_host *p;
-  struct buffer_head *bh;
-
-  p = (struct aic7xxx_host *) disk->device->host->hostdata;
-  bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
-
-  if ( bh )
-  {
-    ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
-    brelse(bh);
-    if ( ret != -1 )
-      return(ret);
-  }
-  
-  heads = 64;
-  sectors = 32;
-  cylinders = disk->capacity / (heads * sectors);
-
-  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
-  {
-    heads = 255;
-    sectors = 63;
-    cylinders = disk->capacity / (heads * sectors);
-  }
-
-  geom[0] = heads;
-  geom[1] = sectors;
-  geom[2] = cylinders;
-
-  return (0);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_release
- *
- * Description:
- *   Free the passed in Scsi_Host memory structures prior to unloading the
- *   module.
- *-F*************************************************************************/
-int
-aic7xxx_release(struct Scsi_Host *host)
-{
-  struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
-  struct aic7xxx_host *next, *prev;
-
-  if(p->irq)
-    free_irq(p->irq, p);
-  if(p->base)
-    release_region(p->base, MAXREG - MINREG);
-#ifdef MMAPIO
-  if(p->maddr)
-  {
-    iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK));
-  }
-#endif /* MMAPIO */
-  prev = NULL;
-  next = first_aic7xxx;
-  while(next != NULL)
-  {
-    if(next == p)
-    {
-      if(prev == NULL)
-        first_aic7xxx = next->next;
-      else
-        prev->next = next->next;
-    }
-    else
-    {
-      prev = next;
-    }
-    next = next->next;
-  }
-  aic7xxx_free(p);
-  return(0);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_print_card
- *
- * Description:
- *   Print out all of the control registers on the card
- *
- *   NOTE: This function is not yet safe for use on the VLB and EISA
- *   controllers, so it isn't used on those controllers at all.
- *-F*************************************************************************/
-static void
-aic7xxx_print_card(struct aic7xxx_host *p)
-{
-  int i, j, k, chip;
-  static struct register_ranges {
-    int num_ranges;
-    int range_val[32];
-  } cards_ds[] = {
-    { 0, {0,} }, /* none */
-    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/
-          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} },
-    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/
-          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
-    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/
-          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
-    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/
-          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
-    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/
-          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
-    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/
-          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
-          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
-          0xfe, 0xff} },
-    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/
-          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a,
-          0x9f, 0x9f, 0xe0, 0xf1} },
-    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/
-          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
-          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
-          0xfe, 0xff} },
-    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
-          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
-          0xe0, 0xf1, 0xf4, 0xfc} },
-    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
-          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
-          0xe0, 0xf1, 0xf4, 0xfc} },
-  };
-  chip = p->chip & AHC_CHIPID_MASK;
-  printk("%s at ",
-         board_names[p->board_name_index]);
-  switch(p->chip & ~AHC_CHIPID_MASK)
-  {
-    case AHC_VL:
-      printk("VLB Slot %d.\n", p->pci_device_fn);
-      break;
-    case AHC_EISA:
-      printk("EISA Slot %d.\n", p->pci_device_fn);
-      break;
-    case AHC_PCI:
-    default:
-      printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
-             PCI_FUNC(p->pci_device_fn));
-      break;
-  }
-
-  /*
-   * the registers on the card....
-   */
-  printk("Card Dump:\n");
-  k = 0;
-  for(i=0; i<cards_ds[chip].num_ranges; i++)
-  {
-    for(j  = cards_ds[chip].range_val[ i * 2 ];
-        j <= cards_ds[chip].range_val[ i * 2 + 1 ] ;
-        j++)
-    {
-      printk("%02x:%02x ", j, aic_inb(p, j));
-      if(++k == 13)
-      {
-        printk("\n");
-        k=0;
-      }
-    }
-  }
-  if(k != 0)
-    printk("\n");
-
-  /*
-   * If this was an Ultra2 controller, then we just hosed the card in terms
-   * of the QUEUE REGS.  This function is only called at init time or by
-   * the panic_abort function, so it's safe to assume a generic init time
-   * setting here
-   */
-
-  if(p->features & AHC_QUEUE_REGS)
-  {
-    aic_outb(p, 0, SDSCB_QOFF);
-    aic_outb(p, 0, SNSCB_QOFF);
-    aic_outb(p, 0, HNSCB_QOFF);
-  }
-
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_print_scratch_ram
- *
- * Description:
- *   Print out the scratch RAM values on the card.
- *-F*************************************************************************/
-static void
-aic7xxx_print_scratch_ram(struct aic7xxx_host *p)
-{
-  int i, k;
-
-  k = 0;
-  printk("Scratch RAM:\n");
-  for(i = SRAM_BASE; i < SEQCTL; i++)
-  {
-    printk("%02x:%02x ", i, aic_inb(p, i));
-    if(++k == 13)
-    {
-      printk("\n");
-      k=0;
-    }
-  }
-  if (p->features & AHC_MORE_SRAM)
-  {
-    for(i = TARG_OFFSET; i < 0x80; i++)
-    {
-      printk("%02x:%02x ", i, aic_inb(p, i));
-      if(++k == 13)
-      {
-        printk("\n");
-        k=0;
-      }
-    }
-  }
-  printk("\n");
-}
-
-
-#include "aic7xxx_proc.c"
-
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = AIC7XXX;
-
-#include "scsi_module.c"
-
-/*
- * Overrides for Emacs so that we almost follow Linus's 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: 2
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -2
- * c-argdecl-indent: 2
- * c-label-offset: -2
- * c-continued-statement-offset: 2
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h
--- v2.4.2/linux/drivers/scsi/aic7xxx.h	Wed Jun 21 17:25:03 2000
+++ linux/drivers/scsi/aic7xxx.h	Wed Dec 31 16:00:00 1969
@@ -1,73 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux.
- *
- * Copyright (c) 1994 John Aycock
- *   The University of Calgary Department of Computer Science.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * 
- * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
- *-M*************************************************************************/
-#ifndef _aic7xxx_h
-#define _aic7xxx_h
-
-#define AIC7XXX_H_VERSION  "5.2.0"
-
-/*
- * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
- * to do with card config are filled in after the card is detected.
- */
-#define AIC7XXX	{						\
-	next: NULL,						\
-	module: NULL,						\
-	proc_info: aic7xxx_proc_info,				\
-	name: NULL,						\
-	detect: aic7xxx_detect,					\
-	release: aic7xxx_release,				\
-	info: aic7xxx_info,					\
-	command: NULL,						\
-	queuecommand: aic7xxx_queue,				\
-	eh_strategy_handler: NULL,				\
-	eh_abort_handler: NULL,					\
-	eh_device_reset_handler: NULL,				\
-	eh_bus_reset_handler: NULL,				\
-	eh_host_reset_handler: NULL,				\
-	abort: aic7xxx_abort,					\
-	reset: aic7xxx_reset,					\
-	slave_attach: NULL,					\
-	bios_param: aic7xxx_biosparam,				\
-	can_queue: 255,		/* max simultaneous cmds      */\
-	this_id: -1,		/* scsi id of host adapter    */\
-	sg_tablesize: 0,	/* max scatter-gather cmds    */\
-	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
-	present: 0,		/* number of 7xxx's present   */\
-	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
-	use_clustering: ENABLE_CLUSTERING,			\
-	use_new_eh_code: 0					\
-}
-
-extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
-extern int aic7xxx_detect(Scsi_Host_Template *);
-extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
-extern int aic7xxx_abort(Scsi_Cmnd *);
-extern int aic7xxx_release(struct Scsi_Host *);
-
-extern const char *aic7xxx_info(struct Scsi_Host *);
-
-extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
-
-#endif /* _aic7xxx_h */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/README.aic7xxx linux/drivers/scsi/aic7xxx_old/README.aic7xxx
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/README.aic7xxx	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/README.aic7xxx	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,511 @@
+			    AIC7xxx Driver for Linux
+
+Introduction
+----------------------------
+The AIC7xxx SCSI driver adds support for Adaptec (http://www.adaptec.com)
+SCSI controllers and chipsets. Major portions of the driver and driver
+development are shared between both Linux and FreeBSD. Support for the
+AIC-7xxx chipsets have been in the default Linux kernel since approximately
+linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
+2.1.0 or later.
+
+  Supported cards/chipsets
+  ----------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-274x
+    AHA-274xT               
+    AHA-2842
+    AHA-2910B               
+    AHA-2920C
+    AHA-2930
+    AHA-2930U
+    AHA-2930CU
+    AHA-2930U2
+    AHA-2940               
+    AHA-2940W              
+    AHA-2940U              
+    AHA-2940UW
+    AHA-2940UW-PRO
+    AHA-2940AU 
+    AHA-2940U2W
+    AHA-2940U2
+    AHA-2940U2B
+    AHA-2940U2BOEM
+    AHA-2944D              
+    AHA-2944WD
+    AHA-2944UD
+    AHA-2944UWD
+    AHA-2950U2
+    AHA-2950U2W
+    AHA-2950U2B
+    AHA-29160M
+    AHA-3940
+    AHA-3940U
+    AHA-3940W
+    AHA-3940UW
+    AHA-3940AUW
+    AHA-3940U2W
+    AHA-3950U2B
+    AHA-3950U2D
+    AHA-3960D
+    AHA-39160M
+    AHA-3985
+    AHA-3985U
+    AHA-3985W
+    AHA-3985UW
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-777x   
+    AIC-785x
+    AIC-786x
+    AIC-787x
+    AIC-788x
+    AIC-789x
+    AIC-3860
+
+    Bus Types
+    ----------------------------
+    W - Wide SCSI, SCSI-3, 16bit bus, 68pin connector, will also support
+        SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
+    U - Ultra SCSI, transfer rates up to 40MB/s.
+    U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
+    D - Differential SCSI.
+    T - Twin Channel SCSI. Up to 14 SCSI devices.
+
+    AHA-274x - EISA SCSI controller
+    AHA-284x - VLB SCSI controller
+    AHA-29xx - PCI SCSI controller
+    AHA-394x - PCI controllers with two separate SCSI controllers on-board.
+    AHA-398x - PCI RAID controllers with three separate SCSI controllers
+               on-board.
+
+  Not Supported Devices
+  ------------------------------
+    Adaptec Cards
+    ----------------------------
+    AHA-2920 (Only the cards that use the Future Domain chipset are not
+              supported, any 2920 cards based on Adaptec AIC chipsets,
+	      such as the 2920C, are supported)
+    AAA-13x Raid Adapters
+    AAA-113x Raid Port Card
+
+    Motherboard Chipsets
+    ----------------------------
+    AIC-7810
+
+    Bus Types
+    ----------------------------
+    R - Raid Port busses are not supported.
+
+    The hardware RAID devices sold by Adaptec are *NOT* supported by this
+    driver (and will people please stop emailing me about them, they are
+    a totally separate beast from the bare SCSI controllers and this driver
+    can not be retrofitted in any sane manner to support the hardware RAID
+    features on those cards - Doug Ledford).
+    
+
+  People
+  ------------------------------
+    Justin T Gibbs  gibbs@plutotech.com
+      (BSD Driver Author)
+    Dan Eischen     deischen@iworks.InterWorks.org
+      (Original Linux Driver Co-maintainer)
+    Dean Gehnert    deang@teleport.com
+      (Original Linux FTP/patch maintainer)
+    Jess Johnson    jester@frenzy.com
+      (AIC7xxx FAQ author)
+    Doug Ledford    dledford@redhat.com
+      (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
+    
+    Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
+    author of the driver. John has since retired from the project. Thanks
+    again for all his work!
+    
+  Mailing list
+  ------------------------------
+    There is a mailing list available for users who want to track development
+    and converse with other users and developers. This list is for both
+    FreeBSD and Linux support of the AIC7xxx chipsets.
+
+    To subscribe to the AIC7xxx mailing list send mail to the list server,
+    with "subscribe AIC7xxx" in the body (no Subject: required):
+        To: majordomo@FreeBSD.ORG
+        ---
+        subscribe AIC7xxx
+
+    To unsubscribe from the list, send mail to the list server with:
+        To: majordomo@FreeBSD.ORG
+        ---
+        unsubscribe AIC7xxx
+
+    Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
+    
+  Boot Command line options
+  ------------------------------
+    "aic7xxx=no_reset" -  Eliminate the SCSI bus reset during startup.
+        Some SCSI devices need the initial reset that this option disables
+	in order to work.  If you have problems at bootup, please make sure
+	you aren't using this option.
+	
+    "aic7xxx=reverse_scan" - Certain PCI motherboards scan for devices at
+        bootup by scanning from the highest numbered PCI device to the
+	lowest numbered PCI device, others do just the opposite and scan
+	from lowest to highest numbered PCI device.  There is no reliable
+	way to autodetect this ordering.  So, we default to the most common
+	order, which is lowest to highest.  Then, in case your motherboard
+	scans from highest to lowest, we have this option.  If your BIOS
+	finds the drives on controller A before controller B but the linux
+	kernel finds your drives on controller B before A, then you should
+	use this option.
+	
+    "aic7xxx=extended" - Force the driver to detect extended drive translation
+        on your controller.  This helps those people who have cards without
+        a SEEPROM make sure that linux and all other operating systems think
+        the same way about your hard drives.
+
+    "aic7xxx=scbram" - Some cards have external SCB RAM that can be used to
+        give the card more hardware SCB slots.  This allows the driver to use
+	that SCB RAM.  Without this option, the driver won't touch the SCB
+	RAM because it is known to cause problems on a few cards out there
+	(such as 3985 class cards).
+	
+    "aic7xxx=irq_trigger:x" - Replace x with either 0 or 1 to force the kernel
+        to use the correct IRQ type for your card.  This only applies to EISA
+        based controllers.  On these controllers, 0 is for Edge triggered
+        interrupts, and 1 is for Level triggered interrupts.  If you aren't
+        sure or don't know which IRQ trigger type your EISA card uses, then
+        let the kernel autodetect the trigger type.
+	
+    "aic7xxx=verbose" - This option can be used in one of two ways.  If you
+        simply specify aic7xxx=verbose, then the kernel will automatically
+	pick the default set of verbose messages for you to see.
+	Alternatively, you can specify the command as 
+	"aic7xxx=verbose:0xXXXX" where the X entries are replaced with
+	hexadecimal digits.  This option is a bit field type option.  For
+	a full listing of the available options, search for the 
+	#define VERBOSE_xxxxxx lines in the aic7xxx.c file.  If you want
+	verbose messages, then it is recommended that you simply use the
+	aic7xxx=verbose variant of this command.
+	
+    "aic7xxx=pci_parity:x" - This option controls whether or not the driver
+        enables PCI parity error checking on the PCI bus.  By default, this
+        checking is disabled.  To enable the checks, simply specify pci_parity
+        with no value afterwords.  To reverse the parity from even to odd,
+        supply any number other than 0 or 255.  In short:
+          pci_parity     - Even parity checking (even is the normal PCI parity)
+          pci_parity:x   - Where x > 0, Odd parity checking
+          pci_parity:0   - No check (default)
+        NOTE: In order to get Even PCI parity checking, you must use the
+        version of the option that does not include the : and a number at
+        the end (unless you want to enter exactly 2^32 - 1 as the number).
+	
+    "aic7xxx=no_probe" - This option will disable the probing for any VLB
+        based 2842 controllers and any EISA based controllers.  This is
+	needed on certain newer motherboards where the normal EISA I/O ranges
+	have been claimed by other PCI devices.  Probing on those machines
+	will often result in the machine crashing or spontaneously rebooting
+	during startup.  Examples of machines that need this are the
+	Dell PowerEdge 6300 machines.
+
+    "aic7xxx=seltime:2" - This option controls how long the card waits
+        during a device selection sequence for the device to respond.
+	The original SCSI spec says that this "should be" 256ms.  This
+	is generally not required with modern devices.  However, some
+	very old SCSI I devices need the full 256ms.  Most modern devices
+	can run fine with only 64ms.  The default for this option is
+	64ms.  If you need to change this option, then use the following
+	table to set the proper value in the example above:
+	  0  -  256ms
+	  1  -  128ms
+	  2  -   64ms
+	  3  -   32ms
+	
+    "aic7xxx=panic_on_abort" - This option is for debugging and will cause
+        the driver to panic the linux kernel and freeze the system the first
+	time the drivers abort or reset routines are called.  This is most
+	helpful when some problem causes infinite reset loops that scroll too
+	fast to see.  By using this option, you can write down what the errors
+	actually are and send that information to me so it can be fixed.
+	
+    "aic7xxx=dump_card" - This option will print out the *entire* set of
+        configuration registers on the card during the init sequence.  This
+	is a debugging aid used to see exactly what state the card is in
+	when we finally finish our initialization routines.  If you don't
+	have documentation on the chipsets, this will do you absolutely
+	no good unless you are simply trying to write all the information
+	down in order to send it to me.
+	
+    "aic7xxx=dump_sequencer" - This is the same as the above options except
+        that instead of dumping the register contents on the card, this
+	option dumps the contents of the sequencer program RAM.  This gives
+	the ability to verify that the instructions downloaded to the
+	card's sequencer are indeed what they are suppossed to be.  Again,
+	unless you have documentation to tell you how to interpret these
+	numbers, then it is totally useless.
+	
+    "aic7xxx=override_term:0xffffffff" - This option is used to force the
+    	termination on your SCSI controllers to a particular setting.  This
+	is a bit mask variable that applies for up to 8 aic7xxx SCSI channels.
+	Each channel gets 4 bits, divided as follows:
+	bit   3   2   1   0
+	      |   |   |   Enable/Disable Single Ended Low Byte Termination
+	      |   |   En/Disable Single Ended High Byte Termination
+	      |   En/Disable Low Byte LVD Termination
+	      En/Disable High Byte LVD Termination
+
+	The upper 2 bits that deal with LVD termination only apply to Ultra2
+	controllers.  Futhermore, due to the current Ultra2 controller
+	designs, these bits are tied together such that setting either bit
+	enables both low and high byte LVD termination.  It is not possible
+	to only set high or low byte LVD termination in this manner.  This is
+	an artifact of the BIOS definition on Ultra2 controllers.  For other
+	controllers, the only important bits are the two lowest bits.  Setting
+	the higher bits on non-Ultra2 controllers has no effect.  A few
+	examples of how to use this option:
+
+	Enable low and high byte termination on a non-ultra2 controller that
+	is the first aic7xxx controller (the correct bits are 0011), 
+	aic7xxx=override_term:0x3
+
+	Enable all termination on the third aic7xxx controller, high byte
+	termination on the second aic7xxx controller, and low and high byte
+	SE termination on the first aic7xxx controller 
+	(bits are 1111 0010 0011), 
+	aic7xxx=override_term:0xf23
+	
+	No attempt has been made to make this option non-cryptic.  It really
+	shouldn't be used except in dire circumstances, and if that happens,
+	I'm probably going to be telling you what to set this to anyway :)
+
+    "aic7xxx=stpwlev:0xffffffff" - This option is used to control the STPWLEV
+        bit in the DEVCONFIG PCI register.  Currently, this is one of the
+	very few registers that we have absolutely *no* way of detecting
+	what the variable should be.  It depends entirely on how the chipset
+	and external terminators were coupled by the card/motherboard maker.
+	Further, a chip reset (at power up) always sets this bit to 0.  If
+	there is no BIOS to run on the chipset/card (such as with a 2910C
+	or a motherboard controller with the BIOS totally disabled) then
+	the variable may not get set properly.  Of course, if the proper
+	setting was 0, then that's what it would be after the reset, but if
+	the proper setting is actually 1.....you get the picture.  Now, since
+	we can't detect this at all, I've added this option to force the
+	setting.  If you have a BIOS on your controller then you should never
+	need to use this option.  However, if you are having lots of SCSI
+	reset problems and can't seem to get them knocked out, this may help.
+
+	Here's a test to know for certain if you need this option.  Make
+	a boot floppy that you can use to boot your computer up and that
+	will detect the aic7xxx controller.  Next, power down your computer.
+	While it's down, unplug all SCSI cables from your Adaptec SCSI
+	controller.  Boot the system back up to the Adaptec EZ-SCSI BIOS
+	and then make sure that termination is enabled on your adapter (if
+	you have an Adaptec BIOS of course).  Next, boot up the floppy you
+	made and wait for it to detect the aic7xxx controller.  If the kernel
+	finds the controller fine, says scsi : x hosts and then tries to
+	detect your devices like normal, up to the point where it fails to
+	mount your root file system and panics, then you're fine.  If, on
+	the other hand, the system goes into an infinite reset loop, then
+	you need to use this option and/or the previous option to force the
+	proper termination settings on your controller.   If this happens,
+	then you next need to figure out what your settings should be.
+
+	To find the correct settings, power your machine back down, connect
+	back up the SCSI cables, and boot back into your machine like normal.
+	However, boot with the aic7xxx=verbose:0x39 option.  Record the
+	initial DEVCONFIG values for each of your aic7xxx controllers as
+	they are listed, and also record what the machine is detecting as
+	the proper termination on your controllers.  NOTE: the order in
+	which the initial DEVCONFIG values are printed out is not gauranteed
+	to be the same order as the SCSI controllers are registered.  The
+	above option and this option both work on the order of the SCSI
+	controllers as they are registered, so make sure you match the right
+	DEVCONFIG values with the right controllers if you have more than
+	one aic7xxx controller.
+
+	Once you have the detected termination settings and the initial
+	DEVCONFIG values for each controller, then figure out what the
+	termination on each of the controllers *should* be.  Hopefully, that
+	part is correct, but it could possibly be wrong if there is
+	bogus cable detection logic on your controller or something similar.
+	If all the controllers have the correct termination settings, then
+	don't set the aic7xxx=override_term variable at all, leave it alone.
+	Next, on any controllers that go into an infinite reset loop when
+	you unplug all the SCSI cables, get the starting DEVCONFIG value.
+	If the initial DEVCONFIG value is divisible by 2, then the correct
+	setting for that controller is 0.  If it's an odd number, then
+	the correct setting for that controller is 1.  For any other
+	controllers that didn't have an infinite reset problem, then reverse
+	the above options.  If DEVCONFIG was even, then the correct setting
+	is 1, if not then the correct setting is 0.
+
+	Now that you know what the correct setting was for each controller,
+	we need to encode that into the aic7xxx=stpwlev:0x... variable.
+	This variable is a bit field encoded variable.  Bit 0 is for the first
+	aic7xxx controller, bit 1 for the next, etc.  Put all these bits
+	together and you get a number.  For example, if the third aic7xxx
+	needed a 1, but the second and first both needed a 0, then the bits
+	would be 100 in binary.  This then translates to 0x04.  You would
+	therefore set aic7xxx=stpwlev:0x04.  This is fairly standard binary
+	to hexadecimal conversions here.  If you aren't up to speed on the
+	binary->hex conversion then send an email to the aic7xxx mailing
+	list and someone can help you out.
+
+    "aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
+        or enable Tagged Command Queueing (TCQ) on specific devices.  As of
+	driver version 5.1.11, TCQ is now either on or off by default
+	according to the setting you choose during the make config process.
+	In order to en/disable TCQ for certian devices at boot time, a user
+	may use this boot param.  The driver will then parse this message out
+        and en/disable the specific device entries that are present based upon
+        the value given.  The param line is parsed in the following manner:
+
+          { - first instance indicates the start of this parameter values
+              second instance is the start of entries for a particular
+              device entry
+          } - end the entries for a particular host adapter, or end the entire
+              set of parameter entries
+          , - move to next entry.  Inside of a set of device entries, this
+              moves us to the next device on the list.  Outside of device
+              entries, this moves us to the next host adapter
+          . - Same effect as , but is safe to use with insmod.
+          x - the number to enter into the array at this position.  
+              0 = Enable tagged queueing on this device and use the default
+                  queue depth
+              1-254 = Enable tagged queueing on this device and use this
+                      number as the queue depth
+              255 = Disable tagged queueing on this device.
+              Note: anything above 32 for an actual queue depth is wasteful
+                    and not recommended.
+
+        A few examples of how this can be used:
+
+        tag_info:{{8,12,,0,,255,4}}
+          This line will only effect the first aic7xxx card registered.  It
+          will set scsi id 0 to a queue depth of 8, id 1 to 12, leave id 2
+          at the default, set id 3 to tagged queueing enabled and use the
+          default queue depth, id 4 default, id 5 disabled, and id 6 to 4.
+          Any not specified entries stay at the default value, repeated
+          commas with no value specified will simply increment to the next id
+          without changing anything for the missing values.
+
+        tag_info:{,,,{,,,255}}
+          First, second, and third adapters at default values.  Fourth
+          adapter, id 3 is disabled.  Notice that leading commas simply
+	  increment what the first number effects, and there are no need
+	  for trailing commas.  When you close out an adapter, or the
+	  entire entry, anything not explicitly set stays at the default
+	  value.
+
+        A final note on this option.  The scanner I used for this isn't
+        perfect or highly robust.  If you mess the line up, the worst that
+        should happen is that the line will get ignored.  If you don't
+        close out the entire entry with the final bracket, then any other
+        aic7xxx options after this will get ignored.  So, in general, be
+        sure of what you are entering, and after you have it right, just
+        add it to the lilo.conf file so there won't be any mistakes.  As
+        a means of checking this parser, the entire tag_info array for
+        each card is now printed out in the /proc/scsi/aic7xxx/x file.  You
+        can use that to verify that your options were parsed correctly. 
+        
+    Boot command line options may be combined to form the proper set of options
+    a user might need.  For example, the following is valid:
+    
+    aic7xxx=verbose,extended,irq_trigger:1
+    
+    The only requirement is that individual options be separated by a comma or
+    a period on the command line.
+        
+  Module Loading command options
+  ------------------------------
+    When loading the aic7xxx driver as a module, the exact same options are
+    available to the user.  However, the syntax to specify the options changes
+    slightly.  For insmod, you need to wrap the aic7xxx= argument in quotes
+    and replace all ',' with '.'.  So, for example, a valid insmod line
+    would be:
+
+    insmod aic7xxx aic7xxx='verbose.irq_trigger:1.extended'
+
+    This line should result in the *exact* same behaviour as if you typed
+    it in at the lilo prompt and the driver was compiled into the kernel
+    instead of being a module.  The reason for the single quote is so that
+    the shell won't try to interpret anything in the line, such as {. 
+    Insmod assumes any options starting with a letter instead of a number
+    is a character string (which is what we want) and by switching all of
+    the commas to periods, insmod won't interpret this as more than one
+    string and write junk into our binary image.  I consider it a bug in
+    the insmod program that even if you wrap your string in quotes (quotes
+    that pass the shell mind you and that insmod sees) it still treates
+    a comma inside of those quotes as starting a new variable, resulting
+    in memory scribbles if you don't switch the commas to periods.
+
+
+  Kernel Compile options
+  ------------------------------
+    The various kernel compile time options for this driver are now fairly
+    well documented in the file Documentation/Configure.help.  In order to
+    see this documentation, you need to use one of the advanced configuration
+    programs (menuconfig and xconfig).  If you are using the "make menuconfig"
+    method of configuring your kernel, then you would simply highlight the
+    option in question and hit the ? key.  If you are using the "make xconfig"
+    method of configuring your kernel, then simply click on the help button
+    next to the option you have questions about.  The help information from
+    the Configure.help file will then get automatically displayed.
+
+  /proc support
+  ------------------------------
+    The /proc support for the AIC7xxx can be found in the /proc/scsi/aic7xxx/
+    directory. That directory contains a file for each SCSI controller in
+    the system. Each file presents the current configuration and transfer
+    statistics (enabled with #define in aic7xxx.c) for each controller.
+
+    Thanks to Michael Neuffer for his upper-level SCSI help, and
+    Matthew Jacob for statistics support.
+
+  Debugging the driver
+  ------------------------------
+    Should you have problems with this driver, and would like some help in
+    getting them solved, there are a couple debugging items built into
+    the driver to facilitate getting the needed information from the system.
+    In general, I need a complete description of the problem, with as many
+    logs as possible concerning what happens.  To help with this, there is
+    a command option aic7xxx=panic_on_abort.  This option, when set, forces
+    the driver to panic the kernel on the first SCSI abort issued by the
+    mid level SCSI code.  If your system is going to reset loops and you
+    can't read the screen, then this is what you need.  Not only will it
+    stop the system, but it also prints out a large amount of state
+    information in the process.  Second, if you specify the option
+    "aic7xxx=verbose:0x1ffff", the system will print out *SOOOO* much
+    information as it runs that you won't be able to see anything.
+    However, this can actually be very usefull if your machine simply
+    locks up when trying to boot, since it will pin-point what was last
+    happening (in regards to the aic7xxx driver) immediately prior to
+    the lockup.  This is really only usefull if your machine simply can
+    not boot up successfully.  If you can get your machine to run, then
+    this will produce far too much information.
+
+  FTP sites
+  ------------------------------
+    ftp://ftp.redhat.com/pub/aic/
+      - Out of date.  I used to keep stuff here, but too many people
+        complained about having a hard time getting into Red Hat's ftp
+	server.  So use the web site below instead.
+    ftp://ftp.pcnet.com/users/eischen/Linux/
+      - Dan Eischen's driver distribution area
+    ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
+      - European Linux mirror of Teleport site
+
+  Web sites
+  ------------------------------
+    http://people.redhat.com/dledford/
+      - My web site, also the primary aic7xxx site with several related
+        pages.
+
+Dean W. Gehnert
+deang@teleport.com
+
+$Revision: 3.0 $
+
+Modified by Doug Ledford 1998-2000
+
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.h linux/drivers/scsi/aic7xxx_old/aic7xxx.h
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.h	Sun Mar  4 14:30:18 2001
@@ -0,0 +1,73 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
+ *-M*************************************************************************/
+#ifndef _aic7xxx_h
+#define _aic7xxx_h
+
+#define AIC7XXX_H_VERSION  "5.2.0"
+
+/*
+ * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
+ * to do with card config are filled in after the card is detected.
+ */
+#define AIC7XXX	{						\
+	next: NULL,						\
+	module: NULL,						\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: aic7xxx_release,				\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	eh_strategy_handler: NULL,				\
+	eh_abort_handler: NULL,					\
+	eh_device_reset_handler: NULL,				\
+	eh_bus_reset_handler: NULL,				\
+	eh_host_reset_handler: NULL,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: aic7xxx_biosparam,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING,			\
+	use_new_eh_code: 0					\
+}
+
+extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
+extern int aic7xxx_detect(Scsi_Host_Template *);
+extern int aic7xxx_command(Scsi_Cmnd *);
+extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
+extern int aic7xxx_abort(Scsi_Cmnd *);
+extern int aic7xxx_release(struct Scsi_Host *);
+
+extern const char *aic7xxx_info(struct Scsi_Host *);
+
+extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
+
+#endif /* _aic7xxx_h */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg linux/drivers/scsi/aic7xxx_old/aic7xxx.reg
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.reg	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.reg	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,1396 @@
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-1998 Justin Gibbs.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ *	$Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
+ */
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+	address			0x000
+	access_mode RW
+	bit	TEMODE		0x80
+	bit	ENSELO		0x40
+	bit	ENSELI		0x20
+	bit	ENRSELI		0x10
+	bit	ENAUTOATNO	0x08
+	bit	ENAUTOATNI	0x04
+	bit	ENAUTOATNP	0x02
+	bit	SCSIRSTO	0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+	address			0x001
+	access_mode RW
+	bit	DFON		0x80
+	bit	DFPEXP		0x40
+	bit	FAST20		0x20
+	bit	CLRSTCNT	0x10
+	bit	SPIOEN		0x08
+	bit	SCAMEN		0x04
+	bit	CLRCHN		0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+	address			0x002
+	access_mode RW
+	bit	BITBUCKET	0x80
+	bit	SWRAPEN		0x40
+	bit	ENSPCHK		0x20
+	mask	STIMESEL	0x18
+	bit	ENSTIMER	0x04
+	bit	ACTNEGEN	0x02
+	bit	STPWEN		0x01	/* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+	address			0x003
+	access_mode RO
+	bit	CDI		0x80
+	bit	IOI		0x40
+	bit	MSGI		0x20
+	bit	ATNI		0x10
+	bit	SELI		0x08
+	bit	BSYI		0x04
+	bit	REQI		0x02
+	bit	ACKI		0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+	address			0x003
+	access_mode WO
+	bit	CDO		0x80
+	bit	IOO		0x40
+	bit	MSGO		0x20
+	bit	ATNO		0x10
+	bit	SELO		0x08
+	bit	BSYO		0x04
+	bit	REQO		0x02
+	bit	ACKO		0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+	address			0x004
+	access_mode RW
+	bit	WIDEXFER	0x80		/* Wide transfer control */
+	mask	SXFR		0x70		/* Sync transfer rate */
+	mask	SXFR_ULTRA2	0x7f		/* Sync transfer rate */
+	mask	SOFS		0x0f		/* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID	{
+	address			0x005
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	OID		0x0f		/* Our ID mask */
+	/*
+	 * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
+	 * The aic7890/91 allow an offset of up to 127 transfers in both wide
+	 * and narrow mode.
+	 */
+	alias	SCSIOFFSET
+	mask	SOFS_ULTRA2	0x7f		/* Sync offset U2 chips */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+	address			0x006
+	access_mode RW
+}
+
+register SCSIDATH {
+	address			0x007
+	access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transferred.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+register STCNT {
+	address			0x008
+	size	3
+	access_mode RW
+}
+
+/*
+ * Option Mode Register (Alternate Mode) (p. 5-198)
+ * This register is used to set certain options on Ultra3 based chips.
+ * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set)
+ */
+register OPTIONMODE {
+	address			0x008
+	access_mode RW
+	bit	AUTORATEEN	0x80
+	bit	AUTOACKEN	0x40
+	bit	ATNMGMNTEN	0x20
+	bit	BUSFREEREV	0x10
+	bit	EXPPHASEDIS	0x08
+	bit	SCSIDATL_IMGEN	0x04
+	bit	AUTO_MSGOUT_DE	0x02
+	bit	DIS_MSGIN_DUALEDGE	0x01
+}
+
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+	address			0x00b
+	access_mode WO
+	bit	CLRSELDO	0x40
+	bit	CLRSELDI	0x20
+	bit	CLRSELINGO	0x10
+	bit	CLRSWRAP	0x08
+	bit	CLRSPIORDY	0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+register SSTAT0	{
+	address			0x00b
+	access_mode RO
+	bit	TARGET		0x80	/* Board acting as target */
+	bit	SELDO		0x40	/* Selection Done */
+	bit	SELDI		0x20	/* Board has been selected */
+	bit	SELINGO		0x10	/* Selection In Progress */
+	bit	SWRAP		0x08	/* 24bit counter wrap */
+	bit	IOERR		0x08	/* LVD Tranceiver mode changed */
+	bit	SDONE		0x04	/* STCNT = 0x000000 */
+	bit	SPIORDY		0x02	/* SCSI PIO Ready */
+	bit	DMADONE		0x01	/* DMA transfer completed */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+	address			0x00c
+	access_mode WO
+	bit	CLRSELTIMEO	0x80
+	bit	CLRATNO		0x40
+	bit	CLRSCSIRSTI	0x20
+	bit	CLRBUSFREE	0x08
+	bit	CLRSCSIPERR	0x04
+	bit	CLRPHASECHG	0x02
+	bit	CLRREQINIT	0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1	{
+	address			0x00c
+	access_mode RO
+	bit	SELTO		0x80
+	bit	ATNTARG 	0x40
+	bit	SCSIRSTI	0x20
+	bit	PHASEMIS	0x10
+	bit	BUSFREE		0x08
+	bit	SCSIPERR	0x04
+	bit	PHASECHG	0x02
+	bit	REQINIT		0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+	address			0x00d
+	access_mode RO
+	bit	OVERRUN		0x80
+	bit	SHVALID		0x40
+	bit	WIDE_RES	0x20
+	bit	EXP_ACTIVE	0x10	/* SCSI Expander Active */
+	bit	CRCVALERR	0x08	/* CRC Value Error */
+	bit	CRCENDERR	0x04	/* CRC End Error */
+	bit	CRCREQERR	0x02	/* CRC REQ Error */
+	bit	DUAL_EDGE_ERROR	0x01	/* Invalid pins for Dual Edge phase */
+	mask	SFCNT		0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+	address			0x00e
+	access_mode RO
+	mask	SCSICNT		0xf0
+	mask	OFFCNT		0x0f
+}
+
+/*
+ * SCSI ID for the aic7890/91 chips
+ */
+register SCSIID_ULTRA2 {
+	address			0x00f
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	OID		0x0f		/* Our ID mask */
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+	address			0x010
+	access_mode RW
+	bit	ENSELDO		0x40
+	bit	ENSELDI		0x20
+	bit	ENSELINGO	0x10
+	bit	ENSWRAP		0x08
+	bit	ENIOERR		0x08	/* LVD Tranceiver mode changes */
+	bit	ENSDONE		0x04
+	bit	ENSPIORDY	0x02
+	bit	ENDMADONE	0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+	address			0x011
+	access_mode RW
+	bit	ENSELTIMO	0x80
+	bit	ENATNTARG	0x40
+	bit	ENSCSIRST	0x20
+	bit	ENPHASEMIS	0x10
+	bit	ENBUSFREE	0x08
+	bit	ENSCSIPERR	0x04
+	bit	ENPHASECHG	0x02
+	bit	ENREQINIT	0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+	address			0x012
+	access_mode RO
+}
+
+register SCSIBUSH {
+	address			0x013
+	access_mode RO
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+	address			0x014
+	size	4
+	access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+	address			0x018
+	access_mode RW
+	bit	STAGE6		0x20
+	bit	STAGE5		0x10
+	bit	STAGE4		0x08
+	bit	STAGE3		0x04
+	bit	STAGE2		0x02
+	bit	STAGE1		0x01
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+	address			0x019
+	access_mode RW
+	mask	SELID_MASK	0xf0
+	bit	ONEBIT		0x08
+}
+
+/*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+	address			0x01b
+	access_mode RW
+	bit	SOFT1		0x80
+	bit	SOFT0		0x40
+	bit	SOFTCMDEN	0x20	
+	bit	HAS_BRDCTL	0x10	/* External Board control */
+	bit	SEEPROM		0x08	/* External serial eeprom logic */
+	bit	EEPROM		0x04	/* Writable external BIOS ROM */
+	bit	ROM		0x02	/* Logic for accessing external ROM */
+	bit	SSPIOCPS	0x01	/* Termination and cable detection */
+}
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection.  In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+	address			0x01f
+	access_mode RW
+	bit	DIAGLEDEN	0x80	/* Aic78X0 only */
+	bit	DIAGLEDON	0x40	/* Aic78X0 only */
+	bit	AUTOFLUSHDIS	0x20
+	bit	SELBUSB		0x08
+	bit	ENAB40		0x08	/* LVD transceiver active */
+	bit	ENAB20		0x04	/* SE/HVD transceiver active */
+	bit	SELWIDE		0x02
+	bit	XCVR		0x01	/* External transceiver active */
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+	address			0x060
+	access_mode RW
+	bit	PERRORDIS	0x80
+	bit	PAUSEDIS	0x40
+	bit	FAILDIS		0x20
+	bit	FASTMODE	0x10
+	bit	BRKADRINTEN	0x08
+	bit	STEP		0x04
+	bit	SEQRESET	0x02
+	bit	LOADRAM		0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in succession.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+	address			0x061
+	access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+	address			0x062
+	access_mode RW
+}
+
+register SEQADDR1 {
+	address			0x063
+	access_mode RW
+	mask	SEQADDR1_MASK	0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+	address			0x064
+	access_mode RW
+	accumulator
+}
+
+register SINDEX	{
+	address			0x065
+	access_mode RW
+	sindex
+}
+
+register DINDEX {
+	address			0x066
+	access_mode RW
+}
+
+register ALLONES {
+	address			0x069
+	access_mode RO
+	allones
+}
+
+register ALLZEROS {
+	address			0x06a
+	access_mode RO
+	allzeros
+}
+
+register NONE {
+	address			0x06a
+	access_mode WO
+	none
+}
+
+register FLAGS {
+	address			0x06b
+	access_mode RO
+	bit	ZERO		0x02
+	bit	CARRY		0x01
+}
+
+register SINDIR	{
+	address			0x06c
+	access_mode RO
+}
+
+register DINDIR	 {
+	address			0x06d
+	access_mode WO
+}
+
+register FUNCTION1 {
+	address			0x06e
+	access_mode RW
+}
+
+register STACK {
+	address			0x06f
+	access_mode RO
+}
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+	address			0x084
+	access_mode RW
+	bit	ACE		0x08
+	bit	ENABLE		0x01
+}
+
+register DSCOMMAND0 {
+	address			0x084
+	access_mode RW
+	bit	CACHETHEN	0x80
+	bit	DPARCKEN	0x40
+	bit	MPARCKEN	0x20
+	bit	EXTREQLCK	0x10
+	bit	INTSCBRAMSEL	0x08
+	bit	RAMPS		0x04
+	bit	USCBSIZE32	0x02
+	bit	CIOPARCKEN	0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND {
+	address			0x084
+	access_mode RW
+	bit	CACHETHEN	0x80	/* Cache Threshold enable */
+	bit	DPARCKEN	0x40	/* Data Parity Check Enable */
+	bit	MPARCKEN	0x20	/* Memory Parity Check Enable */
+	bit	EXTREQLCK	0x10	/* External Request Lock */
+}
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+register BUSTIME {
+	address			0x085
+	access_mode RW
+	mask	BOFF		0xf0
+	mask	BON		0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+register BUSSPD {
+	address			0x086
+	access_mode RW
+	mask	DFTHRSH		0xc0
+	mask	STBOFF		0x38
+	mask	STBON		0x07
+	mask	DFTHRSH_100	0xc0
+}
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+	address			0x087
+	access_mode RW
+	bit	POWRDN		0x40
+	bit	SWINT		0x10
+	bit	IRQMS		0x08
+	bit	PAUSE		0x04
+	bit	INTEN		0x02
+	bit	CHIPRST		0x01
+	bit	CHIPRSTACK	0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+	address			0x088
+	size	4
+	access_mode RW
+}
+
+register HCNT {
+	address			0x08c
+	size	3
+	access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+	address			0x090
+	access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+	address			0x091
+	access_mode RW
+	bit	BRKADRINT 0x08
+	bit	SCSIINT	  0x04
+	bit	CMDCMPLT  0x02
+	bit	SEQINT    0x01
+	mask	BAD_PHASE	SEQINT		/* unknown scsi bus phase */
+	mask	SEND_REJECT	0x10|SEQINT	/* sending a message reject */
+	mask	NO_IDENT	0x20|SEQINT	/* no IDENTIFY after reconnect*/
+	mask	NO_MATCH	0x30|SEQINT	/* no cmd match for reconnect */
+	mask	EXTENDED_MSG	0x40|SEQINT	/* Extended message received */
+	mask	WIDE_RESIDUE	0x50|SEQINT	/* need kernel to back up */
+						/* the SG array for us */
+	mask	REJECT_MSG	0x60|SEQINT	/* Reject message received */
+	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
+	mask	RESIDUAL	0x80|SEQINT	/* Residual byte count != 0 */
+	mask	AWAITING_MSG	0xa0|SEQINT	/*
+						 * Kernel requested to specify
+						 * a message to this target
+						 * (command was null), so tell
+						 * it that it can fill the
+						 * message buffer.
+						 */
+	mask	TRACEPOINT	0xb0|SEQINT
+	mask	TRACEPOINT2	0xc0|SEQINT
+	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
+						 * Target changed phase on us
+						 * when we were expecting
+						 * another msgin byte.
+						 */
+	mask	DATA_OVERRUN	0xe0|SEQINT	/*
+						 * Target attempted to write
+						 * beyond the bounds of its
+						 * command.
+						 */
+
+	mask	SEQINT_MASK	0xf0|SEQINT	/* SEQINT Status Codes */
+	mask	INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+	address			0x092
+	access_mode RO
+	bit	CIOPARERR	0x80	/* Ultra2 only */
+	bit	PCIERRSTAT	0x40	/* PCI only */
+	bit	MPARERR		0x20	/* PCI only */
+	bit	DPARERR		0x10	/* PCI only */
+	bit	SQPARERR	0x08
+	bit	ILLOPCODE	0x04
+	bit	ILLSADDR	0x02
+	bit	DSCTMOUT	0x02	/* Ultra3 only */
+	bit	ILLHADDR	0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+	address			0x092
+	access_mode WO
+	bit	CLRPARERR	0x10	/* PCI only */
+	bit	CLRBRKADRINT	0x08
+	bit	CLRSCSIINT      0x04
+	bit	CLRCMDINT 	0x02
+	bit	CLRSEQINT 	0x01
+}
+
+register DFCNTRL {
+	address			0x093
+	access_mode RW
+	bit	PRELOADEN	0x80	/* aic7890 only */
+	bit	WIDEODD		0x40
+	bit	SCSIEN		0x20
+	bit	SDMAEN		0x10
+	bit	SDMAENACK	0x10
+	bit	HDMAEN		0x08
+	bit	HDMAENACK	0x08
+	bit	DIRECTION	0x04
+	bit	FIFOFLUSH	0x02
+	bit	FIFORESET	0x01
+}
+
+register DFSTATUS {
+	address			0x094
+	access_mode RO
+	bit	PRELOAD_AVAIL	0x80
+	bit	DWORDEMP	0x20
+	bit	MREQPEND	0x10
+	bit	HDONE		0x08
+	bit	DFTHRESH	0x04
+	bit	FIFOFULL	0x02
+	bit	FIFOEMP		0x01
+}
+
+register DFDAT {
+	address			0x099
+	access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+	address			0x09a
+	access_mode RW
+	bit	SCBAUTO		0x80
+	mask	SCBCNT_MASK	0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+	address			0x09b
+	access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT	{
+	address			0x09c
+	access_mode RO
+}
+
+/*
+ * SCSIDATL IMAGE Register (p. 5-104)
+ * Write to this register also go to SCSIDATL but this register will preserve
+ * the data for later reading as long as the SCSIDATL_IMGEN bit in the
+ * OPTIONMODE register is set.
+ */
+register SCSIDATL_IMG {
+	address			0x09c
+	access_mode RW
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+	address			0x09d
+	access_mode WO
+}
+
+/*
+ * CRC Control 1 Register (p. 5-105)
+ * Control bits for the Ultra 160/m CRC facilities
+ */
+register CRCCONTROL1 {
+	address			0x09d
+	access_mode RW
+	bit	CRCONSEEN	0x80 /* CRC ON Single Edge ENable */
+	bit	CRCVALCHKEN	0x40 /* CRC Value Check Enable */
+	bit	CRCENDCHKEN	0x20 /* CRC End Check Enable */
+	bit	CRCREQCHKEN	0x10
+	bit	TARGCRCENDEN	0x08 /* Enable End CRC transfer when target */
+	bit	TARGCRCCNTEN	0x04 /* Enable CRC transfer when target */
+}
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+	address			0x09e
+	access_mode RO
+}
+
+/*
+ * SCSI Phase Register (p. 5-106)
+ * Current bus phase
+ */
+register SCSIPHASE {
+	address			0x09e
+	access_mode RO
+	bit	SP_STATUS		0x20
+	bit	SP_COMMAND		0x10
+	bit	SP_MSG_IN		0x08
+	bit	SP_MSG_OUT		0x04
+	bit	SP_DATA_IN		0x02
+	bit	SP_DATA_OUT	0x01
+}
+
+/*
+ * Special Function
+ */
+register SFUNCT {
+	address			0x09f
+	access_mode RW
+	bit	ALT_MODE	0x80
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+	address			0x0a0
+	SCB_CONTROL {
+		size	1
+		bit	MK_MESSAGE      0x80
+		bit	DISCENB         0x40
+		bit	TAG_ENB		0x20
+		bit	DISCONNECTED	0x04
+		mask	SCB_TAG_TYPE	0x03
+	}
+	SCB_TCL {
+		size	1
+		bit	SELBUSB		0x08
+		mask	TID		0xf0
+		mask	LID		0x07
+	}
+	SCB_TARGET_STATUS {
+		size	1
+	}
+	SCB_SGCOUNT {
+		size	1
+	}
+	SCB_SGPTR {
+		size	4
+	}
+	SCB_RESID_SGCNT {
+		size	1
+	}
+	SCB_RESID_DCNT	{
+		size	3
+	}
+	SCB_DATAPTR {
+		size	4
+	}
+	SCB_DATACNT {
+		/*
+		 * Really only 3 bytes, but padded to make
+		 * the kernel's job easier.
+		 */
+		size	4
+	}
+	SCB_CMDPTR {
+		size	4
+	}
+	SCB_CMDLEN {
+		size	1
+	}
+	SCB_TAG {
+		size	1
+	}
+	SCB_NEXT {
+		size	1
+	}
+	SCB_PREV {
+		size	1
+	}
+	SCB_BUSYTARGETS {
+		size	4
+	}
+}
+
+const	SG_SIZEOF	0x08		/* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+	address			0x0c0
+	access_mode RW
+	bit	CS_2840		0x04
+	bit	CK_2840		0x02
+	bit	DO_2840		0x01
+}
+
+register STATUS_2840 {
+	address			0x0c1
+	access_mode RW
+	bit	EEPROM_TF	0x80
+	mask	BIOS_SEL	0x60
+	mask	ADSEL		0x1e
+	bit	DI_2840		0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register DSPCISTATUS {
+	address			0x086
+	mask	DFTHRSH_100	0xc0
+}
+
+register CCHADDR {
+	address			0x0E0
+	size 8
+}
+
+register CCHCNT {
+	address			0x0E8
+}
+
+register CCSGRAM {
+	address			0x0E9
+}
+
+register CCSGADDR {
+	address			0x0EA
+}
+
+register CCSGCTL {
+	address			0x0EB
+	bit	CCSGDONE	0x80
+	bit	CCSGEN		0x08
+	bit	FLAG		0x02
+	bit	CCSGRESET	0x01
+}
+
+register CCSCBCNT {
+	address			0xEF
+}
+
+register CCSCBCTL {
+	address			0x0EE
+	bit	CCSCBDONE	0x80
+	bit	ARRDONE		0x40	/* SCB Array prefetch done */
+	bit	CCARREN		0x10
+	bit	CCSCBEN		0x08
+	bit	CCSCBDIR	0x04
+	bit	CCSCBRESET	0x01
+}
+
+register CCSCBADDR {
+	address			0x0ED
+}
+
+register CCSCBRAM {
+	address			0xEC
+}
+
+register CCSCBPTR {
+	address			0x0F1
+}
+
+register HNSCB_QOFF {
+	address			0x0F4
+}
+
+register HESCB_QOFF {
+	address			0x0F5
+}
+
+register SNSCB_QOFF {
+	address			0x0F6
+}
+
+register SESCB_QOFF {
+	address			0x0F7
+}
+
+register SDSCB_QOFF {
+	address			0x0F8
+}
+
+register QOFF_CTLSTA {
+	address			0x0FA
+	bit	ESTABLISH_SCB_AVAIL	0x80
+	bit	SCB_AVAIL	0x40
+	bit	SNSCB_ROLLOVER	0x20
+	bit	SDSCB_ROLLOVER	0x10
+	bit	SESCB_ROLLOVER	0x08
+	mask	SCB_QSIZE	0x07
+	mask	SCB_QSIZE_256	0x06
+}
+
+register DFF_THRSH {
+	address			0x0FB
+	mask	WR_DFTHRSH	0x70
+	mask	RD_DFTHRSH	0x07
+	mask	RD_DFTHRSH_MIN	0x00
+	mask	RD_DFTHRSH_25	0x01
+	mask	RD_DFTHRSH_50	0x02
+	mask	RD_DFTHRSH_63	0x03
+	mask	RD_DFTHRSH_75	0x04
+	mask	RD_DFTHRSH_85	0x05
+	mask	RD_DFTHRSH_90	0x06
+	mask	RD_DFTHRSH_MAX	0x07
+	mask	WR_DFTHRSH_MIN	0x00
+	mask	WR_DFTHRSH_25	0x10
+	mask	WR_DFTHRSH_50	0x20
+	mask	WR_DFTHRSH_63	0x30
+	mask	WR_DFTHRSH_75	0x40
+	mask	WR_DFTHRSH_85	0x50
+	mask	WR_DFTHRSH_90	0x60
+	mask	WR_DFTHRSH_MAX	0x70
+}
+
+register SG_CACHEPTR {
+	access_mode RW
+	address			0x0fc
+	mask	SG_USER_DATA	0xfc
+	bit	LAST_SEG	0x02
+	bit	LAST_SEG_DONE	0x01
+}
+
+register BRDCTL	{
+	address			0x01d
+	bit	BRDDAT7		0x80
+	bit	BRDDAT6		0x40
+	bit	BRDDAT5		0x20
+	bit	BRDSTB		0x10
+	bit	BRDCS		0x08
+	bit	BRDRW		0x04
+	bit	BRDCTL1		0x02
+	bit	BRDCTL0		0x01
+	/* 7890 Definitions */
+	bit	BRDDAT4		0x10
+	bit	BRDDAT3		0x08
+	bit	BRDDAT2		0x04
+	bit	BRDRW_ULTRA2	0x02
+	bit	BRDSTB_ULTRA2	0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+register SEECTL {
+	address			0x01e
+	bit	EXTARBACK	0x80
+	bit	EXTARBREQ	0x40
+	bit	SEEMS		0x20
+	bit	SEERDY		0x10
+	bit	SEECS		0x08
+	bit	SEECK		0x04
+	bit	SEEDO		0x02
+	bit	SEEDI		0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+	address			0x020
+
+	/*
+	 * 1 byte per target starting at this address for configuration values
+	 */
+	TARG_SCSIRATE {
+		size		16
+	}
+	/*
+	 * Bit vector of targets that have ULTRA enabled.
+	 */
+	ULTRA_ENB {
+		size		2
+	}
+	/*
+	 * Bit vector of targets that have disconnection disabled.
+	 */
+	DISC_DSB {
+		size		2
+	}
+	/*
+	 * Single byte buffer used to designate the type or message
+	 * to send to a target.
+	 */
+	MSG_OUT {
+		size		1
+	}
+	/* Parameters for DMA Logic */
+	DMAPARAMS {
+		size		1
+		bit	PRELOADEN	0x80
+		bit	WIDEODD		0x40
+		bit	SCSIEN		0x20
+		bit	SDMAEN		0x10
+		bit	SDMAENACK	0x10
+		bit	HDMAEN		0x08
+		bit	HDMAENACK	0x08
+		bit	DIRECTION	0x04
+		bit	FIFOFLUSH	0x02
+		bit	FIFORESET	0x01
+	}
+	SEQ_FLAGS {
+		size		1
+		bit	IDENTIFY_SEEN	0x80
+		bit	SCBPTR_VALID	0x20
+		bit	DPHASE		0x10
+		bit	AMTARGET	0x08
+		bit	WIDE_BUS	0x02
+		bit	TWIN_BUS	0x01
+	}
+	/*
+	 * Temporary storage for the
+	 * target/channel/lun of a
+	 * reconnecting target
+	 */
+	SAVED_TCL {
+		size		1
+	}
+	/* Working value of the number of SG segments left */
+	SG_COUNT {
+		size		1
+	}
+	/* Working value of SG pointer */
+	SG_NEXT	{
+		size		4
+	}
+	/*
+	 * The last bus phase as seen by the sequencer. 
+	 */
+	LASTPHASE {
+		size		1
+		bit	CDI		0x80
+		bit	IOI		0x40
+		bit	MSGI		0x20
+		mask	PHASE_MASK	CDI|IOI|MSGI
+		mask	P_DATAOUT	0x00
+		mask	P_DATAIN	IOI
+		mask	P_COMMAND	CDI
+		mask	P_MESGOUT	CDI|MSGI
+		mask	P_STATUS	CDI|IOI
+		mask	P_MESGIN	CDI|IOI|MSGI
+		mask	P_BUSFREE	0x01
+	}
+	/*
+	 * head of list of SCBs awaiting
+	 * selection
+	 */
+	WAITING_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * disconnected.  Used for SCB
+	 * paging.
+	 */
+	DISCONNECTED_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * not in use.  Used for SCB paging.
+	 */
+	FREE_SCBH {
+		size		1
+	}
+	/*
+	 * Address of the hardware scb array in the host.
+	 */
+	HSCB_ADDR {
+		size		4
+	}
+	/*
+	 * Address of the 256 byte array storing the SCBID of outstanding
+	 * untagged SCBs indexed by TCL.
+	 */
+	SCBID_ADDR {
+		size		4
+	}
+	/*
+	 * Address of the array of command descriptors used to store
+	 * information about incoming selections.
+	 */
+	TMODE_CMDADDR {
+		size		4
+	}
+	KERNEL_QINPOS {
+		size		1
+	}
+	QINPOS {
+		size		1
+	}
+	QOUTPOS {
+		size		1
+	}
+	/*
+	 * Offset into the command descriptor array for the next
+	 * available desciptor to use.
+	 */
+	TMODE_CMDADDR_NEXT {
+		size		1
+	}
+	ARG_1 {
+		size		1
+		mask	SEND_MSG	0x80
+		mask	SEND_SENSE	0x40
+		mask	SEND_REJ	0x20
+		mask	MSGOUT_PHASEMIS	0x10
+		alias	RETURN_1
+	}
+	ARG_2 {
+		size		1
+		alias	RETURN_2
+	}
+
+	/*
+	 * Snapshot of MSG_OUT taken after each message is sent.
+	 */
+	LAST_MSG {
+		size		1
+	}
+
+	/*
+	 * Number of times we have filled the CCSGRAM with prefetched
+	 * SG elements.
+	 */
+	PREFETCH_CNT {
+		size		1
+	}
+
+
+	/*
+	 * These are reserved registers in the card's scratch ram.  Some of
+	 * the values are specified in the AHA2742 technical reference manual
+	 * and are initialized by the BIOS at boot time.
+	 */
+	SCSICONF {
+		address		0x05a
+		size		1
+		bit	TERM_ENB	0x80
+		bit	RESET_SCSI	0x40
+		mask	HSCSIID		0x07	/* our SCSI ID */
+		mask	HWSCSIID	0x0f	/* our SCSI ID if Wide Bus */
+	}
+	HOSTCONF {
+		address		0x05d
+		size		1
+	}
+	HA_274_BIOSCTRL	{
+		address		0x05f
+		size		1
+		mask	BIOSMODE		0x30
+		mask	BIOSDISABLED		0x30	
+		bit	CHANNEL_B_PRIMARY	0x08
+	}
+	/*
+	 * Per target SCSI offset values for Ultra2 controllers.
+	 */
+	TARG_OFFSET {
+		address		0x070
+		size		16
+	}
+}
+
+const SCB_LIST_NULL	0xff
+
+const CCSGADDR_MAX	0x80
+const CCSGRAM_MAXSEGS	16
+
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET	0
+const QOUTFIFO_OFFSET		1
+const QINFIFO_OFFSET		2
+
+/* WDTR Message values */
+const BUS_8_BIT			0x00
+const BUS_16_BIT		0x01
+const BUS_32_BIT		0x02
+
+/* Offset maximums */
+const MAX_OFFSET_8BIT		0x0f
+const MAX_OFFSET_16BIT		0x08
+const MAX_OFFSET_ULTRA2		0x7f
+const HOST_MSG			0xff
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT	0x05
+const CMD_GROUP0_BYTE_DELTA	-4
+const CMD_GROUP2_BYTE_DELTA	-6
+const CMD_GROUP4_BYTE_DELTA	4
+const CMD_GROUP5_BYTE_DELTA	11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS	download
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq linux/drivers/scsi/aic7xxx_old/aic7xxx.seq
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx.seq	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx.seq	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,1411 @@
+/*
+ * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-1999 Justin Gibbs.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License (GPL) and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ *	$Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $
+ */
+
+#include "aic7xxx.reg"
+#include "scsi_message.h"
+
+/*
+ * A few words on the waiting SCB list:
+ * After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
+ * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
+ * this list everytime a request sense occurs or after completing a non-tagged
+ * command for which a second SCB has been queued.  The sequencer will
+ * automatically consume the entries.
+ */
+
+reset:
+	clr	SCSISIGO;		/* De-assert BSY */
+	and	SXFRCTL1, ~BITBUCKET;
+	/* Always allow reselection */
+	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
+
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		/* Ensure that no DMA operations are in progress */
+		clr	CCSGCTL;
+		clr	CCSCBCTL;
+	}
+
+	call	clear_target_state;
+poll_for_work:
+	and	SXFRCTL0, ~SPIOEN;
+	if ((p->features & AHC_QUEUE_REGS) == 0) {
+		mov	A, QINPOS;
+	}
+poll_for_work_loop:
+	if ((p->features & AHC_QUEUE_REGS) == 0) {
+		and	SEQCTL, ~PAUSEDIS;
+	}
+	test	SSTAT0, SELDO|SELDI	jnz selection;
+	test	SCSISEQ, ENSELO	jnz poll_for_work;
+	if ((p->features & AHC_TWIN) != 0) {
+		/*
+		 * Twin channel devices cannot handle things like SELTO
+		 * interrupts on the "background" channel.  So, if we
+		 * are selecting, keep polling the current channel util
+		 * either a selection or reselection occurs.
+		 */
+		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
+		test	SSTAT0, SELDO|SELDI	jnz selection;
+		test	SCSISEQ, ENSELO	jnz poll_for_work;
+		xor	SBLKCTL,SELBUSB;	/* Toggle back */
+	}
+	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
+test_queue:
+	/* Has the driver posted any work for us? */
+	if ((p->features & AHC_QUEUE_REGS) != 0) {
+		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
+		mov	NONE, SNSCB_QOFF;
+		inc	QINPOS;
+	} else {
+		or	SEQCTL, PAUSEDIS;
+		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
+		inc	QINPOS;
+		and	SEQCTL, ~PAUSEDIS;
+	}
+
+/*
+ * We have at least one queued SCB now and we don't have any 
+ * SCBs in the list of SCBs awaiting selection.  If we have
+ * any SCBs available for use, pull the tag from the QINFIFO
+ * and get to work on it.
+ */
+	if ((p->flags & AHC_PAGESCBS) != 0) {
+		mov	ALLZEROS	call	get_free_or_disc_scb;
+	}
+
+dequeue_scb:
+	add	A, -1, QINPOS;
+	mvi	QINFIFO_OFFSET call fetch_byte;
+
+	if ((p->flags & AHC_PAGESCBS) == 0) {
+		/* In the non-paging case, the SCBID == hardware SCB index */
+		mov	SCBPTR, RETURN_2;
+	}
+dma_queued_scb:
+/*
+ * DMA the SCB from host ram into the current SCB location.
+ */
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	RETURN_2	 call dma_scb;
+
+/*
+ * Preset the residual fields in case we never go through a data phase.
+ * This isn't done by the host so we can avoid a DMA to clear these
+ * fields for the normal case of I/O that completes without underrun
+ * or overrun conditions.
+ */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_RESID_DCNT, SCB_DATACNT, 3;
+	} else {
+		mov     SCB_RESID_DCNT[0],SCB_DATACNT[0];
+		mov     SCB_RESID_DCNT[1],SCB_DATACNT[1];
+		mov     SCB_RESID_DCNT[2],SCB_DATACNT[2];
+	}
+	mov     SCB_RESID_SGCNT, SCB_SGCOUNT;
+
+start_scb:
+	/*
+	 * Place us on the waiting list in case our selection
+	 * doesn't win during bus arbitration.
+	 */
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+start_waiting:
+	/*
+	 * Pull the first entry off of the waiting SCB list.
+	 */
+	mov	SCBPTR, WAITING_SCBH;
+	call	start_selection;
+	jmp	poll_for_work;
+
+start_selection:
+	if ((p->features & AHC_TWIN) != 0) {
+		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
+		and	A,SELBUSB,SCB_TCL;	/* Get new channel bit */
+		or	SINDEX,A;
+		mov	SBLKCTL,SINDEX;		/* select channel */
+	}
+initialize_scsiid:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		and	A, TID, SCB_TCL;	/* Get target ID */
+		and	SCSIID_ULTRA2, OID;	/* Clear old target */
+		or	SCSIID_ULTRA2, A;
+	} else {
+		and	A, TID, SCB_TCL;	/* Get target ID */
+		and	SCSIID, OID;		/* Clear old target */
+		or	SCSIID, A;
+	}
+	mov	SCSIDATL, ALLZEROS;		/* clear out the latched */
+						/* data register, this */
+						/* fixes a bug on some */
+						/* controllers where the */
+						/* last byte written to */
+						/* this register can leak */
+						/* onto the data bus at */
+						/* bad times, such as during */
+						/* selection timeouts */
+	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+	or	SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
+	if ((p->features & AHC_ULTRA) != 0) {
+ultra:
+		mvi	SINDEX, ULTRA_ENB+1;
+		test	SAVED_TCL, 0x80		jnz ultra_2; /* Target ID > 7 */
+		dec	SINDEX;
+ultra_2:
+		mov     FUNCTION1,SAVED_TCL;
+		mov     A,FUNCTION1;
+		test	SINDIR, A	jz ndx_dtr;
+		or	SXFRCTL0, FAST20;
+	} 
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCSIRATE.
+ */
+ndx_dtr:
+	shr	A,4,SAVED_TCL;
+	if ((p->features & AHC_TWIN) != 0) {
+		test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
+		or	SAVED_TCL, SELBUSB; 
+		or	A,0x08;			/* Channel B entries add 8 */
+ndx_dtr_2:
+	}
+
+	if ((p->features & AHC_ULTRA2) != 0) {
+		add	SINDEX, TARG_OFFSET, A;
+		mov	SCSIOFFSET, SINDIR;
+	}
+
+	add	SINDEX,TARG_SCSIRATE,A;
+	mov	SCSIRATE,SINDIR ret;
+
+
+selection:
+	test	SSTAT0,SELDO	jnz select_out;
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
+ */
+initiator_reselect:
+	mvi	CLRSINT0, CLRSELDI;
+	/* XXX test for and handle ONE BIT condition */
+	and	SAVED_TCL, SELID_MASK, SELID;
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+	mvi	SPIOEN call	initialize_channel;
+	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */
+	jmp	ITloop;
+
+/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH.  Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select_out:
+	/* Turn off the selection hardware */
+	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
+						 * ATN on parity errors
+						 * for "in" phases
+						 */
+	mvi	CLRSINT0, CLRSELDO;
+	mov	SCBPTR, WAITING_SCBH;
+	mov	WAITING_SCBH,SCB_NEXT;
+	mov	SAVED_TCL, SCB_TCL;
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+	mvi	SPIOEN call	initialize_channel;
+/*
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
+ */
+	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
+	or	SEQ_FLAGS, IDENTIFY_SEEN;
+
+/*
+ * Main loop for information transfer phases.  Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
+ */
+ITloop:
+	call	phase_lock;
+
+	mov	A, LASTPHASE;
+
+	test	A, ~P_DATAIN	jz p_data;
+	cmp	A,P_COMMAND	je p_command;
+	cmp	A,P_MESGOUT	je p_mesgout;
+	cmp	A,P_STATUS	je p_status;
+	cmp	A,P_MESGIN	je p_mesgin;
+
+	mvi	INTSTAT,BAD_PHASE;	/* unknown phase - signal driver */
+	jmp	ITloop;			/* Try reading the bus again. */
+
+await_busfree:
+	and	SIMODE1, ~ENBUSFREE;
+	call	clear_target_state;
+	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	and	SXFRCTL0, ~SPIOEN;
+	test	SSTAT1,REQINIT|BUSFREE	jz .;
+	test	SSTAT1, BUSFREE jnz poll_for_work;
+	mvi	INTSTAT, BAD_PHASE;
+	
+clear_target_state:
+	/*
+	 * We assume that the kernel driver may reset us
+	 * at any time, even in the middle of a DMA, so
+	 * clear DFCNTRL too.
+	 */
+	clr	DFCNTRL;
+
+	/*
+	 * We don't know the target we will connect to,
+	 * so default to narrow transfers to avoid
+	 * parity problems.
+	 */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov    SCSIRATE, ALLZEROS, 2;
+	} else {
+		clr     SCSIRATE;
+		and     SXFRCTL0, ~(FAST20);
+	}
+	mvi	LASTPHASE, P_BUSFREE;
+	/* clear target specific flags */
+	clr	SEQ_FLAGS ret;
+
+/*
+ * If we re-enter the data phase after going through another phase, the
+ * STCNT may have been cleared, so restore it from the residual field.
+ */
+data_phase_reinit:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov	HADDR, SHADDR, 4;
+		bmov    HCNT, SCB_RESID_DCNT, 3;
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		bmov    STCNT, SCB_RESID_DCNT, 3;
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
+		mvi	DINDEX, STCNT;
+		mvi	SCB_RESID_DCNT	call bcopy_3;
+	}
+	jmp	data_phase_loop;
+
+p_data:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
+	} else {
+		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+	}
+	test	LASTPHASE, IOI jnz . + 2;
+	or	DMAPARAMS, DIRECTION;
+	call	assert;			/*
+					 * Ensure entering a data
+					 * phase is okay - seen identify, etc.
+					 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	CCSGADDR, CCSGADDR_MAX;
+	}
+	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+
+	/* We have seen a data phase */
+	or	SEQ_FLAGS, DPHASE;
+
+	/*
+	 * Initialize the DMA address and counter from the SCB.
+	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
+	 * modify the values in the SCB itself until we see a
+	 * save data pointers message.
+	 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov	HADDR, SCB_DATAPTR, 7;
+		bmov    STCNT, HCNT, 3;
+		bmov    SG_COUNT, SCB_SGCOUNT, 5;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCB_DATAPTR	call bcopy_7;
+		call	set_stcnt_from_hcnt;
+		mvi	DINDEX, SG_COUNT;
+		mvi	SCB_SGCOUNT	call bcopy_5;
+	}
+
+data_phase_loop:
+/* Guard against overruns */
+	test	SG_COUNT, 0xff jnz data_phase_inbounds;
+/*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
+	or	SXFRCTL1,BITBUCKET;
+	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		if ((p->features & AHC_ULTRA2) != 0) {
+			bmov	HCNT, ALLONES, 3;
+		}
+		bmov	STCNT, ALLONES, 3;
+	} else {
+		mvi	STCNT[0], 0xFF;
+		mvi	STCNT[1], 0xFF;
+		mvi	STCNT[2], 0xFF;
+	}
+data_phase_inbounds:
+/* If we are the last SG block, tell the hardware. */
+	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+	if ((p->features & AHC_ULTRA2) == 0) {
+		and	DMAPARAMS, ~WIDEODD;
+	} else {
+		mvi	SG_CACHEPTR, LAST_SEG;
+	}
+data_phase_wideodd:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		mov	SINDEX, ALLONES;
+		mov	DFCNTRL, DMAPARAMS;
+		test	SSTAT0, SDONE jnz .;
+data_phase_dma_loop:
+		test	SSTAT0, SDONE jnz data_phase_dma_done;
+		test	SSTAT1,PHASEMIS	jz data_phase_dma_loop;	/* ie. underrun */
+data_phase_dma_phasemis:
+		test	SSTAT0,SDONE	jnz data_phase_dma_done;
+		clr	SINDEX;			/* Remember the phasemiss */
+	} else {
+		mov	DMAPARAMS  call dma;
+	}
+
+data_phase_dma_done:
+/* Go tell the host about any overruns */
+	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+
+/* Exit if we had an underrun.  dma clears SINDEX in this case. */
+	test	SINDEX,0xff	jz data_phase_finish;
+
+/*
+ * Advance the scatter-gather pointers if needed 
+ */
+sg_advance:
+	dec	SG_COUNT;	/* one less segment to go */
+
+	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
+/*
+ * Load a struct scatter and set up the data address and length.
+ * If the working value of the SG count is nonzero, then
+ * we need to load a new set of values.
+ *
+ * This, like all DMA's, assumes little-endian host data storage.
+ */
+sg_load:
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		/*
+		 * Do we have any prefetch left???
+		 */
+		cmp	CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+
+		/*
+		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
+		 */
+		add	A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
+		mvi	A, CCSGADDR_MAX;
+		jc	. + 2;
+		shl	A, 3, SG_COUNT;
+		mov	CCHCNT, A;
+		bmov	CCHADDR, SG_NEXT, 4;
+		mvi	CCSGCTL, CCSGEN|CCSGRESET;
+		test	CCSGCTL, CCSGDONE jz .;
+		and	CCSGCTL, ~CCSGEN;
+		test	CCSGCTL, CCSGEN jnz .;
+		mvi	CCSGCTL, CCSGRESET;
+prefetched_segs_avail:
+		bmov 	HADDR, CCSGRAM, 8;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SG_NEXT	call bcopy_4;
+
+		mvi	HCNT[0],SG_SIZEOF;
+		clr	HCNT[1];
+		clr	HCNT[2];
+
+		or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+		call	dma_finish;
+
+		/*
+		 * Copy data from FIFO into SCB data pointer and data count.
+		 * This assumes that the SG segments are of the form:
+		 * struct ahc_dma_seg {
+		 *	u_int32_t	addr;	four bytes, little-endian order
+		 *	u_int32_t	len;	four bytes, little endian order
+		 * };
+		 */
+		mvi	HADDR	call dfdat_in_7;
+		call	set_stcnt_from_hcnt;
+	}
+
+/* Advance the SG pointer */
+	clr	A;			/* add sizeof(struct scatter) */
+	add	SG_NEXT[0],SG_SIZEOF;
+	adc	SG_NEXT[1],A;
+
+	test    SSTAT1, REQINIT jz .;
+	test	SSTAT1,PHASEMIS	jz data_phase_loop;
+
+/* This drops the last SG segment down to the shadow layer for us */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		mov	DFCNTRL, DMAPARAMS;
+		test	SSTAT0, SDONE	jnz .;
+	}
+
+data_phase_finish:
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		call	ultra2_dmafinish;
+	}
+	if ((p->features & AHC_ULTRA2) == 0) {
+		if ((p->features & AHC_CMD_CHAN) != 0) {
+			bmov    SCB_RESID_DCNT, STCNT, 3;
+			mov	SCB_RESID_SGCNT, SG_COUNT;
+		} else {
+			mov	SCB_RESID_DCNT[0],STCNT[0];
+			mov	SCB_RESID_DCNT[1],STCNT[1];
+			mov	SCB_RESID_DCNT[2],STCNT[2];
+			mov	SCB_RESID_SGCNT, SG_COUNT;
+		}
+	}
+
+	jmp	ITloop;
+
+data_phase_overrun:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		call	ultra2_dmafinish;
+	}
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+	and	SXFRCTL1, ~BITBUCKET;
+	mvi	INTSTAT,DATA_OVERRUN;
+	jmp	ITloop;
+
+ultra2_dmafinish:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
+		and	DFCNTRL, ~SCSIEN;
+		test	DFCNTRL, SCSIEN jnz .;
+ultra2_dmafifoflush:
+		or	DFCNTRL, FIFOFLUSH;
+		test	DFSTATUS, FIFOEMP jz . - 1;
+		/*
+		 * hardware bug alert!  This needless set of jumps is to
+		 * protect against a FIFOEMP status bit glitch in the
+		 * silicon.
+		 */
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, MREQPEND	jnz .;
+ultra2_dmahalt:
+		test	SCSIOFFSET, 0x7f	jnz ultra2_shutdown;
+ultra2_await_nreq:
+		test	SCSISIGI, REQI	jz ultra2_shutdown;
+		test	SSTAT1, (PHASEMIS|REQINIT)	jz ultra2_await_nreq;
+ultra2_shutdown:
+		and     DFCNTRL, ~(HDMAEN|SCSIEN);
+		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
+		bmov	SCB_RESID_DCNT, STCNT, 3;
+		mov	SCB_RESID_SGCNT, SG_COUNT;
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		ret;
+	}
+
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+	call	assert;
+
+/*
+ * Load HADDR and HCNT.
+ */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov	HADDR, SCB_CMDPTR, 5;
+		bmov	HCNT[1], ALLZEROS, 2;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov	STCNT, HCNT, 3;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCB_CMDPTR	call bcopy_5;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		call	set_stcnt_from_hcnt;
+	}
+
+	if ((p->features & AHC_ULTRA2) == 0) {
+		mvi	(SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+	} else {
+		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+		test	SSTAT0, SDONE jnz .;
+p_command_dma_loop:
+		test	SSTAT0, SDONE jnz p_command_ultra2_dma_done;
+		test	SSTAT1,PHASEMIS	jz p_command_dma_loop;	/* ie. underrun */
+p_command_ultra2_dma_done:
+		test	SCSISIGI, REQI	jz p_command_ultra2_shutdown;
+		test	SSTAT1, (PHASEMIS|REQINIT)	jz p_command_ultra2_dma_done;
+p_command_ultra2_shutdown:
+		and     DFCNTRL, ~(HDMAEN|SCSIEN);
+		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+	}
+	jmp	ITloop;
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+	call	assert;
+
+	mov	SCB_TARGET_STATUS, SCSIDATL;
+	jmp	ITloop;
+
+/*
+ * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
+ */
+p_mesgout_retry:
+	or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+p_mesgout:
+	mov	SINDEX, MSG_OUT;
+	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+	if ((p->features & AHC_WIDE) != 0) {
+		and	SINDEX,0xf,SCB_TCL;	/* lun */
+	} else {
+		and	SINDEX,0x7,SCB_TCL;	/* lun */
+	}
+	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
+	or	SINDEX,A;		/* or in disconnect privledge */
+	or	SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+	test	SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
+	mov	SCSIDATL, SINDEX;	/* Send the last byte */
+	jmp	p_mesgout_from_host + 1;/* Skip HOST_MSG test */
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
+ */
+p_mesgout_tag:
+	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+	mov	SCSIDATL, SINDEX;	/* Send the identify message */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	mov	SCB_TAG	jmp p_mesgout_onebyte;
+/*
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
+ */
+p_mesgout_from_host:
+	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
+	mvi     INTSTAT,AWAITING_MSG;
+	nop;
+	/*
+	 * Did the host detect a phase change?
+	 */
+	cmp	RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+	mvi	CLRSINT1, CLRATNO;
+	mov	SCSIDATL, SINDEX;
+
+/*
+ * If the next bus phase after ATN drops is a message out, it means
+ * that the target is requesting that the last message(s) be resent.
+ */
+	call	phase_lock;
+	cmp     LASTPHASE, P_MESGOUT    je p_mesgout_retry;
+
+p_mesgout_done:
+	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
+	mov	LAST_MSG, MSG_OUT;
+	cmp	MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
+	jmp	ITloop;
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
+
+	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
+	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
+	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
+	cmp	ALLZEROS,A		je mesgin_complete;
+	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
+	cmp	A,MSG_EXTENDED		je mesgin_extended;
+	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject;
+	cmp	A,MSG_NOOP		je mesgin_done;
+	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_wide_residue;
+
+rej_mesgin:
+/*
+ * We have no idea what this message in is, so we issue a message reject
+ * and hope for the best.  In any case, rejection should be a rare
+ * occurrence - signal the driver when it happens.
+ */
+	mvi	INTSTAT,SEND_REJECT;		/* let driver know */
+
+	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
+
+mesgin_done:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+	jmp	ITloop;
+
+
+mesgin_complete:
+/*
+ * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * and trigger a completion interrupt.  Before doing so, check to see if there
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
+ * process this information.  In the case of a non zero status byte, we 
+ * additionally interrupt the kernel driver synchronously, allowing it to
+ * decide if sense should be retrieved.  If the kernel driver wishes to request
+ * sense, it will fill the kernel SCB with a request sense command and set
+ * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
+ * the SCB, and process it as the next command by adding it to the waiting list.
+ * If the kernel driver does not wish to request sense, it need only clear
+ * RETURN_1, and the command is allowed to complete normally.  We don't bother
+ * to post to the QOUTFIFO in the error cases since it would require extra
+ * work in the kernel driver to ensure that the entry was removed before the
+ * command complete code tried processing it.
+ */
+
+/*
+ * First check for residuals
+ */
+	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Good Status? */
+upload_scb:
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+check_status:
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Just a residual? */
+	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
+	nop;
+	cmp	RETURN_1, SEND_SENSE	jne complete;
+	/* This SCB becomes the next to execute as it will retrieve sense */
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+add_to_waiting_list:
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+	/*
+	 * Prepare our selection hardware before the busfree so we have a
+	 * high probability of winning arbitration.
+	 */
+	call	start_selection;
+	jmp	await_busfree;
+
+complete:
+	/* If we are untagged, clear our address up in host ram */
+	test	SCB_CONTROL, TAG_ENB jnz complete_post;
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call post_byte_setup;
+	mvi	SCB_LIST_NULL call post_byte;
+
+complete_post:
+	/* Post the SCB and issue an interrupt */
+	if ((p->features & AHC_QUEUE_REGS) != 0) {
+		mov	A, SDSCB_QOFF;
+	} else {
+		mov	A, QOUTPOS;
+	}
+	mvi	QOUTFIFO_OFFSET call post_byte_setup;
+	mov	SCB_TAG call post_byte;
+	if ((p->features & AHC_QUEUE_REGS) == 0) {
+		inc 	QOUTPOS;
+	}
+	mvi	INTSTAT,CMDCMPLT;
+
+add_to_free_list:
+	call	add_scb_to_free_list;
+	jmp	await_busfree;
+
+/*
+ * Is it an extended message?  Copy the message to our message buffer and
+ * notify the host.  The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * or simply to do nothing.
+ */
+mesgin_extended:
+	mvi	INTSTAT,EXTENDED_MSG;		/* let driver know */
+	jmp	ITloop;
+
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
+mesgin_disconnect:
+	or	SCB_CONTROL,DISCONNECTED;
+	call	add_scb_to_disc_list;
+	jmp	await_busfree;
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
+mesgin_sdptrs:
+	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
+	/*
+	 * The SCB SGPTR becomes the next one we'll download,
+	 * and the SCB DATAPTR becomes the current SHADDR.
+	 * Use the residual number since STCNT is corrupted by
+	 * any message transfer.
+	 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_SGCOUNT, SG_COUNT, 5;
+		bmov    SCB_DATAPTR, SHADDR, 4;
+		bmov    SCB_DATACNT, SCB_RESID_DCNT, 3;
+	} else {
+		mvi	DINDEX, SCB_SGCOUNT;
+		mvi	SG_COUNT	call bcopy_5;
+		mvi	DINDEX, SCB_DATAPTR;
+		mvi	SHADDR		call bcopy_4;
+		mvi	SCB_RESID_DCNT	call	bcopy_3;
+	}
+	jmp	mesgin_done;
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
+mesgin_rdptrs:
+	and	SEQ_FLAGS, ~DPHASE;		/*
+						 * We'll reload them
+						 * the next time through
+						 * the dataphase.
+						 */
+	jmp	mesgin_done;
+
+/*
+ * Identify message?  For a reconnecting target, this tells us the lun
+ * that the reconnection is for - find the correct SCB and switch to it,
+ * clearing the "disconnected" bit so we don't "find" it by accident later.
+ */
+mesgin_identify:
+	
+	if ((p->features & AHC_WIDE) != 0) {
+		and	A,0x0f;		/* lun in lower four bits */
+	} else {
+		and	A,0x07;		/* lun in lower three bits */
+	}
+	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
+
+	mvi     ARG_2, SCB_LIST_NULL;   /* SCBID of prev SCB in disc List */
+	call	get_untagged_SCBID;
+	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
+	if ((p->flags & AHC_PAGESCBS) != 0) {
+		test	SEQ_FLAGS, SCBPTR_VALID	jz use_retrieveSCB;
+	}
+	/*
+	 * If the SCB was found in the disconnected list (as is
+	 * always the case in non-paging scenarios), SCBPTR is already
+	 * set to the correct SCB.  So, simply setup the SCB and get
+	 * on with things.
+	 */
+	mov	SCBPTR	call rem_scb_from_disc_list;
+	jmp	setup_SCB;
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to find the proper
+ * SCB.  With SCB paging, this requires using search for both tagged
+ * and non-tagged transactions since the SCB may exist in any slot.
+ * If we're not using SCB paging, we can use the tag as the direct
+ * index to the SCB.
+ */
+snoop_tag:
+	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
+snoop_tag_loop:
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGIN	jne not_found;
+	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
+get_tag:
+	mvi	ARG_1	call inb_next;	/* tag value */
+
+use_retrieveSCB:
+	call	retrieveSCB;
+setup_SCB:
+	mov	A, SAVED_TCL;
+	cmp	SCB_TCL, A	jne not_found_cleanup_scb;
+	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
+	and	SCB_CONTROL,~DISCONNECTED;
+	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
+	/* See if the host wants to send a message upon reconnection */
+	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	HOST_MSG	call mk_mesg;
+	jmp	mesgin_done;
+
+not_found_cleanup_scb:
+	test	SCB_CONTROL, DISCONNECTED jz . + 3;
+	call	add_scb_to_disc_list;
+	jmp	not_found;
+	call	add_scb_to_free_list;
+not_found:
+	mvi	INTSTAT, NO_MATCH;
+	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
+	jmp	mesgin_done;
+
+/*
+ * Message reject?  Let the kernel driver handle this.  If we have an 
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from 
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+	mvi	INTSTAT, REJECT_MSG;
+	jmp	mesgin_done;
+
+/*
+ * Wide Residue.  We handle the simple cases, but pass of the one hard case
+ * to the kernel (when the residue byte happened to cause us to advance our
+ * sg element array, so we know have to back that advance out).
+ */
+mesgin_wide_residue:
+	mvi	ARG_1	call inb_next; /* ACK the wide_residue and get */
+				       /* the size byte */
+/*
+ * In order for this to be reliable, we have to do all sorts of horrible
+ * magic in terms of resetting the datafifo and reloading the shadow layer
+ * with the correct new values (so that a subsequent save data pointers
+ * message will do the right thing).  We let the kernel do that work.
+ */
+ 	mvi	INTSTAT, WIDE_RESIDUE;
+	jmp	mesgin_done;
+	
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * Locking the driver out, build a one-byte message passed in SINDEX
+ * if there is no active message already.  SINDEX is returned intact.
+ */
+mk_mesg:
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
+	mov	MSG_OUT,SINDEX ret;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
+
+inb_next:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+inb_next_wait:
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
+	test	SSTAT1, REQINIT	jz inb_next_wait;
+	test	SSTAT1, SCSIPERR jnz .;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+	mov	DINDEX,SINDEX;
+	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
+inb_last:
+	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
+
+mesgin_phasemis:
+/*
+ * We expected to receive another byte, but the target changed phase
+ */
+	mvi	INTSTAT, MSGIN_PHASEMIS;
+	jmp	ITloop;
+
+/*
+ * DMA data transfer.  HADDR and HCNT must be loaded first, and
+ * SINDEX should contain the value to load DFCNTRL with - 0x3d for
+ * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+ * during initialization.
+ */
+if ((p->features & AHC_ULTRA2) == 0) {
+dma:
+	mov	DFCNTRL,SINDEX;
+dma_loop:
+	test	SSTAT0,DMADONE	jnz dma_dmadone;
+	test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
+dma_phasemis:
+	test	SSTAT0,SDONE	jnz dma_checkfifo;
+	mov	SINDEX,ALLZEROS;		/* Notify caller of phasemiss */
+
+/*
+ * We will be "done" DMAing when the transfer count goes to zero, or
+ * the target changes the phase (in light of this, it makes sense that
+ * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+ * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+ * magically on STCNT=0 or a phase change, so just wait for FIFO empty
+ * status.
+ */
+dma_checkfifo:
+	test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
+dma_fifoflush:
+	test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
+
+dma_fifoempty:
+	/* Don't clobber an inprogress host data transfer */
+	test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are 
+ * actually off first lest we get an ILLSADDR.
+ */
+dma_dmadone:
+	cmp	LASTPHASE, P_COMMAND	je dma_await_nreq;
+	test	SCSIRATE, 0x0f	jnz dma_shutdown;
+dma_await_nreq:
+	test	SCSISIGI, REQI	jz dma_shutdown;
+	test	SSTAT1, (PHASEMIS|REQINIT)	jz dma_await_nreq;
+dma_shutdown:
+	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+	/*
+	 * Some revisions of the aic7880 have a problem where, if the
+	 * data fifo is full, but the PCI input latch is not empty, 
+	 * HDMAEN cannot be cleared.  The fix used here is to attempt
+	 * to drain the data fifo until there is space for the input
+	 * latch to drain and HDMAEN de-asserts.
+	 */
+	mov	NONE, DFDAT;
+	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+}
+return:
+	ret;
+
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * message.
+ */
+assert:
+	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
+
+	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
+
+/*
+ * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
+ * or by the SCBID ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list.  If
+ * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
+ * is set to the proper SCB.
+ */
+findSCB:
+	mov	SCBPTR,SINDEX;			/* Initialize SCBPTR */
+	cmp	ARG_1, SCB_LIST_NULL	jne findSCB_by_SCBID;
+	mov	A, SAVED_TCL;
+	mvi	SCB_TCL	jmp findSCB_loop;	/* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
+	mov	A, ARG_1;			/* Tag passed in ARG_1 */
+	mvi	SCB_TAG	jmp findSCB_loop;	/* &SCB_TAG -> SINDEX */
+findSCB_next:
+	mov     ARG_2, SCBPTR;
+	cmp	SCB_NEXT, SCB_LIST_NULL je notFound;
+	mov	SCBPTR,SCB_NEXT;
+	dec	SINDEX;		/* Last comparison moved us too far */
+findSCB_loop:
+	cmp	SINDIR, A	jne findSCB_next;
+	mov	SINDEX, SCBPTR 	ret;
+notFound:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+
+/*
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host.  This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+	test	SEQ_FLAGS, SCBPTR_VALID	jz retrieve_from_host;
+	mov	SCBPTR	call findSCB;	/* Continue the search */
+	cmp	SINDEX, SCB_LIST_NULL	je retrieve_from_host;
+
+/*
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
+ * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
+ * if it is at the head.
+ */
+rem_scb_from_disc_list:
+/* Remove this SCB from the disconnection list */
+	cmp     ARG_2, SCB_LIST_NULL    je rHead;
+	mov	DINDEX, SCB_NEXT;
+	mov	SCBPTR, ARG_2;
+	mov	SCB_NEXT, DINDEX;
+	mov	SCBPTR, SINDEX ret;
+rHead:
+	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
+
+retrieve_from_host:
+/*
+ * We didn't find it.  Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+	mov	ALLZEROS	call	get_free_or_disc_scb;
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	/* Jump instead of call as we want to return anyway */
+	mov	ARG_1	jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL.  The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+	mvi	ARG_1, SCB_LIST_NULL;
+	mov	DISCONNECTED_SCBH call findSCB;
+	cmp	SINDEX, SCB_LIST_NULL	je get_SCBID_from_host;
+	or	SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+	test	SCB_CONTROL, TAG_ENB	jnz . + 2;
+	mov	ARG_1, SCB_TAG	ret;
+	mvi	ARG_1, SCB_LIST_NULL ret;
+
+/*
+ * Fetch a byte from host memory given an index of (A + (256 * SINDEX))
+ * and a base address of SCBID_ADDR.  The byte is returned in RETURN_2.
+ */
+fetch_byte:
+	mov	ARG_2, SINDEX;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	SCBID_ADDR call set_1byte_addr;
+		mvi	CCHCNT, 1;
+		mvi	CCSGCTL, CCSGEN|CCSGRESET;
+		test	CCSGCTL, CCSGDONE jz .;
+		mvi	CCSGCTL, CCSGRESET;
+		bmov	RETURN_2, CCSGRAM, 1 ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCBID_ADDR call set_1byte_addr;
+		mvi	HCNT[0], 1;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+		call	dma_finish;
+		mov	RETURN_2, DFDAT ret;
+	}
+
+/*
+ * Prepare the hardware to post a byte to host memory given an
+ * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
+ */
+post_byte_setup:
+	mov	ARG_2, SINDEX;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	SCBID_ADDR call	set_1byte_addr;
+		mvi	CCHCNT, 1;
+		mvi	CCSCBCTL, CCSCBRESET ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCBID_ADDR call	set_1byte_addr;
+		mvi	HCNT[0], 1;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		mvi	DFCNTRL, FIFORESET ret;
+	}
+
+post_byte:
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov	CCSCBRAM, SINDEX, 1;
+		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+		test	CCSCBCTL, CCSCBDONE jz .;
+		clr	CCSCBCTL ret;
+	} else {
+		mov	DFDAT, SINDEX;
+		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
+	}
+
+get_SCBID_from_host:
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call fetch_byte;
+	mov	RETURN_1,  RETURN_2 ret;
+
+phase_lock:     
+	test	SSTAT1, REQINIT jz phase_lock;
+	test	SSTAT1, SCSIPERR jnz phase_lock;
+	and	SCSISIGO, PHASE_MASK, SCSISIGI;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
+
+if ((p->features & AHC_CMD_CHAN) == 0) {
+set_stcnt_from_hcnt:
+	mov	STCNT[0], HCNT[0];
+	mov	STCNT[1], HCNT[1];
+	mov	STCNT[2], HCNT[2] ret;
+
+bcopy_7:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+bcopy_5:
+	mov	DINDIR, SINDIR;
+bcopy_4:
+	mov	DINDIR, SINDIR;
+bcopy_3:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR ret;
+}
+
+/*
+ * Setup addr assuming that A is an index into
+ * an array of 32byte objects, SINDEX contains
+ * the base address of that array, and DINDEX
+ * contains the base address of the location
+ * to store the indexed address.
+ */
+set_32byte_addr:
+	shr	ARG_2, 3, A;
+	shl	A, 5;
+/*
+ * Setup addr assuming that A + (ARG_1 * 256) is an
+ * index into an array of 1byte objects, SINDEX contains
+ * the base address of that array, and DINDEX contains
+ * the base address of the location to store the computed
+ * address.
+ */
+set_1byte_addr:
+	add	DINDIR, A, SINDIR;
+	mov	A, ARG_2;
+	adc	DINDIR, A, SINDIR;
+	clr	A;
+	adc	DINDIR, A, SINDIR;
+	adc	DINDIR, A, SINDIR ret;
+
+/*
+ * Either post or fetch and SCB from host memory based on the
+ * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
+ */
+dma_scb:
+	mov	A, SINDEX;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	HSCB_ADDR call set_32byte_addr;
+		mov	CCSCBPTR, SCBPTR;
+		mvi	CCHCNT, 32;
+		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
+		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
+		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
+		jmp	dma_scb_finish;
+dma_scb_tohost:
+		if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+			mvi	CCSCBCTL, CCSCBRESET;
+			bmov	CCSCBRAM, SCB_CONTROL, 32;
+			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			test	CCSCBCTL, CCSCBDONE jz .;
+		} else {
+			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+		}
+dma_scb_finish:
+		clr	CCSCBCTL;
+		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
+		ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	HSCB_ADDR call set_32byte_addr;
+		mvi	HCNT[0], 32;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		mov	DFCNTRL, DMAPARAMS;
+		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
+		/* Fill it with the SCB data */
+copy_scb_tofifo:
+		mvi	SINDEX, SCB_CONTROL;
+		add	A, 32, SINDEX;
+copy_scb_tofifo_loop:
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		cmp	SINDEX, A jne copy_scb_tofifo_loop;
+		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+dma_scb_fromhost:
+		call	dma_finish;
+		/* If we were putting the SCB, we are done */
+		test	DMAPARAMS, DIRECTION	jz	return;
+		mvi	SCB_CONTROL  call dfdat_in_7;
+		call	dfdat_in_7_continued;
+		call	dfdat_in_7_continued;
+		jmp	dfdat_in_7_continued;
+dfdat_in_7:
+		mov     DINDEX,SINDEX;
+dfdat_in_7_continued:
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT ret;
+	}
+
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+if ((p->features & AHC_CMD_CHAN) == 0) {
+dma_finish:
+	test	DFSTATUS,HDONE	jz dma_finish;
+	/* Turn off DMA */
+	and	DFCNTRL, ~HDMAEN;
+	test	DFCNTRL, HDMAEN jnz .;
+	ret;
+}
+
+add_scb_to_free_list:
+	if ((p->flags & AHC_PAGESCBS) != 0) {
+		mov	SCB_NEXT, FREE_SCBH;
+		mov	FREE_SCBH, SCBPTR;
+	}
+	mvi	SCB_TAG, SCB_LIST_NULL ret;
+
+if ((p->flags & AHC_PAGESCBS) != 0) {
+get_free_or_disc_scb:
+	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
+return_error:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+dequeue_disc_scb:
+	mov	SCBPTR, DISCONNECTED_SCBH;
+dma_up_scb:
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+unlink_disc_scb:
+	mov	DISCONNECTED_SCBH, SCB_NEXT ret;
+dequeue_free_scb:
+	mov	SCBPTR, FREE_SCBH;
+	mov	FREE_SCBH, SCB_NEXT ret;
+}
+
+add_scb_to_disc_list:
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+	mov	SCB_NEXT, DISCONNECTED_SCBH;
+	mov	DISCONNECTED_SCBH, SCBPTR ret;
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,413 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver proc support for Linux.
+ *
+ * Copyright (c) 1995, 1996 Dean W. Gehnert
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ----------------------------------------------------------------
+ *  o Modified from the EATA-DMA /proc support.
+ *  o Additional support for device block statistics provided by
+ *    Matthew Jacob.
+ *  o Correction of overflow by Heinz Mauelshagen
+ *  o Adittional corrections by Doug Ledford
+ *
+ *  Dean W. Gehnert, deang@teleport.com, 05/01/96
+ *
+ *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
+ *-M*************************************************************************/
+
+#include <linux/config.h>
+
+#define	BLS	(&aic7xxx_buffer[size])
+#define HDRB \
+"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
+
+#ifdef PROC_DEBUG
+extern int vsprintf(char *, const char *, va_list);
+
+static void
+proc_debug(const char *fmt, ...)
+{
+  va_list ap;
+  char buf[256];
+
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  printk(buf);
+  va_end(ap);
+}
+#else /* PROC_DEBUG */
+#  define proc_debug(fmt, args...)
+#endif /* PROC_DEBUG */
+
+static int aic7xxx_buffer_size = 0;
+static char *aic7xxx_buffer = NULL;
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_info
+ *
+ * Description:
+ *   Set parameters for the driver from the /proc filesystem.
+ *-F*************************************************************************/
+int
+aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+{
+  proc_debug("aic7xxx_set_info(): %s\n", buffer);
+  return (-ENOSYS);  /* Currently this is a no-op */
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_proc_info
+ *
+ * Description:
+ *   Return information to handle /proc support for the driver.
+ *-F*************************************************************************/
+int
+aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
+                    int hostno, int inout)
+{
+  struct Scsi_Host *HBAptr;
+  struct aic7xxx_host *p;
+  int    size = 0;
+  unsigned char i;
+  struct aic7xxx_xferstats *sp;
+  unsigned char target;
+
+  HBAptr = NULL;
+
+  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+    ;
+
+  if (!p)
+  {
+    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
+    if (size > length)
+    {
+      return (size);
+    }
+    else
+    {
+      return (length);
+    }
+  }
+
+  HBAptr = p->host;
+
+  if (inout == TRUE) /* Has data been written to the file? */ 
+  {
+    return (aic7xxx_set_info(buffer, length, HBAptr));
+  }
+
+  p = (struct aic7xxx_host *) HBAptr->hostdata;
+
+  /*
+   * It takes roughly 1K of space to hold all relevant card info, not
+   * counting any proc stats, so we start out with a 1.5k buffer size and
+   * if proc_stats is defined, then we sweep the stats structure to see
+   * how many drives we will be printing out for and add 384 bytes per
+   * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
+   */
+
+  size = 4096;
+  for (target = 0; target < MAX_TARGETS; target++)
+  {
+    if (p->dev_flags[target] & DEVICE_PRESENT)
+#ifdef AIC7XXX_PROC_STATS
+      size += 512;
+#else
+      size += 256;
+#endif
+  }
+  if (aic7xxx_buffer_size != size)
+  {
+    if (aic7xxx_buffer != NULL) 
+    {
+      kfree(aic7xxx_buffer);
+      aic7xxx_buffer_size = 0;
+    }
+    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
+  }
+  if (aic7xxx_buffer == NULL)
+  {
+    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
+        __LINE__);
+    return size;
+  }
+  aic7xxx_buffer_size = size;
+
+  size = 0;
+  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Compile Options:\n");
+#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
+#else
+  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
+#endif
+#ifdef AIC7XXX_PROC_STATS
+  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
+#else
+  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
+#endif
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Adapter Configuration:\n");
+  size += sprintf(BLS, "           SCSI Adapter: %s\n",
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel Controller ");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->features & AHC_WIDE)
+      wide = "Wide ";
+    if (p->features & AHC_ULTRA3)
+    {
+      switch(p->chip & AHC_CHIPID_MASK)
+      {
+        case AHC_AIC7892:
+        case AHC_AIC7899:
+          ultra = "Ultra-160/m LVD/SE ";
+          break;
+        default:
+          ultra = "Ultra-3 LVD/SE ";
+          break;
+      }
+    }
+    else if (p->features & AHC_ULTRA2)
+      ultra = "Ultra-2 LVD/SE ";
+    else if (p->features & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s ",
+      ultra, wide, channel);
+  }
+  switch(p->chip & ~AHC_CHIPID_MASK)
+  {
+    case AHC_VL:
+      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_EISA:
+      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( (p->chip & (AHC_VL | AHC_EISA)) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+  }
+  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
+          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
+         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
+           "SEEPROM not found, using leftover BIOS values.") );
+  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  if (p->flags & AHC_EXTERNAL_SRAM)
+    size += sprintf(BLS, "                         Using External SCB SRAM\n");
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->chip & AHC_EISA)
+  {
+    size += sprintf(BLS, " %s\n",
+        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
+  }
+  else
+  {
+    size += sprintf(BLS, "\n");
+  }
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
+  size += sprintf(BLS, "   Extended Translation: %sabled\n",
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Statistics:\n\n");
+  for (target = 0; target < MAX_TARGETS; target++)
+  {
+    sp = &p->stats[target];
+    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
+    {
+      continue;
+    }
+    if (p->features & AHC_TWIN)
+    {
+      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+          p->host_no, (target >> 3), (target & 0x7), 0);
+    }
+    else
+    {
+      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+          p->host_no, 0, target, 0);
+    }
+    size += sprintf(BLS, "  Device using %s/%s",
+          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+          "Wide" : "Narrow",
+          (p->transinfo[target].cur_offset != 0) ?
+          "Sync transfers at " : "Async transfers.\n" );
+    if (p->transinfo[target].cur_offset != 0)
+    {
+      struct aic7xxx_syncrate *sync_rate;
+      unsigned char options = p->transinfo[target].cur_options;
+      int period = p->transinfo[target].cur_period;
+      int rate = (p->transinfo[target].cur_width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+
+      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
+      if (sync_rate != NULL)
+      {
+        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+                        sync_rate->rate[rate],
+                        p->transinfo[target].cur_offset );
+      }
+      else
+      {
+        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+                        p->transinfo[target].cur_offset );
+      }
+    }
+    size += sprintf(BLS, "  Transinfo settings: ");
+    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
+                    p->transinfo[target].cur_period,
+                    p->transinfo[target].cur_offset,
+                    p->transinfo[target].cur_width,
+                    p->transinfo[target].cur_options);
+    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
+                    p->transinfo[target].goal_period,
+                    p->transinfo[target].goal_offset,
+                    p->transinfo[target].goal_width,
+                    p->transinfo[target].goal_options);
+    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
+                    p->transinfo[target].user_period,
+                    p->transinfo[target].user_offset,
+                    p->transinfo[target].user_width,
+                    p->transinfo[target].user_options);
+#ifdef AIC7XXX_PROC_STATS
+    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+    size += sprintf(BLS, "%s\n", HDRB);
+    size += sprintf(BLS, "   Reads:");
+    for (i = 0; i < NUMBER(sp->r_bins); i++)
+    {
+      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+    size += sprintf(BLS, "  Writes:");
+    for (i = 0; i < NUMBER(sp->w_bins); i++)
+    {
+      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+#else
+    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+#endif /* AIC7XXX_PROC_STATS */
+    size += sprintf(BLS, "\n\n");
+  }
+
+  if (size >= aic7xxx_buffer_size)
+  {
+    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
+  }
+
+  if (offset > size - 1)
+  {
+    kfree(aic7xxx_buffer);
+    aic7xxx_buffer = NULL;
+    aic7xxx_buffer_size = length = 0;
+    *start = NULL;
+  }
+  else
+  {
+    *start = buffer;
+    length = MIN(length, size - offset);
+    memcpy(buffer, &aic7xxx_buffer[offset], length);
+  }
+
+  return (length);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's 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: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx_reg.h	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,629 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+
+#define	SCSISEQ         		0x00
+#define		TEMODE          	0x80
+#define		ENSELO          	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		ENAUTOATNO      	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNP      	0x02
+#define		SCSIRSTO        	0x01
+
+#define	SXFRCTL0        		0x01
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		FAST20          	0x20
+#define		CLRSTCNT        	0x10
+#define		SPIOEN          	0x08
+#define		SCAMEN          	0x04
+#define		CLRCHN          	0x02
+
+#define	SXFRCTL1        		0x02
+#define		BITBUCKET       	0x80
+#define		SWRAPEN         	0x40
+#define		ENSPCHK         	0x20
+#define		STIMESEL        	0x18
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	SCSISIGO        		0x03
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	SCSISIGI        		0x03
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIRATE        		0x04
+#define		WIDEXFER        	0x80
+#define		SXFR_ULTRA2     	0x7f
+#define		SXFR            	0x70
+#define		SOFS            	0x0f
+
+#define	SCSIID          		0x05
+#define	SCSIOFFSET      		0x05
+#define		SOFS_ULTRA2     	0x7f
+
+#define	SCSIDATL        		0x06
+
+#define	SCSIDATH        		0x07
+
+#define	STCNT           		0x08
+
+#define	OPTIONMODE      		0x08
+#define		AUTORATEEN      	0x80
+#define		AUTOACKEN       	0x40
+#define		ATNMGMNTEN      	0x20
+#define		BUSFREEREV      	0x10
+#define		EXPPHASEDIS     	0x08
+#define		SCSIDATL_IMGEN  	0x04
+#define		AUTO_MSGOUT_DE  	0x02
+#define		DIS_MSGIN_DUALEDGE	0x01
+
+#define	CLRSINT0        		0x0b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRSWRAP        	0x08
+#define		CLRSPIORDY      	0x02
+
+#define	SSTAT0          		0x0b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		IOERR           	0x08
+#define		SWRAP           	0x08
+#define		SDONE           	0x04
+#define		SPIORDY         	0x02
+#define		DMADONE         	0x01
+
+#define	CLRSINT1        		0x0c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRPHASECHG     	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x0c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		PHASECHG        	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x0d
+#define		OVERRUN         	0x80
+#define		SHVALID         	0x40
+#define		WIDE_RES        	0x20
+#define		SFCNT           	0x1f
+#define		EXP_ACTIVE      	0x10
+#define		CRCVALERR       	0x08
+#define		CRCENDERR       	0x04
+#define		CRCREQERR       	0x02
+#define		DUAL_EDGE_ERROR 	0x01
+
+#define	SSTAT3          		0x0e
+#define		SCSICNT         	0xf0
+#define		OFFCNT          	0x0f
+
+#define	SCSIID_ULTRA2   		0x0f
+#define		OID             	0x0f
+
+#define	SIMODE0         		0x10
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENIOERR         	0x08
+#define		ENSWRAP         	0x08
+#define		ENSDONE         	0x04
+#define		ENSPIORDY       	0x02
+#define		ENDMADONE       	0x01
+
+#define	SIMODE1         		0x11
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENPHASECHG      	0x02
+#define		ENREQINIT       	0x01
+
+#define	SCSIBUSL        		0x12
+
+#define	SCSIBUSH        		0x13
+
+#define	SHADDR          		0x14
+
+#define	SELTIMER        		0x18
+#define		STAGE6          	0x20
+#define		STAGE5          	0x10
+#define		STAGE4          	0x08
+#define		STAGE3          	0x04
+#define		STAGE2          	0x02
+#define		STAGE1          	0x01
+
+#define	SELID           		0x19
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		HAS_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
+#define	BRDCTL          		0x1d
+#define		BRDDAT7         	0x80
+#define		BRDDAT6         	0x40
+#define		BRDDAT5         	0x20
+#define		BRDDAT4         	0x10
+#define		BRDSTB          	0x10
+#define		BRDCS           	0x08
+#define		BRDDAT3         	0x08
+#define		BRDDAT2         	0x04
+#define		BRDRW           	0x04
+#define		BRDRW_ULTRA2    	0x02
+#define		BRDCTL1         	0x02
+#define		BRDCTL0         	0x01
+#define		BRDSTB_ULTRA2   	0x01
+
+#define	SEECTL          		0x1e
+#define		EXTARBACK       	0x80
+#define		EXTARBREQ       	0x40
+#define		SEEMS           	0x20
+#define		SEERDY          	0x10
+#define		SEECS           	0x08
+#define		SEECK           	0x04
+#define		SEEDO           	0x02
+#define		SEEDI           	0x01
+
+#define	SBLKCTL         		0x1f
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		AUTOFLUSHDIS    	0x20
+#define		ENAB40          	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+#define		XCVR            	0x01
+
+#define	SRAM_BASE       		0x20
+
+#define	TARG_SCSIRATE   		0x20
+
+#define	ULTRA_ENB       		0x30
+
+#define	DISC_DSB        		0x32
+
+#define	MSG_OUT         		0x34
+
+#define	DMAPARAMS       		0x35
+#define		PRELOADEN       	0x80
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAENACK       	0x10
+#define		SDMAEN          	0x10
+#define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SEQ_FLAGS       		0x36
+#define		IDENTIFY_SEEN   	0x80
+#define		SCBPTR_VALID    	0x20
+#define		DPHASE          	0x10
+#define		AMTARGET        	0x08
+#define		WIDE_BUS        	0x02
+#define		TWIN_BUS        	0x01
+
+#define	SAVED_TCL       		0x37
+
+#define	SG_COUNT        		0x38
+
+#define	SG_NEXT         		0x39
+
+#define	LASTPHASE       		0x3d
+#define		P_MESGIN        	0xe0
+#define		PHASE_MASK      	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		P_DATAIN        	0x40
+#define		MSGI            	0x20
+#define		P_BUSFREE       	0x01
+#define		P_DATAOUT       	0x00
+
+#define	WAITING_SCBH    		0x3e
+
+#define	DISCONNECTED_SCBH		0x3f
+
+#define	FREE_SCBH       		0x40
+
+#define	HSCB_ADDR       		0x41
+
+#define	SCBID_ADDR      		0x45
+
+#define	TMODE_CMDADDR   		0x49
+
+#define	KERNEL_QINPOS   		0x4d
+
+#define	QINPOS          		0x4e
+
+#define	QOUTPOS         		0x4f
+
+#define	TMODE_CMDADDR_NEXT		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
+
+#define	ARG_2           		0x52
+#define	RETURN_2        		0x52
+
+#define	LAST_MSG        		0x53
+
+#define	PREFETCH_CNT    		0x54
+
+#define	SCSICONF        		0x5a
+#define		TERM_ENB        	0x80
+#define		RESET_SCSI      	0x40
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
+
+#define	HOSTCONF        		0x5d
+
+#define	HA_274_BIOSCTRL 		0x5f
+#define		BIOSMODE        	0x30
+#define		BIOSDISABLED    	0x30
+#define		CHANNEL_B_PRIMARY	0x08
+
+#define	SEQCTL          		0x60
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQRAM          		0x61
+
+#define	SEQADDR0        		0x62
+
+#define	SEQADDR1        		0x63
+#define		SEQADDR1_MASK   	0x01
+
+#define	ACCUM           		0x64
+
+#define	SINDEX          		0x65
+
+#define	DINDEX          		0x66
+
+#define	ALLONES         		0x69
+
+#define	ALLZEROS        		0x6a
+
+#define	NONE            		0x6a
+
+#define	FLAGS           		0x6b
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SINDIR          		0x6c
+
+#define	DINDIR          		0x6d
+
+#define	FUNCTION1       		0x6e
+
+#define	STACK           		0x6f
+
+#define	TARG_OFFSET     		0x70
+
+#define	BCTL            		0x84
+#define		ACE             	0x08
+#define		ENABLE          	0x01
+
+#define	DSCOMMAND0      		0x84
+#define		INTSCBRAMSEL    	0x08
+#define		RAMPS           	0x04
+#define		USCBSIZE32      	0x02
+#define		CIOPARCKEN      	0x01
+
+#define	DSCOMMAND       		0x84
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+
+#define	BUSTIME         		0x85
+#define		BOFF            	0xf0
+#define		BON             	0x0f
+
+#define	BUSSPD          		0x86
+#define		DFTHRSH         	0xc0
+#define		STBOFF          	0x38
+#define		STBON           	0x07
+
+#define	DSPCISTATUS     		0x86
+#define		DFTHRSH_100     	0xc0
+
+#define	HCNTRL          		0x87
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		IRQMS           	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HADDR           		0x88
+
+#define	HCNT            		0x8c
+
+#define	SCBPTR          		0x90
+
+#define	INTSTAT         		0x91
+#define		SEQINT_MASK     	0xf1
+#define		DATA_OVERRUN    	0xe1
+#define		MSGIN_PHASEMIS  	0xd1
+#define		TRACEPOINT2     	0xc1
+#define		TRACEPOINT      	0xb1
+#define		AWAITING_MSG    	0xa1
+#define		RESIDUAL        	0x81
+#define		BAD_STATUS      	0x71
+#define		REJECT_MSG      	0x61
+#define		WIDE_RESIDUE    	0x51
+#define		EXTENDED_MSG    	0x41
+#define		NO_MATCH        	0x31
+#define		NO_IDENT        	0x21
+#define		SEND_REJECT     	0x11
+#define		INT_PEND        	0x0f
+#define		BRKADRINT       	0x08
+#define		SCSIINT         	0x04
+#define		CMDCMPLT        	0x02
+#define		BAD_PHASE       	0x01
+#define		SEQINT          	0x01
+
+#define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
+#define		CLRBRKADRINT    	0x08
+#define		CLRSCSIINT      	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSEQINT       	0x01
+
+#define	ERROR           		0x92
+#define		CIOPARERR       	0x80
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		DSCTMOUT        	0x02
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
+#define	DFCNTRL         		0x93
+
+#define	DFSTATUS        		0x94
+#define		PRELOAD_AVAIL   	0x80
+#define		DWORDEMP        	0x20
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	DFDAT           		0x99
+
+#define	SCBCNT          		0x9a
+#define		SCBAUTO         	0x80
+#define		SCBCNT_MASK     	0x1f
+
+#define	QINFIFO         		0x9b
+
+#define	QINCNT          		0x9c
+
+#define	SCSIDATL_IMG    		0x9c
+
+#define	QOUTFIFO        		0x9d
+
+#define	CRCCONTROL1     		0x9d
+#define		CRCONSEEN       	0x80
+#define		CRCVALCHKEN     	0x40
+#define		CRCENDCHKEN     	0x20
+#define		CRCREQCHKEN     	0x10
+#define		TARGCRCENDEN    	0x08
+#define		TARGCRCCNTEN    	0x04
+
+#define	QOUTCNT         		0x9e
+
+#define	SCSIPHASE       		0x9e
+#define		SP_STATUS       	0x20
+#define		SP_COMMAND      	0x10
+#define		SP_MSG_IN       	0x08
+#define		SP_MSG_OUT      	0x04
+#define		SP_DATA_IN      	0x02
+#define		SP_DATA_OUT     	0x01
+
+#define	SFUNCT          		0x9f
+#define		ALT_MODE        	0x80
+
+#define	SCB_CONTROL     		0xa0
+#define		MK_MESSAGE      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		DISCONNECTED    	0x04
+#define		SCB_TAG_TYPE    	0x03
+
+#define	SCB_BASE        		0xa0
+
+#define	SCB_TCL         		0xa1
+#define		TID             	0xf0
+#define		SELBUSB         	0x08
+#define		LID             	0x07
+
+#define	SCB_TARGET_STATUS		0xa2
+
+#define	SCB_SGCOUNT     		0xa3
+
+#define	SCB_SGPTR       		0xa4
+
+#define	SCB_RESID_SGCNT 		0xa8
+
+#define	SCB_RESID_DCNT  		0xa9
+
+#define	SCB_DATAPTR     		0xac
+
+#define	SCB_DATACNT     		0xb0
+
+#define	SCB_CMDPTR      		0xb4
+
+#define	SCB_CMDLEN      		0xb8
+
+#define	SCB_TAG         		0xb9
+
+#define	SCB_NEXT        		0xba
+
+#define	SCB_PREV        		0xbb
+
+#define	SCB_BUSYTARGETS 		0xbc
+
+#define	SEECTL_2840     		0xc0
+#define		CS_2840         	0x04
+#define		CK_2840         	0x02
+#define		DO_2840         	0x01
+
+#define	STATUS_2840     		0xc1
+#define		EEPROM_TF       	0x80
+#define		BIOS_SEL        	0x60
+#define		ADSEL           	0x1e
+#define		DI_2840         	0x01
+
+#define	CCHADDR         		0xe0
+
+#define	CCHCNT          		0xe8
+
+#define	CCSGRAM         		0xe9
+
+#define	CCSGADDR        		0xea
+
+#define	CCSGCTL         		0xeb
+#define		CCSGDONE        	0x80
+#define		CCSGEN          	0x08
+#define		FLAG            	0x02
+#define		CCSGRESET       	0x01
+
+#define	CCSCBRAM        		0xec
+
+#define	CCSCBADDR       		0xed
+
+#define	CCSCBCTL        		0xee
+#define		CCSCBDONE       	0x80
+#define		ARRDONE         	0x40
+#define		CCARREN         	0x10
+#define		CCSCBEN         	0x08
+#define		CCSCBDIR        	0x04
+#define		CCSCBRESET      	0x01
+
+#define	CCSCBCNT        		0xef
+
+#define	CCSCBPTR        		0xf1
+
+#define	HNSCB_QOFF      		0xf4
+
+#define	HESCB_QOFF      		0xf5
+
+#define	SNSCB_QOFF      		0xf6
+
+#define	SESCB_QOFF      		0xf7
+
+#define	SDSCB_QOFF      		0xf8
+
+#define	QOFF_CTLSTA     		0xfa
+#define		ESTABLISH_SCB_AVAIL	0x80
+#define		SCB_AVAIL       	0x40
+#define		SNSCB_ROLLOVER  	0x20
+#define		SDSCB_ROLLOVER  	0x10
+#define		SESCB_ROLLOVER  	0x08
+#define		SCB_QSIZE       	0x07
+#define		SCB_QSIZE_256   	0x06
+
+#define	DFF_THRSH       		0xfb
+#define		WR_DFTHRSH      	0x70
+#define		WR_DFTHRSH_MAX  	0x70
+#define		WR_DFTHRSH_90   	0x60
+#define		WR_DFTHRSH_85   	0x50
+#define		WR_DFTHRSH_75   	0x40
+#define		WR_DFTHRSH_63   	0x30
+#define		WR_DFTHRSH_50   	0x20
+#define		WR_DFTHRSH_25   	0x10
+#define		RD_DFTHRSH_MAX  	0x07
+#define		RD_DFTHRSH      	0x07
+#define		RD_DFTHRSH_90   	0x06
+#define		RD_DFTHRSH_85   	0x05
+#define		RD_DFTHRSH_75   	0x04
+#define		RD_DFTHRSH_63   	0x03
+#define		RD_DFTHRSH_50   	0x02
+#define		RD_DFTHRSH_25   	0x01
+#define		RD_DFTHRSH_MIN  	0x00
+#define		WR_DFTHRSH_MIN  	0x00
+
+#define	SG_CACHEPTR     		0xfc
+#define		SG_USER_DATA    	0xfc
+#define		LAST_SEG        	0x02
+#define		LAST_SEG_DONE   	0x01
+
+
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	BUS_8_BIT	0x00
+#define	QOUTFIFO_OFFSET	0x01
+#define	CCSGRAM_MAXSEGS	0x10
+#define	CMD_GROUP2_BYTE_DELTA	0xfa
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_16_BIT	0x01
+#define	QINFIFO_OFFSET	0x02
+#define	CMD_GROUP5_BYTE_DELTA	0x0b
+#define	MAX_OFFSET_ULTRA2	0x7f
+#define	MAX_OFFSET_16BIT	0x08
+#define	UNTAGGEDSCB_OFFSET	0x00
+#define	SCB_LIST_NULL	0xff
+#define	SG_SIZEOF	0x08
+#define	CMD_GROUP4_BYTE_DELTA	0x04
+#define	CMD_GROUP0_BYTE_DELTA	0xfc
+#define	HOST_MSG	0xff
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
+
+
+/* Downloaded Constant Definitions */
+#define	TMODE_NUMCMDS	0x00
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/aic7xxx_seq.c	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,745 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+static unsigned char seqprog[] = {
+	0xff, 0x6a, 0x06, 0x08,
+	0x7f, 0x02, 0x04, 0x08,
+	0x12, 0x6a, 0x00, 0x00,
+	0xff, 0x6a, 0xd6, 0x09,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x00, 0x65, 0xca, 0x58,
+	0xf7, 0x01, 0x02, 0x08,
+	0xff, 0x4e, 0xc8, 0x08,
+	0xbf, 0x60, 0xc0, 0x08,
+	0x60, 0x0b, 0x86, 0x68,
+	0x40, 0x00, 0x0c, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x60, 0x0b, 0x86, 0x68,
+	0x40, 0x00, 0x0c, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0xff, 0x3e, 0x48, 0x60,
+	0x40, 0xfa, 0x10, 0x78,
+	0xff, 0xf6, 0xd4, 0x08,
+	0x01, 0x4e, 0x9c, 0x18,
+	0x40, 0x60, 0xc0, 0x00,
+	0x00, 0x4d, 0x10, 0x70,
+	0x01, 0x4e, 0x9c, 0x18,
+	0xbf, 0x60, 0xc0, 0x08,
+	0x00, 0x6a, 0x3e, 0x5c,
+	0xff, 0x4e, 0xc8, 0x18,
+	0x02, 0x6a, 0x54, 0x5b,
+	0xff, 0x52, 0x20, 0x09,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0x52, 0xca, 0x5b,
+	0x03, 0xb0, 0x52, 0x31,
+	0xff, 0xb0, 0x52, 0x09,
+	0xff, 0xb1, 0x54, 0x09,
+	0xff, 0xb2, 0x56, 0x09,
+	0xff, 0xa3, 0x50, 0x09,
+	0xff, 0x3e, 0x74, 0x09,
+	0xff, 0x90, 0x7c, 0x08,
+	0xff, 0x3e, 0x20, 0x09,
+	0x00, 0x65, 0x4e, 0x58,
+	0x00, 0x65, 0x0c, 0x40,
+	0xf7, 0x1f, 0xca, 0x08,
+	0x08, 0xa1, 0xc8, 0x08,
+	0x00, 0x65, 0xca, 0x00,
+	0xff, 0x65, 0x3e, 0x08,
+	0xf0, 0xa1, 0xc8, 0x08,
+	0x0f, 0x0f, 0x1e, 0x08,
+	0x00, 0x0f, 0x1e, 0x00,
+	0xf0, 0xa1, 0xc8, 0x08,
+	0x0f, 0x05, 0x0a, 0x08,
+	0x00, 0x05, 0x0a, 0x00,
+	0xff, 0x6a, 0x0c, 0x08,
+	0x5a, 0x6a, 0x00, 0x04,
+	0x12, 0x65, 0x02, 0x00,
+	0x31, 0x6a, 0xca, 0x00,
+	0x80, 0x37, 0x6e, 0x68,
+	0xff, 0x65, 0xca, 0x18,
+	0xff, 0x37, 0xdc, 0x08,
+	0xff, 0x6e, 0xc8, 0x08,
+	0x00, 0x6c, 0x76, 0x78,
+	0x20, 0x01, 0x02, 0x00,
+	0x4c, 0x37, 0xc8, 0x28,
+	0x08, 0x1f, 0x7e, 0x78,
+	0x08, 0x37, 0x6e, 0x00,
+	0x08, 0x64, 0xc8, 0x00,
+	0x70, 0x64, 0xca, 0x18,
+	0xff, 0x6c, 0x0a, 0x08,
+	0x20, 0x64, 0xca, 0x18,
+	0xff, 0x6c, 0x08, 0x0c,
+	0x40, 0x0b, 0x96, 0x68,
+	0x20, 0x6a, 0x16, 0x00,
+	0xf0, 0x19, 0x6e, 0x08,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x08, 0x6a, 0x66, 0x58,
+	0x08, 0x6a, 0x68, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x12, 0x6a, 0x00, 0x00,
+	0x40, 0x6a, 0x16, 0x00,
+	0xff, 0x3e, 0x20, 0x09,
+	0xff, 0xba, 0x7c, 0x08,
+	0xff, 0xa1, 0x6e, 0x08,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x08, 0x6a, 0x66, 0x58,
+	0x80, 0x6a, 0x68, 0x00,
+	0x80, 0x36, 0x6c, 0x00,
+	0x00, 0x65, 0x9e, 0x5b,
+	0xff, 0x3d, 0xc8, 0x08,
+	0xbf, 0x64, 0xe2, 0x78,
+	0x80, 0x64, 0xac, 0x71,
+	0xa0, 0x64, 0xdc, 0x71,
+	0xc0, 0x64, 0xd4, 0x71,
+	0xe0, 0x64, 0x1c, 0x72,
+	0x01, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0xf7, 0x11, 0x22, 0x08,
+	0x00, 0x65, 0xca, 0x58,
+	0xff, 0x06, 0xd4, 0x08,
+	0xf7, 0x01, 0x02, 0x08,
+	0x09, 0x0c, 0xc4, 0x78,
+	0x08, 0x0c, 0x0c, 0x68,
+	0x01, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0x26, 0x09,
+	0x02, 0x6a, 0x08, 0x30,
+	0xff, 0x6a, 0x08, 0x08,
+	0xdf, 0x01, 0x02, 0x08,
+	0x01, 0x6a, 0x7a, 0x00,
+	0xff, 0x6a, 0x6c, 0x0c,
+	0x04, 0x14, 0x10, 0x31,
+	0x03, 0xa9, 0x18, 0x31,
+	0x03, 0xa9, 0x10, 0x30,
+	0x08, 0x6a, 0xcc, 0x00,
+	0xa9, 0x6a, 0xb4, 0x5b,
+	0x00, 0x65, 0x02, 0x41,
+	0xa8, 0x6a, 0x6a, 0x00,
+	0x79, 0x6a, 0x6a, 0x00,
+	0x40, 0x3d, 0xea, 0x68,
+	0x04, 0x35, 0x6a, 0x00,
+	0x00, 0x65, 0x0e, 0x5b,
+	0x80, 0x6a, 0xd4, 0x01,
+	0x10, 0x36, 0xd6, 0x68,
+	0x10, 0x36, 0x6c, 0x00,
+	0x07, 0xac, 0x10, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0x05, 0xa3, 0x70, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xac, 0x6a, 0xac, 0x5b,
+	0x00, 0x65, 0xa6, 0x5b,
+	0x38, 0x6a, 0xcc, 0x00,
+	0xa3, 0x6a, 0xb0, 0x5b,
+	0xff, 0x38, 0x12, 0x69,
+	0x80, 0x02, 0x04, 0x00,
+	0xe7, 0x35, 0x6a, 0x08,
+	0x03, 0x69, 0x18, 0x31,
+	0x03, 0x69, 0x10, 0x30,
+	0xff, 0x6a, 0x10, 0x00,
+	0xff, 0x6a, 0x12, 0x00,
+	0xff, 0x6a, 0x14, 0x00,
+	0x01, 0x38, 0x18, 0x61,
+	0xbf, 0x35, 0x6a, 0x08,
+	0x02, 0x6a, 0xf8, 0x01,
+	0xff, 0x69, 0xca, 0x08,
+	0xff, 0x35, 0x26, 0x09,
+	0x04, 0x0b, 0x1c, 0x69,
+	0x04, 0x0b, 0x28, 0x69,
+	0x10, 0x0c, 0x1e, 0x79,
+	0x04, 0x0b, 0x28, 0x69,
+	0xff, 0x6a, 0xca, 0x08,
+	0x00, 0x35, 0xee, 0x5a,
+	0x80, 0x02, 0x7c, 0x69,
+	0xff, 0x65, 0x6c, 0x79,
+	0xff, 0x38, 0x70, 0x18,
+	0xff, 0x38, 0x6c, 0x79,
+	0x80, 0xea, 0x48, 0x61,
+	0xef, 0x38, 0xc8, 0x18,
+	0x80, 0x6a, 0xc8, 0x00,
+	0x00, 0x65, 0x3a, 0x49,
+	0x33, 0x38, 0xc8, 0x28,
+	0xff, 0x64, 0xd0, 0x09,
+	0x04, 0x39, 0xc0, 0x31,
+	0x09, 0x6a, 0xd6, 0x01,
+	0x80, 0xeb, 0x40, 0x79,
+	0xf7, 0xeb, 0xd6, 0x09,
+	0x08, 0xeb, 0x44, 0x69,
+	0x01, 0x6a, 0xd6, 0x01,
+	0x08, 0xe9, 0x10, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x39, 0x6a, 0xb2, 0x5b,
+	0x08, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x0d, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x30, 0x5c,
+	0x88, 0x6a, 0x20, 0x5c,
+	0x00, 0x65, 0xa6, 0x5b,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x08, 0x39, 0x72, 0x18,
+	0x00, 0x3a, 0x74, 0x20,
+	0x01, 0x0c, 0x64, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0xff, 0x35, 0x26, 0x09,
+	0x04, 0x0b, 0x6a, 0x69,
+	0x00, 0x65, 0x84, 0x59,
+	0x03, 0x08, 0x52, 0x31,
+	0xff, 0x38, 0x50, 0x09,
+	0xff, 0x08, 0x52, 0x09,
+	0xff, 0x09, 0x54, 0x09,
+	0xff, 0x0a, 0x56, 0x09,
+	0xff, 0x38, 0x50, 0x09,
+	0x00, 0x65, 0xaa, 0x40,
+	0x00, 0x65, 0x84, 0x59,
+	0x7f, 0x02, 0x04, 0x08,
+	0xe1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0x04, 0x93, 0x9a, 0x69,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0x88, 0x69,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0x8a, 0x79,
+	0x01, 0x94, 0x8a, 0x79,
+	0x01, 0x94, 0x8a, 0x79,
+	0x01, 0x94, 0x8a, 0x79,
+	0x01, 0x94, 0x8a, 0x79,
+	0x01, 0x94, 0x8a, 0x79,
+	0x10, 0x94, 0x98, 0x69,
+	0x7f, 0x05, 0xa0, 0x69,
+	0x02, 0x03, 0xa0, 0x79,
+	0x11, 0x0c, 0x9c, 0x79,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xa2, 0x69,
+	0x03, 0x08, 0x52, 0x31,
+	0xff, 0x38, 0x50, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x0e, 0x5b,
+	0x05, 0xb4, 0x10, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xb4, 0x6a, 0xb0, 0x5b,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x00, 0x65, 0xa6, 0x5b,
+	0x3d, 0x6a, 0xee, 0x5a,
+	0xac, 0x6a, 0x26, 0x01,
+	0x04, 0x0b, 0xc2, 0x69,
+	0x04, 0x0b, 0xc8, 0x69,
+	0x10, 0x0c, 0xc4, 0x79,
+	0x02, 0x03, 0xcc, 0x79,
+	0x11, 0x0c, 0xc8, 0x79,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xce, 0x69,
+	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x00, 0x65, 0x0e, 0x5b,
+	0xff, 0x06, 0x44, 0x09,
+	0x00, 0x65, 0xaa, 0x40,
+	0x10, 0x3d, 0x06, 0x00,
+	0xff, 0x34, 0xca, 0x08,
+	0x80, 0x65, 0x00, 0x62,
+	0x0f, 0xa1, 0xca, 0x08,
+	0x07, 0xa1, 0xca, 0x08,
+	0x40, 0xa0, 0xc8, 0x08,
+	0x00, 0x65, 0xca, 0x00,
+	0x80, 0x65, 0xca, 0x00,
+	0x80, 0xa0, 0xf0, 0x79,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0x02, 0x42,
+	0x20, 0xa0, 0x08, 0x7a,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0x9e, 0x5b,
+	0xa0, 0x3d, 0x10, 0x62,
+	0x23, 0xa0, 0x0c, 0x08,
+	0x00, 0x65, 0x9e, 0x5b,
+	0xa0, 0x3d, 0x10, 0x62,
+	0x00, 0xb9, 0x08, 0x42,
+	0xff, 0x65, 0x08, 0x62,
+	0xa1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x10, 0x51, 0x10, 0x72,
+	0x40, 0x6a, 0x18, 0x00,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0x9e, 0x5b,
+	0xa0, 0x3d, 0xda, 0x71,
+	0x40, 0x6a, 0x18, 0x00,
+	0xff, 0x34, 0xa6, 0x08,
+	0x80, 0x34, 0x18, 0x62,
+	0x7f, 0xa0, 0x40, 0x09,
+	0x08, 0x6a, 0x68, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x64, 0x6a, 0xe4, 0x5a,
+	0x80, 0x64, 0x8e, 0x6a,
+	0x04, 0x64, 0x70, 0x72,
+	0x02, 0x64, 0x76, 0x72,
+	0x00, 0x6a, 0x38, 0x72,
+	0x03, 0x64, 0x8a, 0x72,
+	0x01, 0x64, 0x6c, 0x72,
+	0x07, 0x64, 0xcc, 0x72,
+	0x08, 0x64, 0x34, 0x72,
+	0x23, 0x64, 0xd0, 0x72,
+	0x11, 0x6a, 0x22, 0x01,
+	0x07, 0x6a, 0xd6, 0x5a,
+	0xff, 0x06, 0xd4, 0x08,
+	0x00, 0x65, 0xaa, 0x40,
+	0xff, 0xa8, 0x3c, 0x6a,
+	0xff, 0xa2, 0x54, 0x7a,
+	0x01, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xca, 0x5b,
+	0xff, 0xa2, 0x54, 0x7a,
+	0x71, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x40, 0x51, 0x54, 0x62,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xca, 0x5b,
+	0xff, 0x3e, 0x74, 0x09,
+	0xff, 0x90, 0x7c, 0x08,
+	0x00, 0x65, 0x4e, 0x58,
+	0x00, 0x65, 0xbc, 0x40,
+	0x20, 0xa0, 0x5c, 0x6a,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0x6a, 0x74, 0x5b,
+	0xff, 0x6a, 0x8a, 0x5b,
+	0xff, 0xf8, 0xc8, 0x08,
+	0xff, 0x4f, 0xc8, 0x08,
+	0x01, 0x6a, 0x74, 0x5b,
+	0x00, 0xb9, 0x8a, 0x5b,
+	0x01, 0x4f, 0x9e, 0x18,
+	0x02, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x38, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x41, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0x04, 0xa0, 0x40, 0x01,
+	0x00, 0x65, 0x50, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x10, 0x36, 0x34, 0x7a,
+	0x05, 0x38, 0x46, 0x31,
+	0x04, 0x14, 0x58, 0x31,
+	0x03, 0xa9, 0x60, 0x31,
+	0xa3, 0x6a, 0xcc, 0x00,
+	0x38, 0x6a, 0xb0, 0x5b,
+	0xac, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xb2, 0x5b,
+	0xa9, 0x6a, 0xb4, 0x5b,
+	0x00, 0x65, 0x34, 0x42,
+	0xef, 0x36, 0x6c, 0x08,
+	0x00, 0x65, 0x34, 0x42,
+	0x0f, 0x64, 0xc8, 0x08,
+	0x07, 0x64, 0xc8, 0x08,
+	0x00, 0x37, 0x6e, 0x00,
+	0xff, 0x6a, 0xa4, 0x00,
+	0x00, 0x65, 0x44, 0x5b,
+	0xff, 0x51, 0xa0, 0x72,
+	0x20, 0x36, 0xaa, 0x7a,
+	0x00, 0x90, 0x32, 0x5b,
+	0x00, 0x65, 0xac, 0x42,
+	0xff, 0x06, 0xd4, 0x08,
+	0x00, 0x65, 0x9e, 0x5b,
+	0xe0, 0x3d, 0xc6, 0x62,
+	0x20, 0x12, 0xc6, 0x62,
+	0x51, 0x6a, 0xda, 0x5a,
+	0x00, 0x65, 0x2c, 0x5b,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0xa1, 0xbe, 0x62,
+	0x04, 0xa0, 0xbe, 0x7a,
+	0xfb, 0xa0, 0x40, 0x09,
+	0x80, 0x36, 0x6c, 0x00,
+	0x80, 0xa0, 0x34, 0x7a,
+	0x7f, 0xa0, 0x40, 0x09,
+	0xff, 0x6a, 0xd6, 0x5a,
+	0x00, 0x65, 0x34, 0x42,
+	0x04, 0xa0, 0xc4, 0x7a,
+	0x00, 0x65, 0x50, 0x5c,
+	0x00, 0x65, 0xc6, 0x42,
+	0x00, 0x65, 0x38, 0x5c,
+	0x31, 0x6a, 0x22, 0x01,
+	0x0c, 0x6a, 0xd6, 0x5a,
+	0x00, 0x65, 0x34, 0x42,
+	0x61, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x34, 0x42,
+	0x51, 0x6a, 0xda, 0x5a,
+	0x51, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x34, 0x42,
+	0x10, 0x3d, 0x06, 0x00,
+	0xff, 0x65, 0x68, 0x0c,
+	0xff, 0x06, 0xd4, 0x08,
+	0x01, 0x0c, 0xdc, 0x7a,
+	0x04, 0x0c, 0xde, 0x6a,
+	0xe0, 0x03, 0x7a, 0x08,
+	0xe0, 0x3d, 0xea, 0x62,
+	0xff, 0x65, 0xcc, 0x08,
+	0xff, 0x12, 0xda, 0x0c,
+	0xff, 0x06, 0xd4, 0x0c,
+	0xd1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0xff, 0x65, 0x26, 0x09,
+	0x01, 0x0b, 0xfe, 0x6a,
+	0x10, 0x0c, 0xf0, 0x7a,
+	0x04, 0x0b, 0xf8, 0x6a,
+	0xff, 0x6a, 0xca, 0x08,
+	0x04, 0x93, 0xfc, 0x6a,
+	0x01, 0x94, 0xfa, 0x7a,
+	0x10, 0x94, 0xfc, 0x6a,
+	0x80, 0x3d, 0x02, 0x73,
+	0x0f, 0x04, 0x06, 0x6b,
+	0x02, 0x03, 0x06, 0x7b,
+	0x11, 0x0c, 0x02, 0x7b,
+	0xc7, 0x93, 0x26, 0x09,
+	0xff, 0x99, 0xd4, 0x08,
+	0x38, 0x93, 0x08, 0x6b,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x80, 0x36, 0x0c, 0x6b,
+	0x21, 0x6a, 0x22, 0x05,
+	0xff, 0x65, 0x20, 0x09,
+	0xff, 0x51, 0x1a, 0x63,
+	0xff, 0x37, 0xc8, 0x08,
+	0xa1, 0x6a, 0x26, 0x43,
+	0xff, 0x51, 0xc8, 0x08,
+	0xb9, 0x6a, 0x26, 0x43,
+	0xff, 0x90, 0xa4, 0x08,
+	0xff, 0xba, 0x2a, 0x73,
+	0xff, 0xba, 0x20, 0x09,
+	0xff, 0x65, 0xca, 0x18,
+	0x00, 0x6c, 0x1e, 0x63,
+	0xff, 0x90, 0xca, 0x0c,
+	0xff, 0x6a, 0xca, 0x04,
+	0x20, 0x36, 0x3e, 0x7b,
+	0x00, 0x90, 0x12, 0x5b,
+	0xff, 0x65, 0x3e, 0x73,
+	0xff, 0x52, 0x3c, 0x73,
+	0xff, 0xba, 0xcc, 0x08,
+	0xff, 0x52, 0x20, 0x09,
+	0xff, 0x66, 0x74, 0x09,
+	0xff, 0x65, 0x20, 0x0d,
+	0xff, 0xba, 0x7e, 0x0c,
+	0x00, 0x6a, 0x3e, 0x5c,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0x51, 0xca, 0x43,
+	0xff, 0x3f, 0x98, 0x73,
+	0xff, 0x6a, 0xa2, 0x00,
+	0x00, 0x3f, 0x12, 0x5b,
+	0xff, 0x65, 0x98, 0x73,
+	0x20, 0x36, 0x6c, 0x00,
+	0x20, 0xa0, 0x52, 0x6b,
+	0xff, 0xb9, 0xa2, 0x0c,
+	0xff, 0x6a, 0xa2, 0x04,
+	0xff, 0x65, 0xa4, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xbe, 0x5b,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xd6, 0x01,
+	0x80, 0xeb, 0x5e, 0x7b,
+	0x01, 0x6a, 0xd6, 0x01,
+	0x01, 0xe9, 0xa4, 0x34,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xbe, 0x5b,
+	0x01, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x0d, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0x30, 0x5c,
+	0xff, 0x99, 0xa4, 0x0c,
+	0xff, 0x65, 0xa4, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xbe, 0x5b,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x05,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xbe, 0x5b,
+	0x01, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x01, 0x6a, 0x26, 0x05,
+	0x01, 0x65, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0x8e, 0x7b,
+	0xff, 0x6a, 0xdc, 0x0d,
+	0xff, 0x65, 0x32, 0x09,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x30, 0x44,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0x6a, 0x54, 0x5b,
+	0xff, 0x52, 0xa2, 0x0c,
+	0x01, 0x0c, 0x9e, 0x7b,
+	0x04, 0x0c, 0x9e, 0x6b,
+	0xe0, 0x03, 0x06, 0x08,
+	0xe0, 0x03, 0x7a, 0x0c,
+	0xff, 0x8c, 0x10, 0x08,
+	0xff, 0x8d, 0x12, 0x08,
+	0xff, 0x8e, 0x14, 0x0c,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x0c,
+	0x3d, 0x64, 0xa4, 0x28,
+	0x55, 0x64, 0xc8, 0x28,
+	0x00, 0x6c, 0xda, 0x18,
+	0xff, 0x52, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0x00, 0x6c, 0xda, 0x24,
+	0xff, 0x65, 0xc8, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x41, 0x6a, 0xba, 0x5b,
+	0xff, 0x90, 0xe2, 0x09,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x04, 0x35, 0xdc, 0x7b,
+	0x1d, 0x6a, 0xdc, 0x01,
+	0xdc, 0xee, 0xd8, 0x63,
+	0x00, 0x65, 0xe8, 0x43,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x20, 0xa0, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xe2, 0x7b,
+	0x19, 0x6a, 0xdc, 0x01,
+	0xd8, 0xee, 0xe6, 0x63,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x18, 0xee, 0xea, 0x6b,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x41, 0x6a, 0xba, 0x5b,
+	0x20, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0xff, 0x35, 0x26, 0x09,
+	0x04, 0x35, 0x14, 0x6c,
+	0xa0, 0x6a, 0xca, 0x00,
+	0x20, 0x65, 0xc8, 0x18,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0x00, 0x65, 0x00, 0x64,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x30, 0x5c,
+	0x04, 0x35, 0x0c, 0x7b,
+	0xa0, 0x6a, 0x20, 0x5c,
+	0x00, 0x65, 0x22, 0x5c,
+	0x00, 0x65, 0x22, 0x5c,
+	0x00, 0x65, 0x22, 0x44,
+	0xff, 0x65, 0xcc, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x0c,
+	0x08, 0x94, 0x30, 0x7c,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x34, 0x6c,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0xff, 0x40, 0x74, 0x09,
+	0xff, 0x90, 0x80, 0x08,
+	0xff, 0x6a, 0x72, 0x05,
+	0xff, 0x40, 0x4c, 0x64,
+	0xff, 0x3f, 0x44, 0x64,
+	0xff, 0x6a, 0xca, 0x04,
+	0xff, 0x3f, 0x20, 0x09,
+	0x01, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xca, 0x5b,
+	0xff, 0xba, 0x7e, 0x0c,
+	0xff, 0x40, 0x20, 0x09,
+	0xff, 0xba, 0x80, 0x0c,
+	0xff, 0x3f, 0x74, 0x09,
+	0xff, 0x90, 0x7e, 0x0c,
+};
+
+static int aic7xxx_patch12_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch12_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_WIDE) != 0);
+}
+
+static int aic7xxx_patch11_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch11_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA2) == 0);
+}
+
+static int aic7xxx_patch10_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch10_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_CMD_CHAN) == 0);
+}
+
+static int aic7xxx_patch9_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch9_func(struct aic7xxx_host *p)
+{
+	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+}
+
+static int aic7xxx_patch8_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch8_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA) != 0);
+}
+
+static int aic7xxx_patch7_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch7_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA2) != 0);
+}
+
+static int aic7xxx_patch6_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch6_func(struct aic7xxx_host *p)
+{
+	return ((p->flags & AHC_PAGESCBS) == 0);
+}
+
+static int aic7xxx_patch5_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch5_func(struct aic7xxx_host *p)
+{
+	return ((p->flags & AHC_PAGESCBS) != 0);
+}
+
+static int aic7xxx_patch4_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch4_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_QUEUE_REGS) != 0);
+}
+
+static int aic7xxx_patch3_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch3_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_TWIN) != 0);
+}
+
+static int aic7xxx_patch2_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch2_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_QUEUE_REGS) == 0);
+}
+
+static int aic7xxx_patch1_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch1_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_CMD_CHAN) != 0);
+}
+
+static int aic7xxx_patch0_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch0_func(struct aic7xxx_host *p)
+{
+	return (0);
+}
+
+struct sequencer_patch {
+	int		(*patch_func)(struct aic7xxx_host *);
+	unsigned int	begin	   :10,
+			skip_instr :10,
+			skip_patch :12;
+} sequencer_patches[] = {
+	{ aic7xxx_patch1_func, 3, 2, 1 },
+	{ aic7xxx_patch2_func, 7, 1, 1 },
+	{ aic7xxx_patch2_func, 8, 1, 1 },
+	{ aic7xxx_patch3_func, 11, 4, 1 },
+	{ aic7xxx_patch4_func, 16, 3, 2 },
+	{ aic7xxx_patch0_func, 19, 4, 1 },
+	{ aic7xxx_patch5_func, 23, 1, 1 },
+	{ aic7xxx_patch6_func, 26, 1, 1 },
+	{ aic7xxx_patch1_func, 29, 1, 2 },
+	{ aic7xxx_patch0_func, 30, 3, 1 },
+	{ aic7xxx_patch3_func, 39, 4, 1 },
+	{ aic7xxx_patch7_func, 43, 3, 2 },
+	{ aic7xxx_patch0_func, 46, 3, 1 },
+	{ aic7xxx_patch8_func, 52, 7, 1 },
+	{ aic7xxx_patch3_func, 60, 3, 1 },
+	{ aic7xxx_patch7_func, 63, 2, 1 },
+	{ aic7xxx_patch7_func, 102, 1, 2 },
+	{ aic7xxx_patch0_func, 103, 2, 1 },
+	{ aic7xxx_patch7_func, 107, 2, 1 },
+	{ aic7xxx_patch9_func, 109, 1, 1 },
+	{ aic7xxx_patch10_func, 110, 2, 1 },
+	{ aic7xxx_patch7_func, 113, 1, 2 },
+	{ aic7xxx_patch0_func, 114, 1, 1 },
+	{ aic7xxx_patch1_func, 118, 1, 1 },
+	{ aic7xxx_patch1_func, 121, 3, 2 },
+	{ aic7xxx_patch0_func, 124, 5, 1 },
+	{ aic7xxx_patch1_func, 132, 2, 3 },
+	{ aic7xxx_patch7_func, 132, 1, 1 },
+	{ aic7xxx_patch0_func, 134, 3, 1 },
+	{ aic7xxx_patch11_func, 138, 1, 2 },
+	{ aic7xxx_patch0_func, 139, 1, 1 },
+	{ aic7xxx_patch7_func, 140, 7, 2 },
+	{ aic7xxx_patch0_func, 147, 1, 1 },
+	{ aic7xxx_patch1_func, 152, 14, 3 },
+	{ aic7xxx_patch11_func, 165, 1, 1 },
+	{ aic7xxx_patch0_func, 166, 9, 1 },
+	{ aic7xxx_patch7_func, 180, 2, 1 },
+	{ aic7xxx_patch7_func, 182, 1, 1 },
+	{ aic7xxx_patch11_func, 183, 6, 3 },
+	{ aic7xxx_patch1_func, 183, 2, 2 },
+	{ aic7xxx_patch0_func, 185, 4, 1 },
+	{ aic7xxx_patch7_func, 190, 1, 1 },
+	{ aic7xxx_patch7_func, 194, 20, 1 },
+	{ aic7xxx_patch1_func, 215, 3, 3 },
+	{ aic7xxx_patch11_func, 217, 1, 1 },
+	{ aic7xxx_patch0_func, 218, 5, 1 },
+	{ aic7xxx_patch11_func, 223, 1, 2 },
+	{ aic7xxx_patch0_func, 224, 9, 1 },
+	{ aic7xxx_patch12_func, 240, 1, 2 },
+	{ aic7xxx_patch0_func, 241, 1, 1 },
+	{ aic7xxx_patch4_func, 302, 1, 2 },
+	{ aic7xxx_patch0_func, 303, 1, 1 },
+	{ aic7xxx_patch2_func, 306, 1, 1 },
+	{ aic7xxx_patch1_func, 316, 3, 2 },
+	{ aic7xxx_patch0_func, 319, 5, 1 },
+	{ aic7xxx_patch12_func, 327, 1, 2 },
+	{ aic7xxx_patch0_func, 328, 1, 1 },
+	{ aic7xxx_patch5_func, 333, 1, 1 },
+	{ aic7xxx_patch11_func, 375, 15, 1 },
+	{ aic7xxx_patch1_func, 427, 7, 2 },
+	{ aic7xxx_patch0_func, 434, 8, 1 },
+	{ aic7xxx_patch1_func, 443, 4, 2 },
+	{ aic7xxx_patch0_func, 447, 6, 1 },
+	{ aic7xxx_patch1_func, 453, 4, 2 },
+	{ aic7xxx_patch0_func, 457, 3, 1 },
+	{ aic7xxx_patch10_func, 467, 10, 1 },
+	{ aic7xxx_patch1_func, 486, 17, 4 },
+	{ aic7xxx_patch9_func, 494, 4, 2 },
+	{ aic7xxx_patch0_func, 498, 2, 1 },
+	{ aic7xxx_patch0_func, 503, 33, 1 },
+	{ aic7xxx_patch10_func, 536, 4, 1 },
+	{ aic7xxx_patch5_func, 540, 2, 1 },
+	{ aic7xxx_patch5_func, 543, 9, 1 },
+
+};
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/scsi_message.h linux/drivers/scsi/aic7xxx_old/scsi_message.h
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/scsi_message.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/scsi_message.h	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,49 @@
+/* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
+#define MSG_CMDCOMPLETE		0x00 /* M/M */
+#define MSG_EXTENDED		0x01 /* O/O */
+#define MSG_SAVEDATAPOINTER	0x02 /* O/O */
+#define MSG_RESTOREPOINTERS	0x03 /* O/O */
+#define MSG_DISCONNECT		0x04 /* O/O */
+#define MSG_INITIATOR_DET_ERR	0x05 /* M/M */
+#define MSG_ABORT		0x06 /* O/M */
+#define MSG_MESSAGE_REJECT	0x07 /* M/M */
+#define MSG_NOOP		0x08 /* M/M */
+#define MSG_PARITY_ERROR	0x09 /* M/M */
+#define MSG_LINK_CMD_COMPLETE	0x0a /* O/O */
+#define MSG_LINK_CMD_COMPLETEF	0x0b /* O/O */
+#define MSG_BUS_DEV_RESET	0x0c /* O/M */
+#define MSG_ABORT_TAG		0x0d /* O/O */
+#define MSG_CLEAR_QUEUE		0x0e /* O/O */
+#define MSG_INIT_RECOVERY	0x0f /* O/O */
+#define MSG_REL_RECOVERY	0x10 /* O/O */
+#define MSG_TERM_IO_PROC	0x11 /* O/O */
+
+/* Messages (2 byte) */
+#define MSG_SIMPLE_Q_TAG	0x20 /* O/O */
+#define MSG_HEAD_OF_Q_TAG	0x21 /* O/O */
+#define MSG_ORDERED_Q_TAG	0x22 /* O/O */
+#define MSG_IGN_WIDE_RESIDUE	0x23 /* O/O */
+
+/* Identify message */		     /* M/M */	
+#define MSG_IDENTIFYFLAG	0x80 
+#define MSG_IDENTIFY_DISCFLAG	0x40 
+#define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
+#define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
+
+/* Extended messages (opcode and length) */
+#define MSG_EXT_SDTR		0x01
+#define MSG_EXT_SDTR_LEN	0x03
+
+#define MSG_EXT_WDTR		0x03
+#define MSG_EXT_WDTR_LEN	0x02
+#define MSG_EXT_WDTR_BUS_8_BIT	0x00
+#define MSG_EXT_WDTR_BUS_16_BIT	0x01
+#define MSG_EXT_WDTR_BUS_32_BIT	0x02
+
+#define MSG_EXT_PPR     0x04
+#define MSG_EXT_PPR_LEN	0x06
+#define MSG_EXT_PPR_OPTION_ST 0x00
+#define MSG_EXT_PPR_OPTION_DT_CRC 0x02
+#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03
+#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04
+#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old/sequencer.h linux/drivers/scsi/aic7xxx_old/sequencer.h
--- v2.4.2/linux/drivers/scsi/aic7xxx_old/sequencer.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old/sequencer.h	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,135 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
+ */
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+struct ins_format1 {
+	unsigned int
+			immediate	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+};
+
+struct ins_format2 {
+	unsigned int
+			shift_control	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+};
+
+struct ins_format3 {
+	unsigned int
+			immediate	: 8,
+			source		: 9,
+			address		: 10,
+			opcode		: 4,
+			parity		: 1;
+};
+#elif defined(__BIG_ENDIAN_BITFIELD)
+struct ins_format1 {
+	unsigned int
+			parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			immediate	: 8;
+};
+
+struct ins_format2 {
+	unsigned int
+			parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			shift_control	: 8;
+};
+
+struct ins_format3 {
+	unsigned int
+			parity		: 1,
+			opcode		: 4,
+			address		: 10,
+			source		: 9,
+			immediate	: 8;
+};
+#endif
+
+union ins_formats {
+		struct ins_format1 format1;
+		struct ins_format2 format2;
+		struct ins_format3 format3;
+		unsigned char	   bytes[4];
+		unsigned int	   integer;
+};
+struct instruction {
+	union	ins_formats format;
+	unsigned int	srcline;
+	struct symbol *patch_label;
+  struct {
+    struct instruction *stqe_next;
+  } links;
+};
+
+#define	AIC_OP_OR	0x0
+#define	AIC_OP_AND	0x1
+#define AIC_OP_XOR	0x2
+#define	AIC_OP_ADD	0x3
+#define	AIC_OP_ADC	0x4
+#define	AIC_OP_ROL	0x5
+#define	AIC_OP_BMOV	0x6
+
+#define	AIC_OP_JMP	0x8
+#define AIC_OP_JC	0x9
+#define AIC_OP_JNC	0xa
+#define AIC_OP_CALL	0xb
+#define	AIC_OP_JNE	0xc
+#define	AIC_OP_JNZ	0xd
+#define	AIC_OP_JE	0xe
+#define	AIC_OP_JZ	0xf
+
+/* Pseudo Ops */
+#define	AIC_OP_SHL	0x10
+#define	AIC_OP_SHR	0x20
+#define	AIC_OP_ROR	0x30
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.4.2/linux/drivers/scsi/aic7xxx_old.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/aic7xxx_old.c	Sun Mar  4 14:30:19 2001
@@ -0,0 +1,12242 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
+ * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
+ * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
+ * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
+ * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
+ * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
+ * ANSI SCSI-2 specification (draft 10c), ...
+ *
+ * --------------------------------------------------------------------------
+ *
+ *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ *  Substantially modified to include support for wide and twin bus
+ *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ *  SCB paging, and other rework of the code.
+ *
+ *  Parts of this driver were also based on the FreeBSD driver by
+ *  Justin T. Gibbs.  His copyright follows:
+ *
+ * --------------------------------------------------------------------------  
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * 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.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ *      $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ *  Thanks also go to (in alphabetical order) the following:
+ *
+ *    Rory Bolt     - Sequencer bug fixes
+ *    Jay Estabrook - Initial DEC Alpha support
+ *    Doug Ledford  - Much needed abort/reset bug fixes
+ *    Kai Makisara  - DMAing of SCBs
+ *
+ *  A Boot time option was also added for not resetting the scsi bus.
+ *
+ *    Form:  aic7xxx=extended
+ *           aic7xxx=no_reset
+ *           aic7xxx=ultra
+ *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
+ *           aic7xxx=verbose
+ *
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
+ *
+ *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
+ *-M*************************************************************************/
+
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@redhat.com>
+ *
+ * Copyright (c) 1997-1999 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accomodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
+ * itself.  A diff between the two version of the driver is now a several
+ * thousand line diff.  Second, in approach to solving the same problem.  The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone.  Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible.  To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver.  He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach.  Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux.  I have no objection to those issues.  My
+ * disagreement is on the needed functionality.  There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics.  Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers.  For the time
+ * being, I see issues such as these as major stumbling blocks to the 
+ * reliability of code based upon such middle ware.  Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code.  My approach is to import the sequencer
+ * code from FreeBSD wholesale.  Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements.  But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State".  Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
+/*
+ * The next three defines are user configurable.  These should be the only
+ * defines a user might need to get in here and change.  There are other
+ * defines buried deeper in the code, but those really shouldn't need touched
+ * under normal conditions.
+ */
+
+/*
+ * AIC7XXX_STRICT_PCI_SETUP
+ *   Should we assume the PCI config options on our controllers are set with
+ *   sane and proper values, or should we be anal about our PCI config
+ *   registers and force them to what we want?  The main advantage to
+ *   defining this option is on non-Intel hardware where the BIOS may not
+ *   have been run to set things up, or if you have one of the BIOSless
+ *   Adaptec controllers, such as a 2910, that don't get set up by the
+ *   BIOS.  However, keep in mind that we really do set the most important
+ *   items in the driver regardless of this setting, this only controls some
+ *   of the more esoteric PCI options on these cards.  In that sense, I
+ *   would default to leaving this off.  However, if people wish to try
+ *   things both ways, that would also help me to know if there are some
+ *   machines where it works one way but not another.
+ *
+ *   -- July 7, 17:09
+ *     OK...I need this on my machine for testing, so the default is to
+ *     leave it defined.
+ *
+ *   -- July 7, 18:49
+ *     I needed it for testing, but it didn't make any difference, so back
+ *     off she goes.
+ *
+ *   -- July 16, 23:04
+ *     I turned it back on to try and compensate for the 2.1.x PCI code
+ *     which no longer relies solely on the BIOS and now tries to set
+ *     things itself.
+ */
+
+#define AIC7XXX_STRICT_PCI_SETUP
+
+/*
+ * AIC7XXX_VERBOSE_DEBUGGING
+ *   This option enables a lot of extra printk();s in the code, surrounded
+ *   by if (aic7xxx_verbose ...) statements.  Executing all of those if
+ *   statements and the extra checks can get to where it actually does have
+ *   an impact on CPU usage and such, as well as code size.  Disabling this
+ *   define will keep some of those from becoming part of the code.
+ *
+ *   NOTE:  Currently, this option has no real effect, I will be adding the
+ *   various #ifdef's in the code later when I've decided a section is
+ *   complete and no longer needs debugging.  OK...a lot of things are now
+ *   surrounded by this define, so turning this off does have an impact.
+ */
+ 
+/*
+ * #define AIC7XXX_VERBOSE_DEBUGGING
+ */
+ 
+#if defined(MODULE) || defined(PCMCIA)
+#include <linux/module.h>
+#endif
+
+#if defined(PCMCIA)
+#  undef MODULE
+#endif
+
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/blk.h>
+#include <linux/tqueue.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "aic7xxx_old/aic7xxx.h"
+
+#include "aic7xxx_old/sequencer.h"
+#include "aic7xxx_old/scsi_message.h"
+#include "aic7xxx_old/aic7xxx_reg.h"
+#include <scsi/scsicam.h>
+
+#include <linux/stat.h>
+#include <linux/malloc.h>        /* for kmalloc() */
+
+#include <linux/config.h>        /* for CONFIG_PCI */
+
+/*
+ * To generate the correct addresses for the controller to issue
+ * on the bus.  Originally added for DEC Alpha support.
+ */
+#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
+
+#define AIC7XXX_C_VERSION  "5.2.1"
+
+#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
+#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
+#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
+#define ALL_TARGETS -1
+#define ALL_CHANNELS -1
+#define ALL_LUNS -1
+#define MAX_TARGETS  16
+#define MAX_LUNS     8
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
+#if defined(__powerpc__) || defined(__i386__)
+#  define MMAPIO
+#endif
+
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+#    define cpuid smp_processor_id()
+#    define DRIVER_LOCK_INIT \
+       spin_lock_init(&p->spin_lock);
+#    define DRIVER_LOCK \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+#  else
+#    define DRIVER_LOCK_INIT
+#    define DRIVER_LOCK
+#    define DRIVER_UNLOCK
+#  endif
+
+/*
+ * You can try raising me if tagged queueing is enabled, or lowering
+ * me if you only have 4 SCBs.
+ */
+#ifdef CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE
+#else
+#define AIC7XXX_CMDS_PER_DEVICE 8
+#endif
+
+/*
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
+ *
+ * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
+ * NOTE: This does affect performance since it has to maintain statistics.
+ */
+#ifdef CONFIG_AIC7XXX_OLD_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
+
+/*
+ * *** Determining commands per LUN ***
+ * 
+ * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
+ * own algorithm to determine the commands/LUN.  If SCB paging is
+ * enabled, which is always now, the default is 8 commands per lun
+ * that indicates it supports tagged queueing.  All non-tagged devices
+ * use an internal queue depth of 3, with no more than one of those
+ * three commands active at one time.
+ */
+
+typedef struct
+{
+  unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Make a define that will tell the driver not to use tagged queueing
+ * by default.
+ */
+#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+                              0, 0, 0, 0, 0, 0, 0, 0}
+#else
+#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
+                              255, 255, 255, 255, 255, 255, 255, 255}
+#endif
+
+/*
+ * Modify this as you see fit for your system.  By setting tag_commands
+ * to 0, the driver will use it's own algorithm for determining the
+ * number of commands to use (see above).  When 255, the driver will
+ * not enable tagged queueing for that particular device.  When positive
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
+ *
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+
+/*
+ * NOTE: The below structure is for reference only, the actual structure
+ *       to modify in order to change things is found after this fake one.
+ *
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
+  {DEFAULT_TAG_COMMANDS},
+  {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+*/
+
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+
+/*
+ * Define an array of board names that can be indexed by aha_type.
+ * Don't forget to change this when changing the types!
+ */
+static const char *board_names[] = {
+  "AIC-7xxx Unknown",                                   /* AIC_NONE */
+  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
+  "Adaptec AIC-7770 SCSI host adapter",                 /* AIC_7770 */
+  "Adaptec AHA-274X SCSI host adapter",                 /* AIC_7771 */
+  "Adaptec AHA-284X SCSI host adapter",                 /* AIC_284x */
+  "Adaptec AIC-7850 SCSI host adapter",                 /* AIC_7850 */
+  "Adaptec AIC-7855 SCSI host adapter",                 /* AIC_7855 */
+  "Adaptec AIC-7860 Ultra SCSI host adapter",           /* AIC_7860 */
+  "Adaptec AHA-2940A Ultra SCSI host adapter",          /* AIC_7861 */
+  "Adaptec AIC-7870 SCSI host adapter",                 /* AIC_7870 */
+  "Adaptec AHA-294X SCSI host adapter",                 /* AIC_7871 */
+  "Adaptec AHA-394X SCSI host adapter",                 /* AIC_7872 */
+  "Adaptec AHA-398X SCSI host adapter",                 /* AIC_7873 */
+  "Adaptec AHA-2944 SCSI host adapter",                 /* AIC_7874 */
+  "Adaptec AIC-7880 Ultra SCSI host adapter",           /* AIC_7880 */
+  "Adaptec AHA-294X Ultra SCSI host adapter",           /* AIC_7881 */
+  "Adaptec AHA-394X Ultra SCSI host adapter",           /* AIC_7882 */
+  "Adaptec AHA-398X Ultra SCSI host adapter",           /* AIC_7883 */
+  "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
+  "Adaptec AHA-2940UW Pro Ultra SCSI host adapter",     /* AIC_7887 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter",           /* AIC_7895 */
+  "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
+  "Adaptec AHA-293X Ultra2 SCSI host adapter",          /* AIC_7890 */
+  "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
+  "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
+  "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
+  "Adaptec AIC-7892 Ultra 160/m SCSI host adapter",     /* AIC_7892 */
+  "Adaptec AIC-7899 Ultra 160/m SCSI host adapter",     /* AIC_7899 */
+};
+
+/*
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW   DID_ERROR
+
+/*
+ *  What we want to do is have the higher level scsi driver requeue
+ *  the command to us. There is no specific driver status for this
+ *  condition, but the higher level scsi driver will requeue the
+ *  command on a DID_BUS_BUSY error.
+ *
+ *  Upon further inspection and testing, it seems that DID_BUS_BUSY
+ *  will *always* retry the command.  We can get into an infinite loop
+ *  if this happens when we really want some sort of counter that
+ *  will automatically abort/reset the command after so many retries.
+ *  Using DID_ERROR will do just that.  (Made by a suggestion by
+ *  Doug Ledford 8/1/96)
+ */
+#define DID_RETRY_COMMAND DID_ERROR
+
+#define HSCSIID        0x07
+#define SCSI_RESET     0x040
+
+/*
+ * EISA/VL-bus stuff
+ */
+#define MINSLOT                1
+#define MAXSLOT                15
+#define SLOTBASE(x)        ((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
+
+/*
+ * Standard EISA Host ID regs  (Offset from slot base)
+ */
+#define AHC_HID0              0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define AHC_HID1              0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define AHC_HID2              0x82   /* product                        */
+#define AHC_HID3              0x83   /* firmware revision              */
+
+/*
+ * AIC-7770 I/O range to reserve for a card
+ */
+#define MINREG                0xC00
+#define MAXREG                0xCFF
+
+#define INTDEF                0x5C      /* Interrupt Definition Register */
+
+/*
+ * AIC-78X0 PCI registers
+ */
+#define        CLASS_PROGIF_REVID        0x08
+#define                DEVREVID        0x000000FFul
+#define                PROGINFC        0x0000FF00ul
+#define                SUBCLASS        0x00FF0000ul
+#define                BASECLASS        0xFF000000ul
+
+#define        CSIZE_LATTIME                0x0C
+#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
+#define                LATTIME                0x0000FF00ul
+
+#define        DEVCONFIG                0x40
+#define                SCBSIZE32        0x00010000ul        /* aic789X only */
+#define                MPORTMODE        0x00000400ul        /* aic7870 only */
+#define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                RAMPSM_ULTRA2    0x00000004
+#define                VOLSENSE         0x00000100ul
+#define                SCBRAMSEL        0x00000080ul
+#define                SCBRAMSEL_ULTRA2 0x00000008
+#define                MRDCEN           0x00000040ul
+#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
+#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
+#define                BERREN           0x00000008ul
+#define                DACEN            0x00000004ul
+#define                STPWLEVEL        0x00000002ul
+#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
+
+#define        SCAMCTL                  0x1a                /* Ultra2 only  */
+#define        CCSCBBADDR               0xf0                /* aic7895/6/7  */
+
+/*
+ * Define the different types of SEEPROMs on aic7xxx adapters
+ * and make it also represent the address size used in accessing
+ * its registers.  The 93C46 chips have 1024 bits organized into
+ * 64 16-bit words, while the 93C56 chips have 2048 bits organized
+ * into 128 16-bit words.  The C46 chips use 6 bits to address
+ * each word, while the C56 and C66 (4096 bits) use 8 bits to
+ * address each word.
+ */
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
+
+/*
+ *
+ * Define the format of the SEEPROM registers (16 bits).
+ *
+ */
+struct seeprom_config {
+
+/*
+ * SCSI ID Configuration Flags
+ */
+#define CFXFER                0x0007      /* synchronous transfer rate */
+#define CFSYNCH               0x0008      /* enable synchronous transfer */
+#define CFDISC                0x0010      /* enable disconnection */
+#define CFWIDEB               0x0020      /* wide bus device (wide card) */
+#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
+#define CFNEWULTRAFORMAT      0x0080      /* Use the Ultra2 SEEPROM format */
+#define CFSTART               0x0100      /* send start unit SCSI command */
+#define CFINCBIOS             0x0200      /* include in BIOS scan */
+#define CFRNFOUND             0x0400      /* report even if not found */
+#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
+#define CFWBCACHEYES          0x4000      /* Enable W-Behind Cache on drive */
+#define CFWBCACHENC           0xc000      /* Don't change W-Behind Cache */
+/* UNUSED                0x3000 */
+  unsigned short device_flags[16];        /* words 0-15 */
+
+/*
+ * BIOS Control Bits
+ */
+#define CFSUPREM        0x0001  /* support all removable drives */
+#define CFSUPREMB       0x0002  /* support removable drives for boot only */
+#define CFBIOSEN        0x0004  /* BIOS enabled */
+/* UNUSED                0x0008 */
+#define CFSM2DRV        0x0010  /* support more than two drives */
+#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
+/* UNUSED                0x0040 */
+#define CFEXTEND        0x0080  /* extended translation enabled */
+/* UNUSED                0xFF00 */
+  unsigned short bios_control;  /* word 16 */
+
+/*
+ * Host Adapter Control Bits
+ */
+#define CFAUTOTERM      0x0001  /* Perform Auto termination */
+#define CFULTRAEN       0x0002  /* Ultra SCSI speed enable (Ultra cards) */
+#define CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
+#define CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
+#define CFSTERM         0x0004  /* SCSI low byte termination */
+#define CFWSTERM        0x0008  /* SCSI high byte termination (wide card) */
+#define CFSPARITY       0x0010  /* SCSI parity */
+#define CF284XSTERM     0x0020  /* SCSI low byte termination (284x cards) */
+#define CFRESETB        0x0040  /* reset SCSI bus at boot */
+#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
+#define CFSEAUTOTERM    0x0400  /* aic7890 Perform SE Auto Term */
+#define CFLVDSTERM      0x0800  /* aic7890 LVD Termination */
+/* UNUSED                0xF280 */
+  unsigned short adapter_control;        /* word 17 */
+
+/*
+ * Bus Release, Host Adapter ID
+ */
+#define CFSCSIID        0x000F                /* host adapter SCSI ID */
+/* UNUSED                0x00F0 */
+#define CFBRTIME        0xFF00                /* bus release time */
+  unsigned short brtime_id;                /* word 18 */
+
+/*
+ * Maximum targets
+ */
+#define CFMAXTARG        0x00FF        /* maximum targets */
+/* UNUSED                0xFF00 */
+  unsigned short max_targets;                /* word 19 */
+
+  unsigned short res_1[11];                /* words 20-30 */
+  unsigned short checksum;                /* word 31 */
+};
+
+#define SELBUS_MASK                0x0a
+#define         SELNARROW        0x00
+#define         SELBUSB                0x08
+#define SINGLE_BUS                0x00
+
+#define SCB_TARGET(scb)         \
+       (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb)            \
+       ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb)   \
+       (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
+
+/*
+ * If an error occurs during a data transfer phase, run the command
+ * to completion - it's easier that way - making a note of the error
+ * condition in this location. This then will modify a DID_OK status
+ * into an appropriate error for the higher-level SCSI code.
+ */
+#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
+
+/*
+ * Keep track of the targets returned status.
+ */
+#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
+
+/*
+ * The position of the SCSI commands scb within the scb array.
+ */
+#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
+
+/*
+ * The stored DMA mapping for single-buffer data transfers.
+ */
+#define aic7xxx_mapping(cmd)	     ((cmd)->SCp.phase)
+
+/*
+ * So we can keep track of our host structs
+ */
+static struct aic7xxx_host *first_aic7xxx = NULL;
+
+/*
+ * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
+ * in the scatter-gather lists.  We need to convert the virtual
+ * addresses to physical addresses.
+ */
+struct hw_scatterlist {
+  unsigned int address;
+  unsigned int length;
+};
+
+/*
+ * Maximum number of SG segments these cards can support.
+ */
+#define        AIC7XXX_MAX_SG 128
+
+/*
+ * The maximum number of SCBs we could have for ANY type
+ * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ * SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB        255
+
+
+struct aic7xxx_hwscb {
+/* ------------    Begin hardware supported fields    ---------------- */
+/* 0*/  unsigned char control;
+/* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
+/* 2*/  unsigned char target_status;
+/* 3*/  unsigned char SG_segment_count;
+/* 4*/  unsigned int  SG_list_pointer;
+/* 8*/  unsigned char residual_SG_segment_count;
+/* 9*/  unsigned char residual_data_count[3];
+/*12*/  unsigned int  data_pointer;
+/*16*/  unsigned int  data_count;
+/*20*/  unsigned int  SCSI_cmd_pointer;
+/*24*/  unsigned char SCSI_cmd_length;
+/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
+                                     * Also used as the tag for tagged I/O
+                                     */
+#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
+                                     * via PIO to initialize a transaction.
+                                     */
+/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
+                                     * or disconnected down in the sequencer.
+                                     */
+/*27*/  unsigned char prev;
+/*28*/  unsigned int pad;           /*
+                                     * Unused by the kernel, but we require
+                                     * the padding so that the array of
+                                     * hardware SCBs is alligned on 32 byte
+                                     * boundaries so the sequencer can index
+                                     */
+};
+
+typedef enum {
+        SCB_FREE                = 0x0000,
+        SCB_WAITINGQ            = 0x0002,
+        SCB_ACTIVE              = 0x0004,
+        SCB_SENSE               = 0x0008,
+        SCB_ABORT               = 0x0010,
+        SCB_DEVICE_RESET        = 0x0020,
+        SCB_RESET               = 0x0040,
+        SCB_RECOVERY_SCB        = 0x0080,
+        SCB_MSGOUT_PPR          = 0x0100,
+        SCB_MSGOUT_SENT         = 0x0200,
+        SCB_MSGOUT_SDTR         = 0x0400,
+        SCB_MSGOUT_WDTR         = 0x0800,
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_PPR |
+                                  SCB_MSGOUT_SENT | 
+                                  SCB_MSGOUT_SDTR |
+                                  SCB_MSGOUT_WDTR,
+        SCB_QUEUED_ABORT        = 0x1000,
+        SCB_QUEUED_FOR_DONE     = 0x2000,
+        SCB_WAS_BUSY            = 0x4000
+} scb_flag_type;
+
+typedef enum {
+        AHC_FNONE                 = 0x00000000,
+        AHC_PAGESCBS              = 0x00000001,
+        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
+        AHC_USEDEFAULTS           = 0x00000004,
+        AHC_INDIRECT_PAGING       = 0x00000008,
+        AHC_CHNLB                 = 0x00000020,
+        AHC_CHNLC                 = 0x00000040,
+        AHC_EXTEND_TRANS_A        = 0x00000100,
+        AHC_EXTEND_TRANS_B        = 0x00000200,
+        AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_SE_LOW       = 0x00000400,
+        AHC_TERM_ENB_B            = 0x00000800,
+        AHC_TERM_ENB_SE_HIGH      = 0x00000800,
+        AHC_HANDLING_REQINITS     = 0x00001000,
+        AHC_TARGETMODE            = 0x00002000,
+        AHC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+        AHC_MOTHERBOARD           = 0x00020000,
+        AHC_NO_STPWEN             = 0x00040000,
+        AHC_RESET_DELAY           = 0x00080000,
+        AHC_A_SCANNED             = 0x00100000,
+        AHC_B_SCANNED             = 0x00200000,
+        AHC_MULTI_CHANNEL         = 0x00400000,
+        AHC_BIOS_ENABLED          = 0x00800000,
+        AHC_SEEPROM_FOUND         = 0x01000000,
+        AHC_TERM_ENB_LVD          = 0x02000000,
+        AHC_ABORT_PENDING         = 0x04000000,
+        AHC_RESET_PENDING         = 0x08000000,
+#define AHC_IN_ISR_BIT              28
+        AHC_IN_ISR                = 0x10000000,
+        AHC_IN_ABORT              = 0x20000000,
+        AHC_IN_RESET              = 0x40000000,
+        AHC_EXTERNAL_SRAM         = 0x80000000
+} ahc_flag_type;
+
+typedef enum {
+  AHC_NONE             = 0x0000,
+  AHC_CHIPID_MASK      = 0x00ff,
+  AHC_AIC7770          = 0x0001,
+  AHC_AIC7850          = 0x0002,
+  AHC_AIC7860          = 0x0003,
+  AHC_AIC7870          = 0x0004,
+  AHC_AIC7880          = 0x0005,
+  AHC_AIC7890          = 0x0006,
+  AHC_AIC7895          = 0x0007,
+  AHC_AIC7896          = 0x0008,
+  AHC_AIC7892          = 0x0009,
+  AHC_AIC7899          = 0x000a,
+  AHC_VL               = 0x0100,
+  AHC_EISA             = 0x0200,
+  AHC_PCI              = 0x0400,
+} ahc_chip;
+
+typedef enum {
+  AHC_FENONE           = 0x0000,
+  AHC_ULTRA            = 0x0001,
+  AHC_ULTRA2           = 0x0002,
+  AHC_WIDE             = 0x0004,
+  AHC_TWIN             = 0x0008,
+  AHC_MORE_SRAM        = 0x0010,
+  AHC_CMD_CHAN         = 0x0020,
+  AHC_QUEUE_REGS       = 0x0040,
+  AHC_SG_PRELOAD       = 0x0080,
+  AHC_SPIOCAP          = 0x0100,
+  AHC_ULTRA3           = 0x0200,
+  AHC_NEW_AUTOTERM     = 0x0400,
+  AHC_AIC7770_FE       = AHC_FENONE,
+  AHC_AIC7850_FE       = AHC_SPIOCAP,
+  AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
+  AHC_AIC7870_FE       = AHC_FENONE,
+  AHC_AIC7880_FE       = AHC_ULTRA,
+  AHC_AIC7890_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|
+                         AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM,
+  AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
+  AHC_AIC7896_FE       = AHC_AIC7890_FE,
+  AHC_AIC7892_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
+  AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
+} ahc_feature;
+
+#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset)
+
+struct aic7xxx_scb_dma {
+	unsigned long	       dma_offset;    /* Correction you have to add
+					       * to virtual address to get
+					       * dma handle in this region */
+	dma_addr_t	       dma_address;   /* DMA handle of the start,
+					       * for unmap */
+	unsigned int	       dma_len;	      /* DMA length */
+};
+
+struct aic7xxx_scb {
+        struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
+        Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
+        struct aic7xxx_scb    *q_next;        /* next scb in queue */
+        volatile scb_flag_type flags;         /* current state of scb */
+        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          tag_action;
+        unsigned char          sg_count;
+        unsigned char          *sense_cmd;    /*
+                                               * Allocate 6 characters for
+                                               * sense command.
+                                               */
+	unsigned char	       *cmnd;
+        unsigned int           sg_length; /* We init this during buildscb so we
+                                           * don't have to calculate anything
+                                           * during underflow/overflow/stat code
+                                           */
+        void                  *kmalloc_ptr;
+	struct aic7xxx_scb_dma *scb_dma;
+};
+
+/*
+ * Define a linked list of SCBs.
+ */
+typedef struct {
+  struct aic7xxx_scb *head;
+  struct aic7xxx_scb *tail;
+} scb_queue_type;
+
+static struct {
+  unsigned char errno;
+  const char *errmesg;
+} hard_error[] = {
+  { ILLHADDR,  "Illegal Host Access" },
+  { ILLSADDR,  "Illegal Sequencer Address referenced" },
+  { ILLOPCODE, "Illegal Opcode in sequencer program" },
+  { SQPARERR,  "Sequencer Ram Parity Error" },
+  { DPARERR,   "Data-Path Ram Parity Error" },
+  { MPARERR,   "Scratch Ram/SCB Array Ram Parity Error" },
+  { PCIERRSTAT,"PCI Error detected" },
+  { CIOPARERR, "CIOBUS Parity Error" }
+};
+
+static unsigned char
+generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
+
+typedef struct {
+  scb_queue_type free_scbs;        /*
+                                    * SCBs assigned to free slot on
+                                    * card (no paging required)
+                                    */
+  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
+  struct aic7xxx_hwscb *hscbs;
+  unsigned char  numscbs;          /* current number of scbs */
+  unsigned char  maxhscbs;         /* hardware scbs */
+  unsigned char  maxscbs;          /* max scbs including pageable scbs */
+  dma_addr_t	 hscbs_dma;	   /* DMA handle to hscbs */
+  unsigned int   hscbs_dma_len;    /* length of the above DMA area */
+  void          *hscb_kmalloc_ptr;
+} scb_data_type;
+
+struct target_cmd {
+  unsigned char mesg_bytes[4];
+  unsigned char command[28];
+};
+
+#define AHC_TRANS_CUR    0x0001
+#define AHC_TRANS_ACTIVE 0x0002
+#define AHC_TRANS_GOAL   0x0004
+#define AHC_TRANS_USER   0x0008
+#define AHC_TRANS_QUITE  0x0010
+typedef struct {
+  unsigned char cur_width;
+  unsigned char goal_width;
+  unsigned char cur_period;
+  unsigned char goal_period;
+  unsigned char cur_offset;
+  unsigned char goal_offset;
+  unsigned char cur_options;
+  unsigned char goal_options;
+  unsigned char user_width;
+  unsigned char user_period;
+  unsigned char user_offset;
+  unsigned char user_options;
+} transinfo_type;
+
+/*
+ * Define a structure used for each host adapter.  Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary.  It's also organized to try and be more
+ * cache line efficient.  Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
+ */
+struct aic7xxx_host {
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
+  /*
+   * We are grouping things here....first, items that get either read or
+   * written with nearly every interrupt
+   */
+  volatile long            flags;
+  ahc_feature              features;         /* chip features */
+  unsigned long            base;             /* card base address */
+  volatile unsigned char  *maddr;            /* memory mapped address */
+  unsigned long            isr_count;        /* Interrupt count */
+  unsigned long            spurious_int;
+  scb_data_type           *scb_data;
+  volatile unsigned short  needdv;
+  volatile unsigned short  needppr;
+  volatile unsigned short  needsdtr;
+  volatile unsigned short  needwdtr;
+  volatile unsigned short  dtr_pending;
+  struct aic7xxx_cmd_queue {
+    Scsi_Cmnd *head;
+    Scsi_Cmnd *tail;
+  } completeq;
+
+  /*
+   * Things read/written on nearly every entry into aic7xxx_queue()
+   */
+  volatile scb_queue_type  waiting_scbs;
+  unsigned short           discenable;       /* Targets allowed to disconnect */
+  unsigned short           tagenable;        /* Targets using tagged I/O */
+  unsigned short           orderedtag;       /* Ordered Q tags allowed */
+  unsigned char            unpause;          /* unpause value for HCNTRL */
+  unsigned char            pause;            /* pause value for HCNTRL */
+  volatile unsigned char   qoutfifonext;
+  volatile unsigned char   activescbs;       /* active scbs */
+  volatile unsigned char   max_activescbs;
+  volatile unsigned char   qinfifonext;
+  volatile unsigned char  *untagged_scbs;
+  volatile unsigned char  *qoutfifo;
+  volatile unsigned char  *qinfifo;
+
+#define  DEVICE_PRESENT                 0x01
+#define  BUS_DEVICE_RESET_PENDING       0x02
+#define  DEVICE_RESET_DELAY             0x04
+#define  DEVICE_PRINT_DTR               0x08
+#define  DEVICE_PARITY_ERROR            0x10
+#define  DEVICE_WAS_BUSY                0x20
+#define  DEVICE_SCSI_3                  0x40
+#define  DEVICE_SCANNED                 0x80
+  volatile unsigned char   dev_flags[MAX_TARGETS];
+  volatile unsigned char   dev_active_cmds[MAX_TARGETS];
+  volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
+  unsigned char            dev_commands_sent[MAX_TARGETS];
+
+  unsigned int             dev_timer_active; /* Which devs have a timer set */
+  struct timer_list        dev_timer;
+  unsigned long            dev_expires[MAX_TARGETS];
+
+  spinlock_t               spin_lock;
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+
+  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
+
+  unsigned int             dev_checksum[MAX_TARGETS];
+  
+  unsigned char            dev_last_queue_full[MAX_TARGETS];
+  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+  unsigned char            dev_max_queue_depth[MAX_TARGETS];
+
+  volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
+
+
+  unsigned char            msg_buf[13];      /* The message for the target */
+  unsigned char            msg_type;
+#define MSG_TYPE_NONE              0x00
+#define MSG_TYPE_INITIATOR_MSGOUT  0x01
+#define MSG_TYPE_INITIATOR_MSGIN   0x02
+  unsigned char            msg_len;          /* Length of message */
+  unsigned char            msg_index;        /* Index into msg_buf array */
+  transinfo_type           transinfo[MAX_TARGETS];
+
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.
+   */
+
+  unsigned int             irq;              /* IRQ for this adapter */
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /* channel B for twin adapters */
+  unsigned int             bios_address;
+  int                      board_name_index;
+  unsigned short           needppr_copy;     /* default config */
+  unsigned short           needsdtr_copy;    /* default config */
+  unsigned short           needwdtr_copy;    /* default config */
+  unsigned short           ultraenb;         /* Ultra mode target list */
+  unsigned short           bios_control;     /* bios control - SEEPROM */
+  unsigned short           adapter_control;  /* adapter control - SEEPROM */
+  struct pci_dev	  *pdev;
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+  struct seeprom_config    sc;
+  unsigned short           sc_type;
+  unsigned short           sc_size;
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
+  struct Scsi_Host        *host;             /* pointer to scsi host */
+  int                      host_no;          /* SCSI host number */
+  unsigned long            mbase;            /* I/O memory address */
+  ahc_chip                 chip;             /* chip type */
+  dma_addr_t		   fifo_dma;	     /* DMA handle for fifo arrays */
+
+  /*
+   * Statistics Kept:
+   *
+   * Total Xfers (count for each command that has a data xfer),
+   * broken down further by reads && writes.
+   *
+   * Binned sizes, writes && reads:
+   *    < 512, 512, 1-2K, 2-4K, 4-8K, 8-16K, 16-32K, 32-64K, 64K-128K, > 128K
+   *
+   * Total amounts read/written above 512 bytes (amts under ignored)
+   *
+   * NOTE: Enabling this feature is likely to cause a noticeable performance
+   * decrease as the accesses into the stats structures blows apart multiple
+   * cache lines and is CPU time consuming.
+   *
+   * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM
+   * and blows apart all sorts of cache lines, I modified this so that we
+   * no longer look at the LUN.  All LUNs now go into the same bin on each
+   * device for stats purposes.
+   */
+  struct aic7xxx_xferstats {
+    long w_total;                          /* total writes */
+    long r_total;                          /* total reads */
+#ifdef AIC7XXX_PROC_STATS
+    long w_bins[8];                       /* binned write */
+    long r_bins[8];                       /* binned reads */
+#endif /* AIC7XXX_PROC_STATS */
+  } stats[MAX_TARGETS];                    /* [(channel << 3)|target] */
+
+#if 0
+  struct target_cmd       *targetcmds;
+  unsigned int             num_targetcmds;
+#endif
+
+};
+
+/*
+ * Valid SCSIRATE values. (p. 3-17)
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
+ */
+#define AHC_SYNCRATE_ULTRA3 0
+#define AHC_SYNCRATE_ULTRA2 1
+#define AHC_SYNCRATE_ULTRA  3
+#define AHC_SYNCRATE_FAST   6
+#define AHC_SYNCRATE_CRC 0x40
+#define AHC_SYNCRATE_SE  0x10
+static struct aic7xxx_syncrate {
+  /* Rates in Ultra mode have bit 8 of sxfr set */
+#define                ULTRA_SXFR 0x100
+  int sxfr_ultra2;
+  int sxfr;
+  unsigned char period;
+  const char *rate[2];
+} aic7xxx_syncrates[] = {
+  { 0x42,  0x000,   9,  {"80.0", "160.0"} },
+  { 0x13,  0x000,  10,  {"40.0", "80.0"} },
+  { 0x14,  0x000,  11,  {"33.0", "66.6"} },
+  { 0x15,  0x100,  12,  {"20.0", "40.0"} },
+  { 0x16,  0x110,  15,  {"16.0", "32.0"} },
+  { 0x17,  0x120,  18,  {"13.4", "26.8"} },
+  { 0x18,  0x000,  25,  {"10.0", "20.0"} },
+  { 0x19,  0x010,  31,  {"8.0",  "16.0"} },
+  { 0x1a,  0x020,  37,  {"6.67", "13.3"} },
+  { 0x1b,  0x030,  43,  {"5.7",  "11.4"} },
+  { 0x10,  0x040,  50,  {"5.0",  "10.0"} },
+  { 0x00,  0x050,  56,  {"4.4",  "8.8" } },
+  { 0x00,  0x060,  62,  {"4.0",  "8.0" } },
+  { 0x00,  0x070,  68,  {"3.6",  "7.2" } },
+  { 0x00,  0x000,  0,   {NULL, NULL}   },
+};
+
+#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
+                        (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+                        ((scb->hscb)->target_channel_lun & 0x07)
+
+#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01),  \
+                        ((cmd->target) & 0x0f), \
+                        ((cmd->lun) & 0x07)
+
+#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
+
+/*
+ * A nice little define to make doing our printks a little easier
+ */
+
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
+
+/*
+ * XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *       cards in the system.  This should be fixed.  Exceptions to this
+ *       rule are noted in the comments.
+ */
+
+
+/*
+ * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
+ * has no effect on any later resets that might occur due to things like
+ * SCSI bus timeouts.
+ */
+static unsigned int aic7xxx_no_reset = 0;
+/*
+ * Certain PCI motherboards will scan PCI devices from highest to lowest,
+ * others scan from lowest to highest, and they tend to do all kinds of
+ * strange things when they come into contact with PCI bridge chips.  The
+ * net result of all this is that the PCI card that is actually used to boot
+ * the machine is very hard to detect.  Most motherboards go from lowest
+ * PCI slot number to highest, and the first SCSI controller found is the
+ * one you boot from.  The only exceptions to this are when a controller
+ * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
+ * from lowest PCI slot number to highest PCI slot number.  We also force
+ * all controllers with their BIOS disabled to the end of the list.  This
+ * works on *almost* all computers.  Where it doesn't work, we have this
+ * option.  Setting this option to non-0 will reverse the order of the sort
+ * to highest first, then lowest, but will still leave cards with their BIOS
+ * disabled at the very end.  That should fix everyone up unless there are
+ * really strange cirumstances.
+ */
+static int aic7xxx_reverse_scan = 0;
+/*
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
+ */
+static unsigned int aic7xxx_extended = 0;
+/*
+ * The IRQ trigger method used on EISA controllers. Does not effect PCI cards.
+ *   -1 = Use detected settings.
+ *    0 = Force Edge triggered mode.
+ *    1 = Force Level triggered mode.
+ */
+static int aic7xxx_irq_trigger = -1;
+/*
+ * This variable is used to override the termination settings on a controller.
+ * This should not be used under normal conditions.  However, in the case
+ * that a controller does not have a readable SEEPROM (so that we can't
+ * read the SEEPROM settings directly) and that a controller has a buggered
+ * version of the cable detection logic, this can be used to force the 
+ * correct termination.  It is preferable to use the manual termination
+ * settings in the BIOS if possible, but some motherboard controllers store
+ * those settings in a format we can't read.  In other cases, auto term
+ * should also work, but the chipset was put together with no auto term
+ * logic (common on motherboard controllers).  In those cases, we have
+ * 32 bits here to work with.  That's good for 8 controllers/channels.  The
+ * bits are organized as 4 bits per channel, with scsi0 getting the lowest
+ * 4 bits in the int.  A 1 in a bit position indicates the termination setting
+ * that corresponds to that bit should be enabled, a 0 is disabled.
+ * It looks something like this:
+ *
+ *    0x0f =  1111-Single Ended Low Byte Termination on/off
+ *            ||\-Single Ended High Byte Termination on/off
+ *            |\-LVD Low Byte Termination on/off
+ *            \-LVD High Byte Termination on/off
+ *
+ * For non-Ultra2 controllers, the upper 2 bits are not important.  So, to
+ * enable both high byte and low byte termination on scsi0, I would need to
+ * make sure that the override_term variable was set to 0x03 (bits 0011).
+ * To make sure that all termination is enabled on an Ultra2 controller at
+ * scsi2 and only high byte termination on scsi1 and high and low byte
+ * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011)
+ *
+ * For the most part, users should never have to use this, that's why I
+ * left it fairly cryptic instead of easy to understand.  If you need it,
+ * most likely someone will be telling you what your's needs to be set to.
+ */
+static int aic7xxx_override_term = -1;
+/*
+ * Certain motherboard chipset controllers tend to screw
+ * up the polarity of the term enable output pin.  Use this variable
+ * to force the correct polarity for your system.  This is a bitfield variable
+ * similar to the previous one, but this one has one bit per channel instead
+ * of four.
+ *    0 = Force the setting to active low.
+ *    1 = Force setting to active high.
+ * Most Adaptec cards are active high, several motherboards are active low.
+ * To force a 2940 card at SCSI 0 to active high and a motherboard 7895
+ * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3
+ * to active high, you would need to set stpwlev=0x9 (bits 1001).
+ *
+ * People shouldn't need to use this, but if you are experiencing lots of
+ * SCSI timeout problems, this may help.  There is one sure way to test what
+ * this option needs to be.  Using a boot floppy to boot the system, configure
+ * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and
+ * if needed then also pass a value to override_term to make sure that the
+ * driver is enabling SCSI termination, then set this variable to either 0
+ * or 1.  When the driver boots, make sure there are *NO* SCSI cables
+ * connected to your controller.  If it finds and inits the controller
+ * without problem, then the setting you passed to stpwlev was correct.  If
+ * the driver goes into a reset loop and hangs the system, then you need the
+ * other setting for this variable.  If neither setting lets the machine
+ * boot then you have definite termination problems that may not be fixable.
+ */
+static int aic7xxx_stpwlev = -1;
+/*
+ * Set this to non-0 in order to force the driver to panic the kernel
+ * and print out debugging info on a SCSI abort or reset cycle.
+ */
+static int aic7xxx_panic_on_abort = 0;
+/*
+ * PCI bus parity checking of the Adaptec controllers.  This is somewhat
+ * dubious at best.  To my knowledge, this option has never actually
+ * solved a PCI parity problem, but on certain machines with broken PCI
+ * chipset configurations, it can generate tons of false error messages.
+ * It's included in the driver for completeness.
+ *   0 = Shut off PCI parity check
+ *  -1 = Normal polarity pci parity checking
+ *   1 = reverse polarity pci parity checking
+ *
+ * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
+ * variable to -1 you would actually want to simply pass the variable
+ * name without a number.  That will invert the 0 which will result in
+ * -1.
+ */
+static int aic7xxx_pci_parity = 0;
+/*
+ * Set this to any non-0 value to cause us to dump the contents of all
+ * the card's registers in a hex dump format tailored to each model of
+ * controller.
+ * 
+ * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION.
+ *       YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES
+ *       ONLY
+ */
+static int aic7xxx_dump_card = 0;
+/*
+ * Set this to a non-0 value to make us dump out the 32 bit instruction
+ * registers on the card after completing the sequencer download.  This
+ * allows the actual sequencer download to be verified.  It is possible
+ * to use this option and still boot up and run your system.  This is
+ * only intended for debugging purposes.
+ */
+static int aic7xxx_dump_sequencer = 0;
+/*
+ * Certain newer motherboards have put new PCI based devices into the
+ * IO spaces that used to typically be occupied by VLB or EISA cards.
+ * This overlap can cause these newer motherboards to lock up when scanned
+ * for older EISA and VLB devices.  Setting this option to non-0 will
+ * cause the driver to skip scanning for any VLB or EISA controllers and
+ * only support the PCI controllers.  NOTE: this means that if the kernel
+ * os compiled with PCI support disabled, then setting this to non-0
+ * would result in never finding any devices :)
+ */
+static int aic7xxx_no_probe = 0;
+/*
+ * On some machines, enabling the external SCB RAM isn't reliable yet.  I
+ * haven't had time to make test patches for things like changing the
+ * timing mode on that external RAM either.  Some of those changes may
+ * fix the problem.  Until then though, we default to external SCB RAM
+ * off and give a command line option to enable it.
+ */
+static int aic7xxx_scbram = 0;
+/*
+ * So that we can set how long each device is given as a selection timeout.
+ * The table of values goes like this:
+ *   0 - 256ms
+ *   1 - 128ms
+ *   2 - 64ms
+ *   3 - 32ms
+ * We default to 64ms because it's fast.  Some old SCSI-I devices need a
+ * longer time.  The final value has to be left shifted by 3, hence 0x10
+ * is the final value.
+ */
+static int aic7xxx_seltime = 0x10;
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+MODULE_PARM(aic7xxx, "s");
+
+/*
+ * Just in case someone uses commas to separate items on the insmod
+ * command line, we define a dummy buffer here to avoid having insmod
+ * write wild stuff into our code segment
+ */
+static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n";
+
+#endif
+
+#define VERBOSE_NORMAL         0x0000
+#define VERBOSE_NEGOTIATION    0x0001
+#define VERBOSE_SEQINT         0x0002
+#define VERBOSE_SCSIINT        0x0004
+#define VERBOSE_PROBE          0x0008
+#define VERBOSE_PROBE2         0x0010
+#define VERBOSE_NEGOTIATION2   0x0020
+#define VERBOSE_MINOR_ERROR    0x0040
+#define VERBOSE_TRACING        0x0080
+#define VERBOSE_ABORT          0x0f00
+#define VERBOSE_ABORT_MID      0x0100
+#define VERBOSE_ABORT_FIND     0x0200
+#define VERBOSE_ABORT_PROCESS  0x0400
+#define VERBOSE_ABORT_RETURN   0x0800
+#define VERBOSE_RESET          0xf000
+#define VERBOSE_RESET_MID      0x1000
+#define VERBOSE_RESET_FIND     0x2000
+#define VERBOSE_RESET_PROCESS  0x4000
+#define VERBOSE_RESET_RETURN   0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+           VERBOSE_PROBE;                     /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * We're going to start putting in function declarations so that order of
+ * functions is no longer important.  As needed, they are added here.
+ *
+ ***************************************************************************/
+
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
+static void aic7xxx_print_card(struct aic7xxx_host *p);
+static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
+static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer);
+#endif
+
+/****************************************************************************
+ *
+ * These functions are now used.  They happen to be wrapped in useless
+ * inb/outb port read/writes around the real reads and writes because it
+ * seems that certain very fast CPUs have a problem dealing with us when
+ * going at full speed.
+ *
+ ***************************************************************************/
+
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+#ifdef MMAPIO
+  unsigned char x;
+  if(p->maddr)
+  {
+    x = readb(p->maddr + port);
+  }
+  else
+  {
+    x = inb(p->base + port);
+  }
+  return(x);
+#else
+  return(inb(p->base + port));
+#endif
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+#ifdef MMAPIO
+  if(p->maddr)
+  {
+    writeb(val, p->maddr + port);
+    mb(); /* locked operation in order to force CPU ordering */
+    readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */
+  }
+  else
+  {
+    outb(val, p->base + port);
+    mb(); /* locked operation in order to force CPU ordering */
+  }
+#else
+  outb(val, p->base + port);
+  mb(); /* locked operation in order to force CPU ordering */
+#endif
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_setup
+ *
+ * Description:
+ *   Handle Linux boot parameters. This routine allows for assigning a value
+ *   to a parameter with a ':' between the parameter and the value.
+ *   ie. aic7xxx=unpause:0x0A,extended
+ *-F*************************************************************************/
+static int
+aic7xxx_setup(char *s)
+{
+  int   i, n;
+  char *p;
+  char *end;
+
+  static struct {
+    const char *name;
+    unsigned int *flag;
+  } options[] = {
+    { "extended",    &aic7xxx_extended },
+    { "no_reset",    &aic7xxx_no_reset },
+    { "irq_trigger", &aic7xxx_irq_trigger },
+    { "verbose",     &aic7xxx_verbose },
+    { "reverse_scan",&aic7xxx_reverse_scan },
+    { "override_term", &aic7xxx_override_term },
+    { "stpwlev", &aic7xxx_stpwlev },
+    { "no_probe", &aic7xxx_no_probe },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
+    { "pci_parity", &aic7xxx_pci_parity },
+    { "dump_card", &aic7xxx_dump_card },
+    { "dump_sequencer", &aic7xxx_dump_sequencer },
+    { "scbram", &aic7xxx_scbram },
+    { "seltime", &aic7xxx_seltime },
+    { "tag_info",    NULL }
+  };
+
+  end = strchr(s, '\0');
+
+  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
+  {
+    for (i = 0; i < NUMBER(options); i++)
+    {
+      n = strlen(options[i].name);
+      if (!strncmp(options[i].name, p, n))
+      {
+        if (!strncmp(p, "tag_info", n))
+        {
+          if (p[n] == ':')
+          {
+            char *base;
+            char *tok, *tok_end, *tok_end2;
+            char tok_list[] = { '.', ',', '{', '}', '\0' };
+            int i, instance = -1, device = -1;
+            unsigned char done = FALSE;
+
+            base = p;
+            tok = base + n + 1;  /* Forward us just past the ':' */
+            tok_end = strchr(tok, '\0');
+            if (tok_end < end)
+              *tok_end = ',';
+            while(!done)
+            {
+              switch(*tok)
+              {
+                case '{':
+                  if (instance == -1)
+                    instance = 0;
+                  else if (device == -1)
+                    device = 0;
+                  tok++;
+                  break;
+                case '}':
+                  if (device != -1)
+                    device = -1;
+                  else if (instance != -1)
+                    instance = -1;
+                  tok++;
+                  break;
+                case ',':
+                case '.':
+                  if (instance == -1)
+                    done = TRUE;
+                  else if (device >= 0)
+                    device++;
+                  else if (instance >= 0)
+                    instance++;
+                  if ( (device >= MAX_TARGETS) || 
+                       (instance >= NUMBER(aic7xxx_tag_info)) )
+                    done = TRUE;
+                  tok++;
+                  if (!done)
+                  {
+                    base = tok;
+                  }
+                  break;
+                case '\0':
+                  done = TRUE;
+                  break;
+                default:
+                  done = TRUE;
+                  tok_end = strchr(tok, '\0');
+                  for(i=0; tok_list[i]; i++)
+                  {
+                    tok_end2 = strchr(tok, tok_list[i]);
+                    if ( (tok_end2) && (tok_end2 < tok_end) )
+                    {
+                      tok_end = tok_end2;
+                      done = FALSE;
+                    }
+                  }
+                  if ( (instance >= 0) && (device >= 0) &&
+                       (instance < NUMBER(aic7xxx_tag_info)) &&
+                       (device < MAX_TARGETS) )
+                    aic7xxx_tag_info[instance].tag_commands[device] =
+                      simple_strtoul(tok, NULL, 0) & 0xff;
+                  tok = tok_end;
+                  break;
+              }
+            }
+            while((p != base) && (p != NULL))
+              p = strtok(NULL, ",.");
+          }
+        }
+        else if (p[n] == ':')
+        {
+          *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+          if(!strncmp(p, "seltime", n))
+          {
+            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
+          }
+        }
+        else if (!strncmp(p, "verbose", n))
+        {
+          *(options[i].flag) = 0xff29;
+        }
+        else
+        {
+          *(options[i].flag) = ~(*(options[i].flag));
+          if(!strncmp(p, "seltime", n))
+          {
+            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
+          }
+        }
+      }
+    }
+  }
+  return 1;
+}
+
+__setup("aic7xxx=", aic7xxx_setup);
+
+/*+F*************************************************************************
+ * Function:
+ *   pause_sequencer
+ *
+ * Description:
+ *   Pause the sequencer and wait for it to actually stop - this
+ *   is important since the sequencer can disable pausing for critical
+ *   sections.
+ *-F*************************************************************************/
+static void
+pause_sequencer(struct aic7xxx_host *p)
+{
+  aic_outb(p, p->pause, HCNTRL);
+  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
+  {
+    ;
+  }
+  if(p->features & AHC_ULTRA2)
+  {
+    aic_inb(p, CCSCBCTL);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   unpause_sequencer
+ *
+ * Description:
+ *   Unpause the sequencer. Unremarkable, yet done often enough to
+ *   warrant an easy way to do it.
+ *-F*************************************************************************/
+static void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
+{
+  if (unpause_always ||
+      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+        !(p->flags & AHC_HANDLING_REQINITS) ) )
+  {
+    aic_outb(p, p->unpause, HCNTRL);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   restart_sequencer
+ *
+ * Description:
+ *   Restart the sequencer program from address zero.  This assumes
+ *   that the sequencer is already paused.
+ *-F*************************************************************************/
+static void
+restart_sequencer(struct aic7xxx_host *p)
+{
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+  aic_outb(p, FASTMODE, SEQCTL);
+}
+
+/*
+ * We include the aic7xxx_seq.c file here so that the other defines have
+ * already been made, and so that it comes before the code that actually
+ * downloads the instructions (since we don't typically use function
+ * prototype, our code has to be ordered that way, it's a left-over from
+ * the original driver days.....I should fix it some time DL).
+ */
+#include "aic7xxx_old/aic7xxx_seq.c"
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_check_patch
+ *
+ * Description:
+ *   See if the next patch to download should be downloaded.
+ *-F*************************************************************************/
+static int
+aic7xxx_check_patch(struct aic7xxx_host *p,
+  struct sequencer_patch **start_patch, int start_instr, int *skip_addr)
+{
+  struct sequencer_patch *cur_patch;
+  struct sequencer_patch *last_patch;
+  int num_patches;
+
+  num_patches = sizeof(sequencer_patches)/sizeof(struct sequencer_patch);
+  last_patch = &sequencer_patches[num_patches];
+  cur_patch = *start_patch;
+
+  while ((cur_patch < last_patch) && (start_instr == cur_patch->begin))
+  {
+    if (cur_patch->patch_func(p) == 0)
+    {
+      /*
+       * Start rejecting code.
+       */
+      *skip_addr = start_instr + cur_patch->skip_instr;
+      cur_patch += cur_patch->skip_patch;
+    }
+    else
+    {
+      /*
+       * Found an OK patch.  Advance the patch pointer to the next patch
+       * and wait for our instruction pointer to get here.
+       */
+      cur_patch++;
+    }
+  }
+
+  *start_patch = cur_patch;
+  if (start_instr < *skip_addr)
+    /*
+     * Still skipping
+     */
+    return (0);
+  return(1);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_download_instr
+ *
+ * Description:
+ *   Find the next patch to download.
+ *-F*************************************************************************/
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
+  unsigned char *dconsts)
+{
+  union ins_formats instr;
+  struct ins_format1 *fmt1_ins;
+  struct ins_format3 *fmt3_ins;
+  unsigned char opcode;
+
+  instr = *(union ins_formats*) &seqprog[instrptr * 4];
+
+  instr.integer = le32_to_cpu(instr.integer);
+  
+  fmt1_ins = &instr.format1;
+  fmt3_ins = NULL;
+
+  /* Pull the opcode */
+  opcode = instr.format1.opcode;
+  switch (opcode)
+  {
+    case AIC_OP_JMP:
+    case AIC_OP_JC:
+    case AIC_OP_JNC:
+    case AIC_OP_CALL:
+    case AIC_OP_JNE:
+    case AIC_OP_JNZ:
+    case AIC_OP_JE:
+    case AIC_OP_JZ:
+    {
+      struct sequencer_patch *cur_patch;
+      int address_offset;
+      unsigned int address;
+      int skip_addr;
+      int i;
+
+      fmt3_ins = &instr.format3;
+      address_offset = 0;
+      address = fmt3_ins->address;
+      cur_patch = sequencer_patches;
+      skip_addr = 0;
+
+      for (i = 0; i < address;)
+      {
+        aic7xxx_check_patch(p, &cur_patch, i, &skip_addr);
+        if (skip_addr > i)
+        {
+          int end_addr;
+
+          end_addr = MIN(address, skip_addr);
+          address_offset += end_addr - i;
+          i = skip_addr;
+        }
+        else
+        {
+          i++;
+        }
+      }
+      address -= address_offset;
+      fmt3_ins->address = address;
+      /* Fall Through to the next code section */
+    }
+    case AIC_OP_OR:
+    case AIC_OP_AND:
+    case AIC_OP_XOR:
+    case AIC_OP_ADD:
+    case AIC_OP_ADC:
+    case AIC_OP_BMOV:
+      if (fmt1_ins->parity != 0)
+      {
+        fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
+      }
+      fmt1_ins->parity = 0;
+      /* Fall Through to the next code section */
+    case AIC_OP_ROL:
+      if ((p->features & AHC_ULTRA2) != 0)
+      {
+        int i, count;
+
+        /* Calculate odd parity for the instruction */
+        for ( i=0, count=0; i < 31; i++)
+        {
+          unsigned int mask;
+
+          mask = 0x01 << i;
+          if ((instr.integer & mask) != 0)
+            count++;
+        }
+        if (!(count & 0x01))
+          instr.format1.parity = 1;
+      }
+      else
+      {
+        if (fmt3_ins != NULL)
+        {
+          instr.integer =  fmt3_ins->immediate |
+                          (fmt3_ins->source << 8) |
+                          (fmt3_ins->address << 16) |
+                          (fmt3_ins->opcode << 25);
+        }
+        else
+        {
+          instr.integer =  fmt1_ins->immediate |
+                          (fmt1_ins->source << 8) |
+                          (fmt1_ins->destination << 16) |
+                          (fmt1_ins->ret << 24) |
+                          (fmt1_ins->opcode << 25);
+        }
+      }
+      aic_outb(p, (instr.integer & 0xff), SEQRAM);
+      aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
+      aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
+      aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+      udelay(10);
+      break;
+
+    default:
+      panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+      break;
+  }
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_loadseq
+ *
+ * Description:
+ *   Load the sequencer code into the controller memory.
+ *-F*************************************************************************/
+static void
+aic7xxx_loadseq(struct aic7xxx_host *p)
+{
+  struct sequencer_patch *cur_patch;
+  int i;
+  int downloaded;
+  int skip_addr;
+  unsigned char download_consts[4] = {0, 0, 0, 0};
+
+  if (aic7xxx_verbose & VERBOSE_PROBE)
+  {
+    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
+  }
+#if 0
+  download_consts[TMODE_NUMCMDS] = p->num_targetcmds;
+#endif
+  download_consts[TMODE_NUMCMDS] = 0;
+  cur_patch = &sequencer_patches[0];
+  downloaded = 0;
+  skip_addr = 0;
+
+  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  for (i = 0; i < sizeof(seqprog) / 4;  i++)
+  {
+    if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0)
+    {
+      /* Skip this instruction for this configuration. */
+      continue;
+    }
+    aic7xxx_download_instr(p, i, &download_consts[0]);
+    downloaded++;
+  }
+
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+  aic_outb(p, FASTMODE | FAILDIS, SEQCTL);
+  unpause_sequencer(p, TRUE);
+  mdelay(1);
+  pause_sequencer(p);
+  aic_outb(p, FASTMODE, SEQCTL);
+  if (aic7xxx_verbose & VERBOSE_PROBE)
+  {
+    printk(" %d instructions downloaded\n", downloaded);
+  }
+  if (aic7xxx_dump_sequencer)
+    aic7xxx_print_sequencer(p, downloaded);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_sequencer
+ *
+ * Description:
+ *   Print the contents of the sequencer memory to the screen.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded)
+{
+  int i, k, temp;
+  
+  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  k = 0;
+  for (i=0; i < downloaded; i++)
+  {
+    if ( k == 0 )
+      printk("%03x: ", i);
+    temp = aic_inb(p, SEQRAM);
+    temp |= (aic_inb(p, SEQRAM) << 8);
+    temp |= (aic_inb(p, SEQRAM) << 16);
+    temp |= (aic_inb(p, SEQRAM) << 24);
+    printk("%08x", temp);
+    if ( ++k == 8 )
+    {
+      printk("\n");
+      k = 0;
+    }
+    else
+      printk(" ");
+  }
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+  aic_outb(p, FASTMODE | FAILDIS, SEQCTL);
+  unpause_sequencer(p, TRUE);
+  mdelay(1);
+  pause_sequencer(p);
+  aic_outb(p, FASTMODE, SEQCTL);
+  printk("\n");
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_info
+ *
+ * Description:
+ *   Return a string describing the driver.
+ *-F*************************************************************************/
+const char *
+aic7xxx_info(struct Scsi_Host *dooh)
+{
+  static char buffer[256];
+  char *bp;
+  struct aic7xxx_host *p;
+
+  bp = &buffer[0];
+  p = (struct aic7xxx_host *)dooh->hostdata;
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(bp, AIC7XXX_C_VERSION);
+  strcat(bp, "/");
+  strcat(bp, AIC7XXX_H_VERSION);
+  strcat(bp, "\n");
+  strcat(bp, "       <");
+  strcat(bp, board_names[p->board_name_index]);
+  strcat(bp, ">");
+
+  return(bp);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_syncrate
+ *
+ * Description:
+ *   Look up the valid period to SCSIRATE conversion in our table
+ *-F*************************************************************************/
+static struct aic7xxx_syncrate *
+aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
+  unsigned int maxsync, unsigned char *options)
+{
+  struct aic7xxx_syncrate *syncrate;
+  int done = FALSE;
+
+  switch(*options)
+  {
+    case MSG_EXT_PPR_OPTION_DT_CRC:
+    case MSG_EXT_PPR_OPTION_DT_UNITS:
+      if(!(p->features & AHC_ULTRA3))
+      {
+        *options = 0;
+        maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+      }
+      break;
+    case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+    case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+      if(!(p->features & AHC_ULTRA3))
+      {
+        *options = 0;
+        maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+      }
+      else
+      {
+        /*
+         * we don't support the Quick Arbitration variants of dual edge
+         * clocking.  As it turns out, we want to send back the
+         * same basic option, but without the QA attribute.
+         * We know that we are responding because we would never set
+         * these options ourself, we would only respond to them.
+         */
+        switch(*options)
+        {
+          case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+            *options = MSG_EXT_PPR_OPTION_DT_CRC;
+            break;
+          case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+            *options = MSG_EXT_PPR_OPTION_DT_UNITS;
+            break;
+        }
+      }
+      break;
+    default:
+      *options = 0;
+      maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+      break;
+  }
+  syncrate = &aic7xxx_syncrates[maxsync];
+  while ( (syncrate->rate[0] != NULL) &&
+         (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
+  {
+    if (*period <= syncrate->period) 
+    {
+      switch(*options)
+      {
+        case MSG_EXT_PPR_OPTION_DT_CRC:
+        case MSG_EXT_PPR_OPTION_DT_UNITS:
+          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+          {
+            done = TRUE;
+            /*
+             * oops, we went too low for the CRC/DualEdge signalling, so
+             * clear the options byte
+             */
+            *options = 0;
+            /*
+             * We'll be sending a reply to this packet to set the options
+             * properly, so unilaterally set the period as well.
+             */
+            *period = syncrate->period;
+          }
+          else
+          {
+            done = TRUE;
+            if(syncrate == &aic7xxx_syncrates[maxsync])
+            {
+              *period = syncrate->period;
+            }
+          }
+          break;
+        default:
+          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+          {
+            done = TRUE;
+            if(syncrate == &aic7xxx_syncrates[maxsync])
+            {
+              *period = syncrate->period;
+            }
+          }
+          break;
+      }
+      if(done)
+      {
+        break;
+      }
+    }
+    syncrate++;
+  }
+  if ( (*period == 0) || (syncrate->rate[0] == NULL) ||
+       ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) )
+  {
+    /*
+     * Use async transfers for this target
+     */
+    *options = 0;
+    *period = 255;
+    syncrate = NULL;
+  }
+  return (syncrate);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_period
+ *
+ * Description:
+ *   Look up the valid SCSIRATE to period conversion in our table
+ *-F*************************************************************************/
+static unsigned int
+aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate,
+  unsigned int maxsync)
+{
+  struct aic7xxx_syncrate *syncrate;
+
+  if (p->features & AHC_ULTRA2)
+  {
+    scsirate &= SXFR_ULTRA2;
+  }
+  else
+  {
+    scsirate &= SXFR;
+  }
+
+  syncrate = &aic7xxx_syncrates[maxsync];
+  while (syncrate->rate[0] != NULL)
+  {
+    if (p->features & AHC_ULTRA2)
+    {
+      if (syncrate->sxfr_ultra2 == 0)
+        break;
+      else if (scsirate == syncrate->sxfr_ultra2)
+        return (syncrate->period);
+      else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC))
+        return (syncrate->period);
+    }
+    else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
+    {
+      return (syncrate->period);
+    }
+    syncrate++;
+  }
+  return (0); /* async */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_validate_offset
+ *
+ * Description:
+ *   Set a valid offset value for a particular card in use and transfer
+ *   settings in use.
+ *-F*************************************************************************/
+static void
+aic7xxx_validate_offset(struct aic7xxx_host *p,
+  struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide)
+{
+  unsigned int maxoffset;
+
+  /* Limit offset to what the card (and device) can do */
+  if (syncrate == NULL)
+  {
+    maxoffset = 0;
+  }
+  else if (p->features & AHC_ULTRA2)
+  {
+    maxoffset = MAX_OFFSET_ULTRA2;
+  }
+  else
+  {
+    if (wide)
+      maxoffset = MAX_OFFSET_16BIT;
+    else
+      maxoffset = MAX_OFFSET_8BIT;
+  }
+  *offset = MIN(*offset, maxoffset);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_syncrate
+ *
+ * Description:
+ *   Set the actual syncrate down in the card and in our host structs
+ *-F*************************************************************************/
+static void
+aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
+    int target, int channel, unsigned int period, unsigned int offset,
+    unsigned char options, unsigned int type)
+{
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun, old_options;
+  unsigned int old_period, old_offset;
+
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
+
+  if (syncrate == NULL)
+  {
+    period = 0;
+    offset = 0;
+  }
+
+  old_period = p->transinfo[tindex].cur_period;
+  old_offset = p->transinfo[tindex].cur_offset;
+  old_options = p->transinfo[tindex].cur_options;
+
+  
+  if (type & AHC_TRANS_CUR)
+  {
+    unsigned int scsirate;
+
+    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+    if (p->features & AHC_ULTRA2)
+    {
+      scsirate &= ~SXFR_ULTRA2;
+      if (syncrate != NULL)
+      {
+        switch(options)
+        {
+          case MSG_EXT_PPR_OPTION_DT_UNITS:
+            /*
+             * mask off the CRC bit in the xfer settings
+             */
+            scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC);
+            break;
+          default:
+            scsirate |= syncrate->sxfr_ultra2;
+            break;
+        }
+      }
+      if (type & AHC_TRANS_ACTIVE)
+      {
+        aic_outb(p, offset, SCSIOFFSET);
+      }
+      aic_outb(p, offset, TARG_OFFSET + tindex);
+    }
+    else /* Not an Ultra2 controller */
+    {
+      scsirate &= ~(SXFR|SOFS);
+      p->ultraenb &= ~target_mask;
+      if (syncrate != NULL)
+      {
+        if (syncrate->sxfr & ULTRA_SXFR)
+        {
+          p->ultraenb |= target_mask;
+        }
+        scsirate |= (syncrate->sxfr & SXFR);
+        scsirate |= (offset & SOFS);
+      }
+      if (type & AHC_TRANS_ACTIVE)
+      {
+        unsigned char sxfrctl0;
+
+        sxfrctl0 = aic_inb(p, SXFRCTL0);
+        sxfrctl0 &= ~FAST20;
+        if (p->ultraenb & target_mask)
+          sxfrctl0 |= FAST20;
+        aic_outb(p, sxfrctl0, SXFRCTL0);
+      }
+      aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+      aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 );
+    }
+    if (type & AHC_TRANS_ACTIVE)
+    {
+      aic_outb(p, scsirate, SCSIRATE);
+    }
+    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
+    p->transinfo[tindex].cur_period = period;
+    p->transinfo[tindex].cur_offset = offset;
+    p->transinfo[tindex].cur_options = options;
+    if ( !(type & AHC_TRANS_QUITE) &&
+         (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+    {
+      if (offset)
+      {
+        int rate_mod = (scsirate & WIDEXFER) ? 1 : 0;
+      
+        printk(INFO_LEAD "Synchronous at %s Mbyte/sec, "
+               "offset %d.\n", p->host_no, channel, target, lun,
+               syncrate->rate[rate_mod], offset);
+      }
+      else
+      {
+        printk(INFO_LEAD "Using asynchronous transfers.\n",
+               p->host_no, channel, target, lun);
+      }
+      p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
+    }
+  }
+
+  if (type & AHC_TRANS_GOAL)
+  {
+    p->transinfo[tindex].goal_period = period;
+    p->transinfo[tindex].goal_offset = offset;
+    p->transinfo[tindex].goal_options = options;
+  }
+
+  if (type & AHC_TRANS_USER)
+  {
+    p->transinfo[tindex].user_period = period;
+    p->transinfo[tindex].user_offset = offset;
+    p->transinfo[tindex].user_options = options;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_width
+ *
+ * Description:
+ *   Set the actual width down in the card and in our host structs
+ *-F*************************************************************************/
+static void
+aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
+    unsigned int width, unsigned int type)
+{
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned int old_width;
+
+  tindex = target | (channel << 3);
+  target_mask = 1 << tindex;
+  
+  old_width = p->transinfo[tindex].cur_width;
+
+  if (type & AHC_TRANS_CUR) 
+  {
+    unsigned char scsirate;
+
+    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+
+    scsirate &= ~WIDEXFER;
+    if (width == MSG_EXT_WDTR_BUS_16_BIT)
+      scsirate |= WIDEXFER;
+
+    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
+
+    if (type & AHC_TRANS_ACTIVE)
+      aic_outb(p, scsirate, SCSIRATE);
+
+    p->transinfo[tindex].cur_width = width;
+
+    if ( !(type & AHC_TRANS_QUITE) &&
+          (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
+          (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+    {
+      printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
+        lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
+    }
+  }
+
+  if (type & AHC_TRANS_GOAL)
+    p->transinfo[tindex].goal_width = width;
+  if (type & AHC_TRANS_USER)
+    p->transinfo[tindex].user_width = width;
+
+  if (p->transinfo[tindex].goal_offset)
+  {
+    if (p->features & AHC_ULTRA2)
+    {
+      p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+    }
+    else if (width == MSG_EXT_WDTR_BUS_16_BIT)
+    {
+      p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+    }
+    else
+    {
+      p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+    }
+  }
+}
+      
+/*+F*************************************************************************
+ * Function:
+ *   scbq_init
+ *
+ * Description:
+ *   SCB queue initialization.
+ *
+ *-F*************************************************************************/
+static void
+scbq_init(volatile scb_queue_type *queue)
+{
+  queue->head = NULL;
+  queue->tail = NULL;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_insert_head
+ *
+ * Description:
+ *   Add an SCB to the head of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  scb->q_next = queue->head;
+  queue->head = scb;
+  if (queue->tail == NULL)       /* If list was empty, update tail. */
+    queue->tail = queue->head;
+  DRIVER_UNLOCK
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_remove_head
+ *
+ * Description:
+ *   Remove an SCB from the head of the list.
+ *
+ *-F*************************************************************************/
+static inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
+{
+  struct aic7xxx_scb * scbp;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  scbp = queue->head;
+  if (queue->head != NULL)
+    queue->head = queue->head->q_next;
+  if (queue->head == NULL)       /* If list is now empty, update tail. */
+    queue->tail = NULL;
+  DRIVER_UNLOCK
+  return(scbp);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_remove
+ *
+ * Description:
+ *   Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  if (queue->head == scb)
+  {
+    /* At beginning of queue, remove from head. */
+    scbq_remove_head(queue);
+  }
+  else
+  {
+    struct aic7xxx_scb *curscb = queue->head;
+
+    /*
+     * Search until the next scb is the one we're looking for, or
+     * we run out of queue.
+     */
+    while ((curscb != NULL) && (curscb->q_next != scb))
+    {
+      curscb = curscb->q_next;
+    }
+    if (curscb != NULL)
+    {
+      /* Found it. */
+      curscb->q_next = scb->q_next;
+      if (scb->q_next == NULL)
+      {
+        /* Update the tail when removing the tail. */
+        queue->tail = curscb;
+      }
+    }
+  }
+  DRIVER_UNLOCK
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_insert_tail
+ *
+ * Description:
+ *   Add an SCB at the tail of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  scb->q_next = NULL;
+  if (queue->tail != NULL)       /* Add the scb at the end of the list. */
+    queue->tail->q_next = scb;
+  queue->tail = scb;             /* Update the tail. */
+  if (queue->head == NULL)       /* If list was empty, update head. */
+    queue->head = queue->tail;
+  DRIVER_UNLOCK
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_match_scb
+ *
+ * Description:
+ *   Checks to see if an scb matches the target/channel as specified.
+ *   If target is ALL_TARGETS (-1), then we're looking for any device
+ *   on the specified channel; this happens when a channel is going
+ *   to be reset and all devices on that channel must be aborted.
+ *-F*************************************************************************/
+static int
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    int target, int channel, int lun, unsigned char tag)
+{
+  int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
+  int slun = scb->hscb->target_channel_lun & 0x07;
+  int match;
+
+  match = ((chan == channel) || (channel == ALL_CHANNELS));
+  if (match != 0)
+    match = ((targ == target) || (target == ALL_TARGETS));
+  if (match != 0)
+    match = ((lun == slun) || (lun == ALL_LUNS));
+  if (match != 0)
+    match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+  return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ *   Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+  /*
+   * Invalidate the tag so that aic7xxx_find_scb doesn't think
+   * it's active
+   */
+  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+  aic_outb(p, 0, SCB_CONTROL);
+
+  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ *   Removes the current SCB from the disconnected list and adds it
+ *   to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr,
+                               unsigned char prev)
+{
+  unsigned char next;
+
+  aic_outb(p, scbptr, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+  aic7xxx_add_curscb_to_free_list(p);
+
+  if (prev != SCB_LIST_NULL)
+  {
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
+  }
+  else
+  {
+    aic_outb(p, next, DISCONNECTED_SCBH);
+  }
+
+  return next;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_busy_target
+ *
+ * Description:
+ *   Set the specified target busy.
+ *-F*************************************************************************/
+static inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_index_busy_target
+ *
+ * Description:
+ *   Returns the index of the busy target, and optionally sets the
+ *   target inactive.
+ *-F*************************************************************************/
+static inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+    int unbusy)
+{
+  unsigned char busy_scbid;
+
+  busy_scbid = p->untagged_scbs[tcl];
+  if (unbusy)
+  {
+    p->untagged_scbs[tcl] = SCB_LIST_NULL;
+  }
+  return (busy_scbid);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_scb
+ *
+ * Description:
+ *   Look through the SCB array of the card and attempt to find the
+ *   hardware SCB that corresponds to the passed in SCB.  Return
+ *   SCB_LIST_NULL if unsuccessful.  This routine assumes that the
+ *   card is already paused.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char saved_scbptr;
+  unsigned char curindex;
+
+  saved_scbptr = aic_inb(p, SCBPTR);
+  curindex = 0;
+  for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
+  {
+    aic_outb(p, curindex, SCBPTR);
+    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
+    {
+      break;
+    }
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  if (curindex >= p->scb_data->maxhscbs)
+  {
+    curindex = SCB_LIST_NULL;
+  }
+
+  return (curindex);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_allocate_scb
+ *
+ * Description:
+ *   Get an SCB from the free list or by allocating a new one.
+ *-F*************************************************************************/
+static int
+aic7xxx_allocate_scb(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb   *scbp = NULL;
+  int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6;
+  int i;
+  int step = PAGE_SIZE / 1024;
+  unsigned long scb_count = 0;
+  struct hw_scatterlist *hsgp;
+  struct aic7xxx_scb *scb_ap;
+  struct aic7xxx_scb_dma *scb_dma;
+  unsigned char *bufs;
+
+  if (p->scb_data->numscbs < p->scb_data->maxscbs)
+  {
+    /*
+     * Calculate the optimal number of SCBs to allocate.
+     *
+     * NOTE: This formula works because the sizeof(sg_array) is always
+     * 1024.  Therefore, scb_size * i would always be > PAGE_SIZE *
+     * (i/step).  The (i-1) allows the left hand side of the equation
+     * to grow into the right hand side to a point of near perfect
+     * efficiency since scb_size * (i -1) is growing slightly faster
+     * than the right hand side.  If the number of SG array elements
+     * is changed, this function may not be near so efficient any more.
+     *
+     * Since the DMA'able buffers are now allocated in a seperate
+     * chunk this algorithm has been modified to match.  The '12'
+     * and '6' factors in scb_size are for the DMA'able command byte
+     * and sensebuffers respectively.  -DaveM
+     */
+    for ( i=step;; i *= 2 )
+    {
+      if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) )
+      {
+        i /= 2;
+        break;
+      }
+    }
+    scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
+    scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+					   + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
+    if (scb_ap == NULL)
+      return(0);
+    scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count];
+    hsgp = (struct hw_scatterlist *)
+      pci_alloc_consistent(p->pdev, scb_size * scb_count,
+			   &scb_dma->dma_address);
+    if (hsgp == NULL)
+    {
+      kfree(scb_ap);
+      return(0);
+    }
+    bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG];
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (aic7xxx_verbose > 0xffff)
+    {
+      if (p->scb_data->numscbs == 0)
+	printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+	  p->host_no, -1, -1, -1, scb_count);
+      else
+	printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+	  p->host_no, -1, -1, -1, scb_count);
+    }
+#endif
+    memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count);
+    scb_dma->dma_offset = (unsigned long)scb_dma->dma_address
+			  - (unsigned long)hsgp;
+    scb_dma->dma_len = scb_size * scb_count;
+    for (i=0; i < scb_count; i++)
+    {
+      scbp = &scb_ap[i];
+      scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+      scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+      scbp->sense_cmd = bufs;
+      scbp->cmnd = bufs + 6;
+      bufs += 12 + 6;
+      scbp->scb_dma = scb_dma;
+      memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+      scbp->hscb->tag = p->scb_data->numscbs;
+      /*
+       * Place in the scb array; never is removed
+       */
+      p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+      scbq_insert_tail(&p->scb_data->free_scbs, scbp);
+    }
+    scbp->kmalloc_ptr = scb_ap;
+  }
+  return(scb_count);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_queue_cmd_complete
+ *
+ * Description:
+ *   Due to race conditions present in the SCSI subsystem, it is easier
+ *   to queue completed commands, then call scsi_done() on them when
+ *   we're finished.  This function queues the completed commands.
+ *-F*************************************************************************/
+static void
+aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+{
+  cmd->host_scribble = (char *)p->completeq.head;
+  p->completeq.head = cmd;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_done_cmds_complete
+ *
+ * Description:
+ *   Process the completed command queue.
+ *-F*************************************************************************/
+static void
+aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
+{
+  Scsi_Cmnd *cmd;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned int cpu_flags = 0;
+#endif
+  
+  DRIVER_LOCK
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    cmd->scsi_done(cmd);
+  }
+  DRIVER_UNLOCK
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free_scb
+ *
+ * Description:
+ *   Free the scb and insert into the free scb list.
+ *-F*************************************************************************/
+static void
+aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+
+  scb->flags = SCB_FREE;
+  scb->cmd = NULL;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+  scb->tag_action = 0;
+  scb->hscb->control = 0;
+  scb->hscb->target_status = 0;
+  scb->hscb->target_channel_lun = SCB_LIST_NULL;
+
+  scbq_insert_head(&p->scb_data->free_scbs, scb);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_done
+ *
+ * Description:
+ *   Calls the higher level scsi done function and frees the scb.
+ *-F*************************************************************************/
+static void
+aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  Scsi_Cmnd *cmd = scb->cmd;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_scb *scbp;
+  unsigned char queue_depth;
+
+  if (cmd->use_sg > 1)
+  {
+    struct scatterlist *sg;
+
+    sg = (struct scatterlist *)cmd->request_buffer;
+    pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+  }
+  else if (cmd->request_bufflen)
+    pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
+		     cmd->request_bufflen,
+                     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+  if (scb->flags & SCB_SENSE)
+  {
+    pci_unmap_single(p->pdev,
+                     le32_to_cpu(scb->sg_list[0].address),
+                     sizeof(cmd->sense_buffer),
+                     PCI_DMA_FROMDEVICE);
+  }
+  if (scb->flags & SCB_RECOVERY_SCB)
+  {
+    p->flags &= ~AHC_ABORT_PENDING;
+  }
+  if (scb->flags & SCB_RESET)
+  {
+      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+  }
+  else if (scb->flags & SCB_ABORT)
+  {
+      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+  }
+  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+  {
+    if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
+    {
+      char *buffer;
+      
+      p->dev_flags[tindex] |= DEVICE_PRESENT;
+      if(cmd->use_sg)
+      {
+        struct scatterlist *sg;
+
+        sg = (struct scatterlist *)cmd->request_buffer;
+        buffer = (char *)sg[0].address;
+      }
+      else
+      {
+        buffer = (char *)cmd->request_buffer;
+      }
+#define WIDE_INQUIRY_BITS 0x60
+#define SYNC_INQUIRY_BITS 0x10
+#define SCSI_VERSION_BITS 0x07
+#define SCSI_DT_BIT       0x04
+      if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+           (p->features & AHC_WIDE) )
+      {
+        p->needwdtr |= (1<<tindex);
+        p->needwdtr_copy |= (1<<tindex);
+        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+      }
+      else
+      {
+        p->needwdtr &= ~(1<<tindex);
+        p->needwdtr_copy &= ~(1<<tindex);
+        pause_sequencer(p);
+        aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+                          MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+                                                   AHC_TRANS_GOAL |
+                                                   AHC_TRANS_CUR) );
+        unpause_sequencer(p, FALSE);
+      }
+      if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+            p->transinfo[tindex].user_offset )
+      {
+        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+        if (p->features & AHC_ULTRA2)
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+        else
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
+               (buffer[56] & SCSI_DT_BIT) ||
+	       (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+               (p->transinfo[tindex].user_period <= 9) &&
+               (p->transinfo[tindex].user_options) )
+        {
+          p->needppr |= (1<<tindex);
+          p->needppr_copy |= (1<<tindex);
+          p->needsdtr &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->needwdtr &= ~(1<<tindex);
+          p->needwdtr_copy &= ~(1<<tindex);
+          p->dev_flags[tindex] |= DEVICE_SCSI_3;
+        }
+        else
+        {
+          p->needsdtr |= (1<<tindex);
+          p->needsdtr_copy |= (1<<tindex);
+          p->transinfo[tindex].goal_period = 
+            MAX(10, p->transinfo[tindex].goal_period);
+          p->transinfo[tindex].goal_options = 0;
+        }
+      }
+      else
+      {
+        p->needsdtr &= ~(1<<tindex);
+        p->needsdtr_copy &= ~(1<<tindex);
+        p->transinfo[tindex].goal_period = 255;
+        p->transinfo[tindex].goal_offset = 0;
+        p->transinfo[tindex].goal_options = 0;
+      }
+      /*
+       * This is needed to work around a sequencer bug for now.  Regardless
+       * of the controller in use, if we have a Quantum drive, we need to
+       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
+       * of the sequencer, this code will get yanked.
+       */
+      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
+         p->transinfo[tindex].goal_options )
+      {
+        p->transinfo[tindex].goal_period = 
+          MAX(p->transinfo[tindex].goal_period, 10);
+        p->transinfo[tindex].goal_options = 0;
+        p->needppr &= ~(1<<tindex);
+        p->needppr_copy &= ~(1<<tindex);
+        p->needsdtr |= (1<<tindex);
+        p->needsdtr_copy |= (1<<tindex);
+        p->needwdtr |= (1<<tindex);
+        p->needwdtr_copy |= (1<<tindex);
+      }
+      /*
+       * Get the INQUIRY checksum.  We use this on Ultra 160/m
+       * and older devices both.  It allows us to drop speed on any bus type
+       * while at the same time giving us the needed domain validation for
+       * Ultra 160/m
+       *
+       * Note: We only get the checksum and set the SCANNED bit if this is
+       * one of our dtr commands.  If we don't do this, then we end up
+       * getting bad checksum results on the mid-level SCSI code's INQUIRY
+       * commands.
+       */
+      if(p->dev_dtr_cmnd[tindex] == cmd) {
+        unsigned int checksum = 0;
+        int *ibuffer;
+        int i=0;
+
+        ibuffer = (int *)buffer;
+        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+        {
+          checksum += ibuffer[i];
+        }
+        p->dev_checksum[tindex] = checksum;
+        p->dev_flags[tindex] |= DEVICE_SCANNED;
+        p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
+      }
+#undef WIDE_INQUIRY_BITS
+#undef SYNC_INQUIRY_BITS
+#undef SCSI_VERSION_BITS
+#undef SCSI_DT_BIT
+    }
+  }
+  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+  {
+    unsigned short mask;
+    int message_error = FALSE;
+
+    mask = 0x01 << tindex;
+ 
+    /*
+     * Check to see if we get an invalid message or a message error
+     * after failing to negotiate a wide or sync transfer message.
+     */
+    if ((scb->flags & SCB_SENSE) && 
+          ((scb->cmd->sense_buffer[12] == 0x43) ||  /* INVALID_MESSAGE */
+          (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR  */
+    {
+      message_error = TRUE;
+    }
+
+    if (scb->flags & SCB_MSGOUT_WDTR)
+    {
+      p->dtr_pending &= ~mask;
+      if (message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+        }
+        p->needwdtr &= ~mask;
+        p->needwdtr_copy &= ~mask;
+      }
+    }
+    if (scb->flags & SCB_MSGOUT_SDTR)
+    {
+      p->dtr_pending &= ~mask;
+      if (message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
+        }
+        p->needsdtr &= ~mask;
+        p->needsdtr_copy &= ~mask;
+      }
+    }
+    if (scb->flags & SCB_MSGOUT_PPR)
+    {
+      p->dtr_pending &= ~mask;
+      if(message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Parallel Protocol "
+            "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
+            "device.\n", p->host_no, CTL_OF_SCB(scb));
+        }
+        /*
+         * Disable PPR negotiation and revert back to WDTR and SDTR setup
+         */
+        p->needppr &= ~mask;
+        p->needppr_copy &= ~mask;
+        p->needsdtr |= mask;
+        p->needsdtr_copy |= mask;
+        p->needwdtr |= mask;
+        p->needwdtr_copy |= mask;
+      }
+    }
+  }
+  queue_depth = p->dev_temp_queue_depth[tindex];
+  if (queue_depth >= p->dev_active_cmds[tindex])
+  {
+    scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+    if (scbp)
+    {
+      if (queue_depth == 1)
+      {
+        /*
+         * Give extra preference to untagged devices, such as CD-R devices
+         * This makes it more likely that a drive *won't* stuff up while
+         * waiting on data at a critical time, such as CD-R writing and
+         * audio CD ripping operations.  Should also benefit tape drives.
+         */
+        scbq_insert_head(&p->waiting_scbs, scbp);
+      }
+      else
+      {
+        scbq_insert_tail(&p->waiting_scbs, scbp);
+      }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n",
+               p->host_no, CTL_OF_SCB(scbp));
+#endif
+      if (queue_depth > p->dev_active_cmds[tindex])
+      {
+        scbp = scbq_remove_head(&p->delayed_scbs[tindex]);
+        if (scbp)
+          scbq_insert_tail(&p->waiting_scbs, scbp);
+      }
+    }
+  }
+  if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
+  {
+    p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+  }
+  p->dev_active_cmds[tindex]--;
+  p->activescbs--;
+
+  {
+    int actual;
+
+    /*
+     * XXX: we should actually know how much actually transferred
+     * XXX: for each command, but apparently that's too difficult.
+     * 
+     * We set a lower limit of 512 bytes on the transfer length.  We
+     * ignore anything less than this because we don't have a real
+     * reason to count it.  Read/Writes to tapes are usually about 20K
+     * and disks are a minimum of 512 bytes unless you want to count
+     * non-read/write commands (such as TEST_UNIT_READY) which we don't
+     */
+    actual = scb->sg_length;
+    if ((actual >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
+    {
+      struct aic7xxx_xferstats *sp;
+#ifdef AIC7XXX_PROC_STATS
+      long *ptr;
+      int x;
+#endif /* AIC7XXX_PROC_STATS */
+
+      sp = &p->stats[TARGET_INDEX(cmd)];
+
+      /*
+       * For block devices, cmd->request.cmd is always == either READ or
+       * WRITE.  For character devices, this isn't always set properly, so
+       * we check data_cmnd[0].  This catches the conditions for st.c, but
+       * I'm still not sure if request.cmd is valid for sg devices.
+       */
+      if ( (cmd->request.cmd == WRITE) || (cmd->data_cmnd[0] == WRITE_6) ||
+           (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
+      {
+        sp->w_total++;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) )
+          aic7xxx_verbose &= 0xffff;
+#endif
+#ifdef AIC7XXX_PROC_STATS
+        ptr = sp->w_bins;
+#endif /* AIC7XXX_PROC_STATS */
+      }
+      else
+      {
+        sp->r_total++;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) )
+          aic7xxx_verbose &= 0xffff;
+#endif
+#ifdef AIC7XXX_PROC_STATS
+        ptr = sp->r_bins;
+#endif /* AIC7XXX_PROC_STATS */
+      }
+#ifdef AIC7XXX_PROC_STATS
+      x = -11;
+      while(actual)
+      {
+        actual >>= 1;
+        x++;
+      }
+      if (x < 0)
+      {
+        ptr[0]++;
+      }
+      else if (x > 7)
+      {
+        ptr[7]++;
+      }
+      else
+      {
+        ptr[x]++;
+      }
+#endif /* AIC7XXX_PROC_STATS */
+    }
+  }
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_run_done_queue
+ *
+ * Description:
+ *   Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ *   aborted list, and adds each scb to the free list.  If complete
+ *   is TRUE, we also process the commands complete list.
+ *-F*************************************************************************/
+static void
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
+{
+  struct aic7xxx_scb *scb;
+  int i, found = 0;
+
+  for (i = 0; i < p->scb_data->numscbs; i++)
+  {
+    scb = p->scb_data->scb_array[i];
+    if (scb->flags & SCB_QUEUED_FOR_DONE)
+    {
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Aborting scb %d\n",
+             p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+      found++;
+      aic7xxx_done(p, scb);
+    }
+  }
+  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
+  {
+    printk(INFO_LEAD "%d commands found and queued for "
+        "completion.\n", p->host_no, -1, -1, -1, found);
+  }
+  if (complete)
+  {
+    aic7xxx_done_cmds_complete(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_abort_waiting_scb
+ *
+ * Description:
+ *   Manipulate the waiting for selection list and return the
+ *   scb that follows the one that we remove.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    unsigned char scbpos, unsigned char prev)
+{
+  unsigned char curscb, next;
+
+  /*
+   * Select the SCB we want to abort and pull the next pointer out of it.
+   */
+  curscb = aic_inb(p, SCBPTR);
+  aic_outb(p, scbpos, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+
+  aic7xxx_add_curscb_to_free_list(p);
+
+  /*
+   * Update the waiting list
+   */
+  if (prev == SCB_LIST_NULL)
+  {
+    /*
+     * First in the list
+     */
+    aic_outb(p, next, WAITING_SCBH);
+  }
+  else
+  {
+    /*
+     * Select the scb that pointed to us and update its next pointer.
+     */
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
+  }
+  /*
+   * Point us back at the original scb position and inform the SCSI
+   * system that the command has been aborted.
+   */
+  aic_outb(p, curscb, SCBPTR);
+  return (next);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_search_qinfifo
+ *
+ * Description:
+ *   Search the queue-in FIFO for matching SCBs and conditionally
+ *   requeue.  Returns the number of matching SCBs.
+ *-F*************************************************************************/
+static int
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+    int lun, unsigned char tag, int flags, int requeue,
+    volatile scb_queue_type *queue)
+{
+  int      found;
+  unsigned char qinpos, qintail;
+  struct aic7xxx_scb *scbp;
+
+  found = 0;
+  qinpos = aic_inb(p, QINPOS);
+  qintail = p->qinfifonext;
+
+  p->qinfifonext = qinpos;
+
+  while (qinpos != qintail)
+  {
+    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+    {
+       /*
+        * We found an scb that needs to be removed.
+        */
+       if (requeue && (queue != NULL))
+       {
+         if (scbp->flags & SCB_WAITINGQ)
+         {
+           scbq_remove(queue, scbp);
+           scbq_remove(&p->waiting_scbs, scbp);
+           scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
+           p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+           p->activescbs++;
+         }
+         scbq_insert_tail(queue, scbp);
+         p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]--;
+         p->activescbs--;
+         scbp->flags |= SCB_WAITINGQ;
+         if ( !(scbp->tag_action & TAG_ENB) )
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       else if (requeue)
+       {
+         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
+       }
+       else
+       {
+        /*
+         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+         * flags we were called with, presumeably so aic7xxx_run_done_queue
+         * can find this scb
+         */
+         scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+                                       FALSE) == scbp->hscb->tag)
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       found++;
+    }
+    else
+    {
+      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
+    }
+  }
+  /*
+   * Now that we've done the work, clear out any left over commands in the
+   * qinfifo and update the KERNEL_QINPOS down on the card.
+   *
+   *  NOTE: This routine expect the sequencer to already be paused when
+   *        it is run....make sure it's that way!
+   */
+  qinpos = p->qinfifonext;
+  while(qinpos != qintail)
+  {
+    p->qinfifo[qinpos++] = SCB_LIST_NULL;
+  }
+  if (p->features & AHC_QUEUE_REGS)
+    aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+  else
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ *   Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i=0;
+
+  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+  {
+    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+      return TRUE;
+    else
+      i++;
+  }
+  return FALSE;
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset_device
+ *
+ * Description:
+ *   The device at the given target/channel has been reset.  Abort
+ *   all active and queued scbs for that target/channel.  This function
+ *   need not worry about linked next pointers because if was a MSG_ABORT_TAG
+ *   then we had a tagged command (no linked next), if it was MSG_ABORT or
+ *   MSG_BUS_DEV_RESET then the device won't know about any commands any more
+ *   and no busy commands will exist, and if it was a bus reset, then nothing
+ *   knows about any linked next commands any more.  In all cases, we don't
+ *   need to worry about the linked next or busy scb, we just need to clear
+ *   them.
+ *-F*************************************************************************/
+static void
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
+                     int lun, unsigned char tag)
+{
+  struct aic7xxx_scb *scbp;
+  unsigned char active_scb, tcl;
+  int i = 0, j, init_lists = FALSE;
+
+  /*
+   * Restore this when we're done
+   */
+  active_scb = aic_inb(p, SCBPTR);
+
+  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+    printk(INFO_LEAD "Reset device, active_scb %d\n",
+         p->host_no, channel, target, lun, active_scb);
+  /*
+   * Deal with the busy target and linked next issues.
+   */
+  {
+    int min_target, max_target;
+    struct aic7xxx_scb *scbp, *prev_scbp;
+
+    /* Make all targets 'relative' to bus A. */
+    if (target == ALL_TARGETS)
+    {
+      switch (channel)
+      {
+        case 0:
+                 min_target = 0;
+                 max_target = (p->features & AHC_WIDE) ? 15 : 7;
+                 break;
+        case 1:
+                 min_target = 8;
+                 max_target = 15;
+                 break;
+        case ALL_CHANNELS:
+        default:
+                 min_target = 0;
+                 max_target = (p->features & (AHC_TWIN|AHC_WIDE)) ? 15 : 7;
+                 break;
+      }
+    }
+    else
+    { 
+      min_target = target | (channel << 3);
+      max_target = min_target;
+    }
+
+
+    for (i = min_target; i <= max_target; i++)
+    {
+      if ( i == p->scsi_id )
+      {
+        continue;
+      }
+      if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Cleaning up status information "
+          "and delayed_scbs.\n", p->host_no, channel, i, lun);
+      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
+      if ( tag == SCB_LIST_NULL )
+      {
+        p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
+        p->dev_expires[i] = jiffies + (4 * HZ);
+        p->dev_timer_active |= (0x01 << i);
+        p->dev_last_queue_full_count[i] = 0;
+        p->dev_last_queue_full[i] = 0;
+        p->dev_temp_queue_depth[i] =
+          p->dev_max_queue_depth[i];
+      }
+      for(j=0; j<MAX_LUNS; j++)
+      {
+        if (channel == 1)
+          tcl = ((i << 4) & 0x70) | (channel << 3) | j;
+        else
+          tcl = (i << 4) | (channel << 3) | j;
+        if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+             (tag == SCB_LIST_NULL) )
+          aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+      }
+      j = 0; 
+      prev_scbp = NULL; 
+      scbp = p->delayed_scbs[i].head;
+      while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
+      {
+        prev_scbp = scbp;
+        scbp = scbp->q_next;
+        if ( prev_scbp == scbp )
+        {
+          if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+            printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+              "in the delayed_scbs queue!\n", p->host_no, channel, i, lun);
+          scbp = NULL;
+          prev_scbp->q_next = NULL;
+          p->delayed_scbs[i].tail = prev_scbp;
+        }
+        if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+        {
+          scbq_remove(&p->delayed_scbs[i], prev_scbp);
+          if (prev_scbp->flags & SCB_WAITINGQ)
+          {
+            p->dev_active_cmds[i]++;
+            p->activescbs++;
+          }
+          prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        }
+      }
+      if ( j > (p->scb_data->maxscbs + 1) )
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! There's a loop in the "
+            "delayed_scbs queue!\n", p->host_no, channel, i, lun);
+        scbq_init(&p->delayed_scbs[i]);
+      }
+      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+            time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
+      {
+        mod_timer(&p->dev_timer, p->dev_expires[i]);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+      }
+    }
+  }
+
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
+  aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
+
+/*
+ *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
+ *  ABORT/RESET commands.
+ */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+      target, lun );
+  {
+    struct aic7xxx_scb *scbp, *prev_scbp;
+
+    j = 0; 
+    prev_scbp = NULL; 
+    scbp = p->waiting_scbs.head;
+    while ( (scbp != NULL) && (j++ <= (p->scb_data->numscbs + 1)) )
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if ( prev_scbp == scbp )
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+          printk(WARN_LEAD "Yikes!! scb->q_next == scb "
+            "in the waiting_scbs queue!\n", p->host_no, CTL_OF_SCB(scbp));
+        scbp = NULL;
+        prev_scbp->q_next = NULL;
+        p->waiting_scbs.tail = prev_scbp;
+      }
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+      {
+        scbq_remove(&p->waiting_scbs, prev_scbp);
+        if (prev_scbp->flags & SCB_WAITINGQ)
+        {
+          p->dev_active_cmds[TARGET_INDEX(prev_scbp->cmd)]++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      }
+    }
+    if ( j > (p->scb_data->maxscbs + 1) )
+    {
+      if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+        printk(WARN_LEAD "Yikes!! There's a loop in the "
+          "waiting_scbs queue!\n", p->host_no, channel, target, lun);
+      scbq_init(&p->waiting_scbs);
+    }
+  }
+
+
+  /*
+   * Search waiting for selection list.
+   */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting for selection "
+      "list.\n", p->host_no, channel, target, lun);
+  {
+    unsigned char next, prev, scb_index;
+
+    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
+    prev = SCB_LIST_NULL;
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
+    {
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+      if (scb_index >= p->scb_data->numscbs)
+      {
+       /*
+        * No aic7xxx_verbose check here.....we want to see this since it
+        * means either the kernel driver or the sequencer screwed things up
+        */
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic_inb(p, SCB_NEXT);
+        aic7xxx_add_curscb_to_free_list(p);
+      }
+      else
+      {
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+          if (scbp->flags & SCB_WAITINGQ)
+          {
+            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+            p->activescbs++;
+          }
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (prev == SCB_LIST_NULL)
+          {
+            /*
+             * This is either the first scb on the waiting list, or we
+             * have already yanked the first and haven't left any behind.
+             * Either way, we need to turn off the selection hardware if
+             * it isn't already off.
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
+          }
+        }
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
+      }
+    }
+    if ( j > (p->scb_data->maxscbs + 1) )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the waiting for "
+        "selection list!\n", p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
+  }
+
+  /*
+   * Go through disconnected list and remove any entries we have queued
+   * for completion, zeroing their control byte too.
+   */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning disconnected scbs "
+      "list.\n", p->host_no, channel, target, lun);
+  if (p->flags & AHC_PAGESCBS)
+  {
+    unsigned char next, prev, scb_index;
+
+    next = aic_inb(p, DISCONNECTED_SCBH);
+    prev = SCB_LIST_NULL;
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
+    {
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+      if (scb_index > p->scb_data->numscbs)
+      {
+        printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
+      }
+      else
+      {
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
+          if (scbp->flags & SCB_WAITINGQ)
+          {
+            p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+            p->activescbs++;
+          }
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->hscb->control = 0;
+        }
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
+      }
+    }
+    if ( j > (p->scb_data->maxscbs + 1) )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the disconnected list!\n",
+        p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
+  }
+
+  /*
+   * Walk the free list making sure no entries on the free list have
+   * a valid SCB_TAG value or SCB_CONTROL byte.
+   */
+  if (p->flags & AHC_PAGESCBS)
+  {
+    unsigned char next;
+
+    j = 0;
+    next = aic_inb(p, FREE_SCBH);
+    if ( (next >= p->scb_data->maxhscbs) && (next != SCB_LIST_NULL) )
+    {
+      printk(WARN_LEAD "Bogus FREE_SCBH!.\n", p->host_no, channel,
+        target, lun);
+      init_lists = TRUE;
+      next = SCB_LIST_NULL;
+    }
+    while ( (next != SCB_LIST_NULL) && (j++ <= (p->scb_data->maxscbs + 1)) )
+    {
+      aic_outb(p, next, SCBPTR);
+      if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs)
+      {
+        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+          target, lun);
+        init_lists = TRUE;
+        next = SCB_LIST_NULL;
+      }
+      else
+      {
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        next = aic_inb(p, SCB_NEXT);
+      }
+    }
+    if ( j > (p->scb_data->maxscbs + 1) )
+    {
+      printk(WARN_LEAD "Yikes!!  There is a loop in the free list!\n",
+        p->host_no, channel, target, lun);
+      init_lists = TRUE;
+    }
+  }
+
+  /*
+   * Go through the hardware SCB array looking for commands that
+   * were active but not on any list.
+   */
+  if (init_lists)
+  {
+    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+  }
+  for (i = p->scb_data->maxhscbs - 1; i >= 0; i--)
+  {
+    unsigned char scbid;
+
+    aic_outb(p, i, SCBPTR);
+    if (init_lists)
+    {
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+      aic_outb(p, 0, SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    else
+    {
+      scbid = aic_inb(p, SCB_TAG);
+      if (scbid < p->scb_data->numscbs)
+      {
+        scbp = p->scb_data->scb_array[scbid];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          aic_outb(p, 0, SCB_CONTROL);
+          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+          aic7xxx_add_curscb_to_free_list(p);
+        }
+      }
+    }
+  }
+
+  /*
+   * Go through the entire SCB array now and look for commands for
+   * for this target that are stillactive.  These are other (most likely
+   * tagged) commands that were disconnected when the reset occurred.
+   * Any commands we find here we know this about, it wasn't on any queue,
+   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+   * lists, so it really must have been a paged out SCB.  In that case,
+   * we shouldn't need to bother with updating any counters, just mark
+   * the correct flags and go on.
+   */
+  for (i = 0; i < p->scb_data->numscbs; i++)
+  {
+    scbp = p->scb_data->scb_array[i];
+    if ((scbp->flags & SCB_ACTIVE) &&
+        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+        !aic7xxx_scb_on_qoutfifo(p, scbp))
+    {
+      if (scbp->flags & SCB_WAITINGQ)
+      {
+        scbq_remove(&p->waiting_scbs, scbp);
+        scbq_remove(&p->delayed_scbs[TARGET_INDEX(scbp->cmd)], scbp);
+        p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
+        p->activescbs++;
+      }
+      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+    }
+  }
+
+  aic_outb(p, active_scb, SCBPTR);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_clear_intstat
+ *
+ * Description:
+ *   Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+  /* Clear any interrupt conditions this may have caused. */
+  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, CLRSINT1);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset_current_bus
+ *
+ * Description:
+ *   Reset the current SCSI bus.
+ *-F*************************************************************************/
+static void
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
+{
+
+  /* Disable reset interrupts. */
+  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
+
+  /* Turn off the bus' current operations, after all, we shouldn't have any
+   * valid commands left to cause a RSELI and SELO once we've tossed the
+   * bus away with this reset, so we might as well shut down the sequencer
+   * until the bus is restarted as oppossed to saving the current settings
+   * and restoring them (which makes no sense to me). */
+
+  /* Turn on the bus reset. */
+  aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ);
+  while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
+    mdelay(5);
+
+  /*
+   * Some of the new Ultra2 chipsets need a longer delay after a chip
+   * reset than just the init setup creates, so we have to delay here
+   * before we go into a reset in order to make the chips happy.
+   */
+  if (p->features & AHC_ULTRA2)
+    mdelay(250);
+  else
+    mdelay(50);
+
+  /* Turn off the bus reset. */
+  aic_outb(p, 0, SCSISEQ);
+  mdelay(10);
+
+  aic7xxx_clear_intstat(p);
+  /* Re-enable reset interrupts. */
+  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset_channel
+ *
+ * Description:
+ *   Reset the channel.
+ *-F*************************************************************************/
+static void
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
+{
+  unsigned long offset_min, offset_max;
+  unsigned char sblkctl;
+  int cur_channel;
+
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
+
+
+  if (channel == 1)
+  {
+    p->needsdtr |= (p->needsdtr_copy & 0xFF00);
+    p->dtr_pending &= 0x00FF;
+    offset_min = 8;
+    offset_max = 16;
+  }
+  else
+  {
+    if (p->features & AHC_TWIN)
+    {
+      /* Channel A */
+      p->needsdtr |= (p->needsdtr_copy & 0x00FF);
+      p->dtr_pending &= 0xFF00;
+      offset_min = 0;
+      offset_max = 8;
+    }
+    else
+    {
+      p->needppr = p->needppr_copy;
+      p->needsdtr = p->needsdtr_copy;
+      p->needwdtr = p->needwdtr_copy;
+      p->dtr_pending = 0x0;
+      offset_min = 0;
+      if (p->features & AHC_WIDE)
+      {
+        offset_max = 16;
+      }
+      else
+      {
+        offset_max = 8;
+      }
+    }
+  }
+
+  while (offset_min < offset_max)
+  {
+    /*
+     * Revert to async/narrow transfers until we renegotiate.
+     */
+    aic_outb(p, 0, TARG_SCSIRATE + offset_min);
+    if (p->features & AHC_ULTRA2)
+    {
+      aic_outb(p, 0, TARG_OFFSET + offset_min);
+    }
+    offset_min++;
+  }
+
+  /*
+   * Reset the bus and unpause/restart the controller
+   */
+  sblkctl = aic_inb(p, SBLKCTL);
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+    cur_channel = (sblkctl & SELBUSB) >> 3;
+  else
+    cur_channel = 0;
+  if ( (cur_channel != channel) && (p->features & AHC_TWIN) )
+  {
+    /*
+     * Case 1: Command for another bus is active
+     */
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+        channel, -1, -1);
+    /*
+     * Stealthily reset the other bus without upsetting the current bus.
+     */
+    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
+    if (initiate_reset)
+    {
+      aic7xxx_reset_current_bus(p);
+    }
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
+    aic7xxx_clear_intstat(p);
+    aic_outb(p, sblkctl, SBLKCTL);
+  }
+  else
+  {
+    /*
+     * Case 2: A command from this bus is active or we're idle.
+     */
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+        channel, -1, -1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    p->msg_type = MSG_TYPE_NONE;
+    p->msg_len = 0;
+    if (initiate_reset)
+    {
+      aic7xxx_reset_current_bus(p);
+    }
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
+    aic7xxx_clear_intstat(p);
+  }
+  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
+  /*
+   * Clean up all the state information for the pending transactions
+   * on this bus.
+   */
+  aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+
+  if ( !(p->features & AHC_TWIN) )
+  {
+    restart_sequencer(p);
+  }
+
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_run_waiting_queues
+ *
+ * Description:
+ *   Scan the awaiting_scbs queue downloading and starting as many
+ *   scbs as we can.
+ *-F*************************************************************************/
+static void
+aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb *scb;
+  int tindex;
+  int sent;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+
+
+  if (p->waiting_scbs.head == NULL)
+    return;
+
+  sent = 0;
+
+  /*
+   * First handle SCBs that are waiting but have been assigned a slot.
+   */
+  DRIVER_LOCK
+  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
+  {
+    tindex = TARGET_INDEX(scb->cmd);
+    if ( !scb->tag_action && (p->tagenable & (1<<tindex)) )
+    {
+      p->dev_temp_queue_depth[tindex] = 1;
+    }
+    if ( (p->dev_active_cmds[tindex] >=
+          p->dev_temp_queue_depth[tindex]) ||
+         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) ||
+         (p->flags & AHC_RESET_DELAY) )
+    {
+      scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+    }
+    else
+    {
+        scb->flags &= ~SCB_WAITINGQ;
+        p->dev_active_cmds[tindex]++;
+        p->activescbs++;
+        if ( !(scb->tag_action) )
+        {
+          aic7xxx_busy_target(p, scb);
+        }
+        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+        sent++;
+    }
+  }
+  if (sent)
+  {
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
+    }
+    if (p->activescbs > p->max_activescbs)
+      p->max_activescbs = p->activescbs;
+  }
+  DRIVER_UNLOCK
+}
+
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_pci_intr
+ *
+ * Description:
+ *   Check the scsi card for PCI errors and clear the interrupt
+ *
+ *   NOTE: If you don't have this function and a 2940 card encounters
+ *         a PCI error condition, the machine will end up locked as the
+ *         interrupt handler gets slammed with non-stop PCI error interrupts
+ *-F*************************************************************************/
+static void
+aic7xxx_pci_intr(struct aic7xxx_host *p)
+{
+  unsigned char status1;
+
+  pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1);
+
+  if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+      "phase.\n", p->host_no, -1, -1, -1);
+  if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+      "PERR#\n", p->host_no, -1, -1, -1);
+  
+  pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1);
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+  if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) )
+    aic7xxx_panic_abort(p, NULL);
+
+}
+#endif /* CONFIG_PCI */
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_timer
+ *
+ * Description:
+ *   Take expired extries off of delayed queues and place on waiting queue
+ *   then run waiting queue to start commands.
+ ***************************************************************************/
+static void
+aic7xxx_timer(struct aic7xxx_host *p)
+{
+  int i, j;
+  unsigned long cpu_flags = 0;
+  struct aic7xxx_scb *scb;
+
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
+  if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
+       time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
+  {
+    p->flags &= ~AHC_RESET_DELAY;
+    p->dev_timer_active &= ~(0x01 << p->scsi_id);
+  }
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if ( (i != p->scsi_id) &&
+         (p->dev_timer_active & (0x01 << i)) &&
+         time_after_eq(jiffies, p->dev_expires[i]) )
+    {
+      p->dev_timer_active &= ~(0x01 << i);
+      p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY);
+      p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
+      j = 0;
+      while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
+              (j++ < p->scb_data->numscbs) )
+      {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+      }
+      if (j == p->scb_data->numscbs)
+      {
+        printk(INFO_LEAD "timer: Yikes, loop in delayed_scbs list.\n",
+          p->host_no, 0, i, -1);
+        scbq_init(&p->delayed_scbs[i]);
+        scbq_init(&p->waiting_scbs);
+        /*
+         * Well, things are screwed now, wait for a reset to clean the junk
+         * out.
+         */
+      }
+    }
+    else if ( p->dev_timer_active & (0x01 << i) )
+    {
+      if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
+      {
+        if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
+        {
+          p->dev_timer.expires = p->dev_expires[i];
+        }
+      }
+      else
+      {
+        p->dev_timer.expires = p->dev_expires[i];
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+      }
+    }
+  }
+  if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
+  {
+    add_timer(&p->dev_timer);
+  }
+
+  aic7xxx_run_waiting_queues(p);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_ppr
+ *
+ * Description:
+ *   Build up a Parallel Protocol Request message for use with SCSI-3
+ *   devices.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int tindex = TARGET_INDEX(scb->cmd);
+
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
+  p->msg_buf[p->msg_index++] = 0;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
+  p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
+  p->msg_len += 8;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_sdtr
+ *
+ * Description:
+ *   Constucts a synchronous data transfer message in the message
+ *   buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
+        unsigned char offset)
+{
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+  p->msg_buf[p->msg_index++] = period;
+  p->msg_buf[p->msg_index++] = offset;
+  p->msg_len += 5;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_wdtr
+ *
+ * Description:
+ *   Constucts a wide data transfer message in the message buffer
+ *   on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
+{
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+  p->msg_buf[p->msg_index++] = bus_width;
+  p->msg_len += 4;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_calc_residual
+ *
+ * Description:
+ *   Calculate the residual data not yet transferred.
+ *-F*************************************************************************/
+static void
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  struct aic7xxx_hwscb *hscb;
+  Scsi_Cmnd *cmd;
+  int actual, i;
+
+  cmd = scb->cmd;
+  hscb = scb->hscb;
+
+  /*
+   *  Don't destroy valid residual information with
+   *  residual coming from a check sense operation.
+   */
+  if (((scb->hscb->control & DISCONNECTED) == 0) &&
+      (scb->flags & SCB_SENSE) == 0)
+  {
+    /*
+     *  We had an underflow. At this time, there's only
+     *  one other driver that bothers to check for this,
+     *  and cmd->underflow seems to be set rather half-
+     *  heartedly in the higher-level SCSI code.
+     */
+    actual = scb->sg_length;
+    for (i=1; i < hscb->residual_SG_segment_count; i++)
+    {
+      actual -= scb->sg_list[scb->sg_count - i].length;
+    }
+    actual -= (hscb->residual_data_count[2] << 16) |
+              (hscb->residual_data_count[1] <<  8) |
+              hscb->residual_data_count[0];
+
+    if (actual < cmd->underflow)
+    {
+      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+          (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+          hscb->residual_SG_segment_count);
+      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+      aic7xxx_status(cmd) = hscb->target_status;
+    }
+  }
+
+  /*
+   * Clean out the residual information in the SCB for the
+   * next consumer.
+   */
+  hscb->residual_data_count[2] = 0;
+  hscb->residual_data_count[1] = 0;
+  hscb->residual_data_count[0] = 0;
+  hscb->residual_SG_segment_count = 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_device_reset
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
+{
+  unsigned short targ_mask;
+  unsigned char tindex = target;
+
+  tindex |= ((channel & 0x01) << 3);
+
+  targ_mask = (0x01 << tindex);
+  /*
+   * Go back to async/narrow transfers and renegotiate.
+   */
+  p->needppr |= (p->needppr_copy & targ_mask);
+  p->needsdtr |= (p->needsdtr_copy & targ_mask);
+  p->needwdtr |= (p->needwdtr_copy & targ_mask);
+  p->dtr_pending &= ~targ_mask;
+  aic_outb(p, 0, TARG_SCSIRATE + tindex);
+  if (p->features & AHC_ULTRA2)
+    aic_outb(p, 0, TARG_OFFSET + tindex);
+  aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+      target, -1);
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_seqint
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  struct aic7xxx_scb *scb;
+  unsigned short target_mask;
+  unsigned char target, lun, tindex;
+  unsigned char queue_flag = FALSE;
+  char channel;
+
+  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+  else
+    channel = 0;
+  tindex = target + (channel << 3);
+  lun = aic_inb(p, SAVED_TCL) & 0x07;
+  target_mask = (0x01 << tindex);
+
+  /*
+   * Go ahead and clear the SEQINT now, that avoids any interrupt race
+   * conditions later on in case we enable some other interrupt.
+   */
+  aic_outb(p, CLRSEQINT, CLRINT);
+  switch (intstat & SEQINT_MASK)
+  {
+    case NO_MATCH:
+      {
+        aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
+                 SCSISEQ);
+        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               p->host_no, channel, target, lun,
+               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+        if (aic7xxx_panic_on_abort)
+          aic7xxx_panic_abort(p, NULL);
+      }
+      break;
+
+    case SEND_REJECT:
+      {
+        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
+      }
+      break;
+
+    case NO_IDENT:
+      {
+        /*
+         * The reconnecting target either did not send an identify
+         * message, or did, but we didn't find an SCB to match and
+         * before it could respond to our ATN/abort, it hit a dataphase.
+         * The only safe thing to do is to blow it away with a bus
+         * reset.
+         */
+        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
+
+        aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+        aic7xxx_run_done_queue(p, TRUE);
+
+      }
+      break;
+
+    case BAD_PHASE:
+      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
+      {
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+            target, lun);
+        restart_sequencer(p);
+      }
+      else
+      {
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+            channel, target, lun);
+      }
+      break;
+
+    case EXTENDED_MSG:
+      {
+        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+        p->msg_len = 0;
+        p->msg_index = 0;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if (aic7xxx_verbose > 0xffff)
+          printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no,
+                 channel, target, lun);
+#endif
+
+       /*      
+        * To actually receive the message, simply turn on
+        * REQINIT interrupts and let our interrupt handler
+        * do the rest (REQINIT should already be true).
+        */
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+
+       /*
+        * We don't want the sequencer unpaused yet so we return early
+        */
+        return;
+      }
+
+    case REJECT_MSG:
+      {
+        /*
+         * What we care about here is if we had an outstanding SDTR
+         * or WDTR message for this target. If we did, this is a
+         * signal that the target is refusing negotiation.
+         */
+        unsigned char scb_index;
+        unsigned char last_msg;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+        last_msg = aic_inb(p, LAST_MSG);
+
+        if ( (last_msg == MSG_IDENTIFYFLAG) &&
+             (scb->tag_action) &&
+            !(scb->flags & SCB_MSGOUT_BITS) )
+        {
+          if (scb->tag_action == MSG_ORDERED_Q_TAG)
+          {
+            /*
+             * OK...the device seems able to accept tagged commands, but
+             * not ordered tag commands, only simple tag commands.  So, we
+             * disable ordered tag commands and go on with life just like
+             * normal.
+             */
+            p->orderedtag &= ~target_mask;
+            scb->tag_action = MSG_SIMPLE_Q_TAG;
+            scb->hscb->control &= ~SCB_TAG_TYPE;
+            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+            aic_outb(p, scb->hscb->control, SCB_CONTROL);
+            /*
+             * OK..we set the tag type to simple tag command, now we re-assert
+             * ATNO and hope this will take us into the identify phase again
+             * so we can resend the tag type and info to the device.
+             */
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+          else if (scb->tag_action == MSG_SIMPLE_Q_TAG)
+          {
+            unsigned char i, reset = 0;
+            struct aic7xxx_scb *scbp;
+            int old_verbose;
+            /*
+             * Hmmmm....the device is flaking out on tagged commands.  The
+             * bad thing is that we already have tagged commands enabled in
+             * the device struct in the mid level code.  We also have a queue
+             * set according to the tagged queue depth.  Gonna have to live
+             * with it by controlling our queue depth internally and making
+             * sure we don't set the tagged command flag any more.
+             */
+            p->tagenable &= ~target_mask;
+            p->orderedtag &= ~target_mask;
+            p->dev_max_queue_depth[tindex] =
+               p->dev_temp_queue_depth[tindex] = 1;
+            /*
+             * We set this command up as a bus device reset.  However, we have
+             * to clear the tag type as it's causing us problems.  We shouldnt
+             * have to worry about any other commands being active, since if
+             * the device is refusing tagged commands, this should be the
+             * first tagged command sent to the device, however, we do have
+             * to worry about any other tagged commands that may already be
+             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
+             * send all the commands back to the mid level code, then let them
+             * come back and get rebuilt as untagged commands.
+             */
+            scb->tag_action = 0;
+            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
+
+            old_verbose = aic7xxx_verbose;
+            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+            for (i=0; i!=p->scb_data->numscbs; i++)
+            {
+              scbp = p->scb_data->scb_array[i];
+              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
+              {
+                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+                {
+                  aic7xxx_reset_device(p, target, channel, lun, i);
+                  reset++;
+                }
+                aic7xxx_run_done_queue(p, TRUE);
+              }
+            }
+            aic7xxx_verbose = old_verbose;
+            /*
+             * Wait until after the for loop to set the busy index since
+             * aic7xxx_reset_device will clear the busy index during its
+             * operation.
+             */
+            aic7xxx_busy_target(p, scb);
+            printk(INFO_LEAD "Device is refusing tagged commands, using "
+              "untagged I/O.\n", p->host_no, channel, target, lun);
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          /*
+           * As per the draft specs, any device capable of supporting any of
+           * the option values other than 0 are not allowed to reject the
+           * PPR message.  Instead, they must negotiate out what they do
+           * support instead of rejecting our offering or else they cause
+           * a parity error during msg_out phase to signal that they don't
+           * like our settings.
+           */
+          p->needppr &= ~target_mask;
+          p->needppr_copy &= ~target_mask;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+          p->transinfo[tindex].goal_options = 0;
+          p->dtr_pending &= ~target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting PPR messages, falling "
+              "back.\n", p->host_no, channel, target, lun);
+          }
+          if ( p->transinfo[tindex].goal_width )
+          {
+            p->needwdtr |= target_mask;
+            p->needwdtr_copy |= target_mask;
+            p->dtr_pending |= target_mask;
+            scb->flags |= SCB_MSGOUT_WDTR;
+          }
+          if ( p->transinfo[tindex].goal_offset )
+          {
+            p->needsdtr |= target_mask;
+            p->needsdtr_copy |= target_mask;
+            if( !(p->dtr_pending & target_mask) )
+            {
+              p->dtr_pending |= target_mask;
+              scb->flags |= SCB_MSGOUT_SDTR;
+            }
+          }
+          if ( p->dtr_pending & target_mask )
+          {
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          /*
+           * note 8bit xfers and clear flag
+           */
+          p->needwdtr &= ~target_mask;
+          p->needwdtr_copy &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting WDTR messages, using "
+              "narrow transfers.\n", p->host_no, channel, target, lun);
+          }
+          p->needsdtr |= (p->needsdtr_copy & target_mask);
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+         /*
+          * note asynch xfers and clear flag
+          */
+          p->needsdtr &= ~target_mask;
+          p->needsdtr_copy &= ~target_mask;
+          p->dtr_pending &= ~target_mask;
+          scb->flags &= ~SCB_MSGOUT_SDTR;
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+            (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting SDTR messages, using "
+              "async transfers.\n", p->host_no, channel, target, lun);
+          }
+        }
+        else if (aic7xxx_verbose & VERBOSE_SEQINT)
+        {
+          /*
+           * Otherwise, we ignore it.
+           */
+          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
+            "Ignoring.\n", p->host_no, channel, target, lun);
+        }
+      }
+      break;
+
+    case BAD_STATUS:
+      {
+        unsigned char scb_index;
+        struct aic7xxx_hwscb *hscb;
+        Scsi_Cmnd *cmd;
+
+        /* The sequencer will notify us when a command has an error that
+         * would be of interest to the kernel.  This allows us to leave
+         * the sequencer running in the common case of command completes
+         * without error.  The sequencer will have DMA'd the SCB back
+         * up to us, so we can reference the drivers SCB array.
+         *
+         * Set the default return value to 0 indicating not to send
+         * sense.  The sense code will change this if needed and this
+         * reduces code duplication.
+         */
+        aic_outb(p, 0, RETURN_1);
+        scb_index = aic_inb(p, SCB_TAG);
+        if (scb_index > p->scb_data->numscbs)
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+            p->host_no, channel, target, lun, intstat, scb_index);
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        hscb = scb->hscb;
+
+        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+            scb_index, scb->flags, (unsigned long) scb->cmd);
+        }
+        else
+        {
+          cmd = scb->cmd;
+          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
+          aic7xxx_status(cmd) = hscb->target_status;
+
+          cmd->result = hscb->target_status;
+
+          switch (status_byte(hscb->target_status))
+          {
+            case GOOD:
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+                  p->host_no, CTL_OF_SCB(scb));
+              break;
+
+            case COMMAND_TERMINATED:
+            case CHECK_CONDITION:
+              if ( !(scb->flags & SCB_SENSE) )
+              {
+                /*
+                 * Send a sense command to the requesting target.
+                 * XXX - revisit this and get rid of the memcopys.
+                 */
+                memcpy(scb->sense_cmd, &generic_sense[0],
+                       sizeof(generic_sense));
+
+                scb->sense_cmd[1] = (cmd->lun << 5);
+                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+                scb->sg_list[0].length = 
+                  cpu_to_le32(sizeof(cmd->sense_buffer));
+		scb->sg_list[0].address =
+                        cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
+                                                   sizeof(cmd->sense_buffer),
+                                                   PCI_DMA_FROMDEVICE));
+
+                /*
+                 * XXX - We should allow disconnection, but can't as it
+                 * might allow overlapped tagged commands.
+                 */
+                /* hscb->control &= DISCENB; */
+                hscb->control = 0;
+                hscb->target_status = 0;
+                hscb->SG_list_pointer = 
+		  cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
+                hscb->SCSI_cmd_pointer = 
+                  cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
+                hscb->data_count = scb->sg_list[0].length;
+                hscb->data_pointer = scb->sg_list[0].address;
+                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->residual_SG_segment_count = 0;
+                hscb->residual_data_count[0] = 0;
+                hscb->residual_data_count[1] = 0;
+                hscb->residual_data_count[2] = 0;
+
+                scb->sg_count = hscb->SG_segment_count = 1;
+                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->tag_action = 0;
+                scb->flags |= SCB_SENSE;
+                /*
+                 * Ensure the target is busy since this will be an
+                 * an untagged request.
+                 */
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+                if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+                {
+                  if (scb->flags & SCB_MSGOUT_BITS)
+                    printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
+                           CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ?
+                           "SDTR" : "WDTR");
+                  else
+                    printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no,
+                           CTL_OF_SCB(scb));
+                }
+#endif
+                aic7xxx_busy_target(p, scb);
+                aic_outb(p, SEND_SENSE, RETURN_1);
+                aic7xxx_error(cmd) = DID_OK;
+                break;
+              }  /* first time sense, no errors */
+              aic7xxx_error(cmd) = DID_ERROR;
+              scb->flags &= ~SCB_SENSE;
+              break;
+
+            case QUEUE_FULL:
+              queue_flag = TRUE;    /* Mark that this is a QUEUE_FULL and */
+            case BUSY:              /* drop through to here */
+            {
+              struct aic7xxx_scb *next_scbp, *prev_scbp;
+              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+              /*
+               * We have to look three places for queued commands:
+               *  1: QINFIFO
+               *  2: p->waiting_scbs queue
+               *  3: WAITING_SCBS list on card (for commands that are started
+               *     but haven't yet made it to the device)
+               */
+              aic7xxx_search_qinfifo(p, target, channel, lun,
+                SCB_LIST_NULL, 0, TRUE,
+                &p->delayed_scbs[tindex]);
+              next_scbp = p->waiting_scbs.head;
+              while ( next_scbp != NULL )
+              {
+                prev_scbp = next_scbp;
+                next_scbp = next_scbp->q_next;
+                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
+                     SCB_LIST_NULL) )
+                {
+                  scbq_remove(&p->waiting_scbs, prev_scbp);
+                  scbq_insert_tail(&p->delayed_scbs[tindex],
+                    prev_scbp);
+                }
+              }
+              next_scbp = NULL;
+              active_hscb = aic_inb(p, SCBPTR);
+              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+              next_hscb = aic_inb(p, WAITING_SCBH);
+              while (next_hscb != SCB_LIST_NULL)
+              {
+                aic_outb(p, next_hscb, SCBPTR);
+                scb_index = aic_inb(p, SCB_TAG);
+                if (scb_index < p->scb_data->numscbs)
+                {
+                  next_scbp = p->scb_data->scb_array[scb_index];
+                  if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                      SCB_LIST_NULL) )
+                  {
+                    if (next_scbp->flags & SCB_WAITINGQ)
+                    {
+                      p->dev_active_cmds[tindex]++;
+                      p->activescbs--;
+                      scbq_remove(&p->delayed_scbs[tindex], next_scbp);
+                      scbq_remove(&p->waiting_scbs, next_scbp);
+                    }
+                    scbq_insert_head(&p->delayed_scbs[tindex],
+                      next_scbp);
+                    next_scbp->flags |= SCB_WAITINGQ;
+                    p->dev_active_cmds[tindex]--;
+                    p->activescbs--;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                    aic_outb(p, 0, SCB_CONTROL);
+                    aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                    aic7xxx_add_curscb_to_free_list(p);
+                    if (prev_hscb == SCB_LIST_NULL)
+                    {
+                      /* We were first on the list,
+                       * so we kill the selection
+                       * hardware.  Let the sequencer
+                       * re-init the hardware itself
+                       */
+                      aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+                      aic_outb(p, CLRSELTIMEO, CLRSINT1);
+                      aic_outb(p, next_hscb, WAITING_SCBH);
+                    }
+                    else
+                    {
+                      aic_outb(p, prev_hscb, SCBPTR);
+                      aic_outb(p, next_hscb, SCB_NEXT);
+                    }
+                  }
+                  else
+                  {
+                    prev_hscb = next_hscb;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                  }
+                } /* scb_index >= p->scb_data->numscbs */
+              }
+              aic_outb(p, active_hscb, SCBPTR);
+              if (scb->flags & SCB_WAITINGQ)
+              {
+                scbq_remove(&p->delayed_scbs[tindex], scb);
+                scbq_remove(&p->waiting_scbs, scb);
+                p->dev_active_cmds[tindex]++;
+                p->activescbs++;
+              }
+              scbq_insert_head(&p->delayed_scbs[tindex], scb);
+              p->dev_active_cmds[tindex]--;
+              p->activescbs--;
+              scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+                  
+              if ( !(p->dev_timer_active & (0x01 << tindex)) ) 
+              {
+                p->dev_timer_active |= (0x01 << tindex);
+                if ( p->dev_active_cmds[tindex] )
+                {
+                  p->dev_expires[tindex] = jiffies + HZ;
+                }
+                else
+                {
+                  p->dev_expires[tindex] = jiffies + (HZ / 10);
+                }
+                if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) )
+                {
+                  p->dev_timer.expires = p->dev_expires[tindex];
+                  p->dev_timer_active |= (0x01 << MAX_TARGETS);
+                  add_timer(&p->dev_timer);
+                }
+                else if ( time_after_eq(p->dev_timer.expires,
+                                        p->dev_expires[tindex]) )
+                  mod_timer(&p->dev_timer, p->dev_expires[tindex]);
+              }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+              if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
+                  (aic7xxx_verbose > 0xffff) )
+              {
+                if (queue_flag)
+                  printk(INFO_LEAD "Queue full received; queue depth %d, "
+                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
+                    p->dev_max_queue_depth[tindex],
+                    p->dev_active_cmds[tindex]);
+                else
+                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
+
+              }
+#endif
+              if (queue_flag)
+              {
+                if ( p->dev_last_queue_full[tindex] !=
+                     p->dev_active_cmds[tindex] )
+                {
+                  p->dev_last_queue_full[tindex] = 
+                      p->dev_active_cmds[tindex];
+                  p->dev_last_queue_full_count[tindex] = 0;
+                }
+                else
+                {
+                  p->dev_last_queue_full_count[tindex]++;
+                }
+                if ( (p->dev_last_queue_full_count[tindex] > 14) &&
+                     (p->dev_active_cmds[tindex] > 4) )
+                {
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+                      CTL_OF_SCB(scb), p->dev_active_cmds[tindex]);
+                  p->dev_max_queue_depth[tindex] = 
+                      p->dev_active_cmds[tindex];
+                  p->dev_last_queue_full[tindex] = 0;
+                  p->dev_last_queue_full_count[tindex] = 0;
+                  p->dev_temp_queue_depth[tindex] = 
+                    p->dev_active_cmds[tindex];
+                }
+                else if (p->dev_active_cmds[tindex] == 0)
+                {
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+                  {
+                    printk(INFO_LEAD "QUEUE_FULL status received with 0 "
+                           "commands active.\n", p->host_no, CTL_OF_SCB(scb));
+                    printk(INFO_LEAD "Tagged Command Queueing disabled\n",
+                           p->host_no, CTL_OF_SCB(scb));
+                  }
+                  p->dev_max_queue_depth[tindex] = 1;
+                  p->dev_temp_queue_depth[tindex] = 1;
+                  scb->tag_action = 0;
+                  scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG);
+                }
+                else
+                {
+                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+                  p->dev_temp_queue_depth[tindex] = 
+                    p->dev_active_cmds[tindex];
+                }
+              }
+              break;
+            }
+            
+            default:
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+                     CTL_OF_SCB(scb), scb->hscb->target_status);
+              if (!aic7xxx_error(cmd))
+              {
+                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+              }
+              break;
+          }  /* end switch */
+        }  /* end else of */
+      }
+      break;
+
+    case AWAITING_MSG:
+      {
+        unsigned char scb_index, msg_out;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        msg_out = aic_inb(p, MSG_OUT);
+        scb = p->scb_data->scb_array[scb_index];
+        p->msg_index = p->msg_len = 0;
+        /*
+         * This SCB had a MK_MESSAGE set in its control byte informing
+         * the sequencer that we wanted to send a special message to
+         * this target.
+         */
+
+        if ( !(scb->flags & SCB_DEVICE_RESET) &&
+              (msg_out == MSG_IDENTIFYFLAG) &&
+              (scb->hscb->control & TAG_ENB) )
+        {
+          p->msg_buf[p->msg_index++] = scb->tag_action;
+          p->msg_buf[p->msg_index++] = scb->hscb->tag;
+          p->msg_len += 2;
+        }
+
+        if (scb->flags & SCB_DEVICE_RESET)
+        {
+          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+            printk(INFO_LEAD "Bus device reset mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_ABORT)
+        {
+          if (scb->tag_action)
+          {
+            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
+          }
+          else
+          {
+            p->msg_buf[p->msg_index++] = MSG_ABORT;
+          }
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+              CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
+                   p->host_no, CTL_OF_SCB(scb),
+                   p->transinfo[tindex].goal_period,
+                   p->transinfo[tindex].goal_offset,
+                   p->transinfo[tindex].goal_width,
+                   p->transinfo[tindex].goal_options);
+          }
+          aic7xxx_construct_ppr(p, scb);
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
+                   CTL_OF_SCB(scb));
+          }
+          aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          unsigned int max_sync, period;
+          unsigned char options = 0;
+          /*
+           * Now that the device is selected, use the bits in SBLKCTL and
+           * SSTAT2 to determine the max sync rate for this device.
+           */
+          if (p->features & AHC_ULTRA2)
+          {
+            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+            {
+              max_sync = AHC_SYNCRATE_ULTRA2;
+            }
+            else
+            {
+              max_sync = AHC_SYNCRATE_ULTRA;
+            }
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            max_sync = AHC_SYNCRATE_ULTRA;
+          }
+          else
+          {
+            max_sync = AHC_SYNCRATE_FAST;
+          }
+          period = p->transinfo[tindex].goal_period;
+          aic7xxx_find_syncrate(p, &period, max_sync, &options);
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
+                   CTL_OF_SCB(scb), period,
+                   p->transinfo[tindex].goal_offset);
+          }
+          aic7xxx_construct_sdtr(p, period,
+            p->transinfo[tindex].goal_offset);
+        }
+        else 
+        {
+          sti();
+          panic("aic7xxx: AWAITING_MSG for an SCB that does "
+                "not have a waiting message.\n");
+        }
+        /*
+         * We've set everything up to send our message, now to actually do
+         * so we need to enable reqinit interrupts and let the interrupt
+         * handler do the rest.  We don't want to unpause the sequencer yet
+         * though so we'll return early.  We also have to make sure that
+         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+         * or else it's possible on VLB cards to loose the first REQINIT
+         * interrupt.  Edge triggered EISA cards could also loose this
+         * interrupt, although PCI and level triggered cards should not
+         * have this problem since they continually interrupt the kernel
+         * until we take care of the situation.
+         */
+        scb->flags |= SCB_MSGOUT_SENT;
+        p->msg_index = 0;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+        return;
+      }
+      break;
+
+    case DATA_OVERRUN:
+      {
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned char lastphase = aic_inb(p, LASTPHASE);
+        unsigned int i;
+
+        scb = (p->scb_data->scb_array[scb_index]);
+        /*
+         * XXX - What do we really want to do on an overrun?  The
+         *       mid-level SCSI code should handle this, but for now,
+         *       we'll just indicate that the command should retried.
+         *    If we retrieved sense info on this target, then the 
+         *    base SENSE info should have been saved prior to the
+         *    overrun error.  In that case, we return DID_OK and let
+         *    the mid level code pick up on the sense info.  Otherwise
+         *    we return DID_ERROR so the command will get retried.
+         */
+        if ( !(scb->flags & SCB_SENSE) )
+        {
+          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+            p->host_no, CTL_OF_SCB(scb), 
+            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+            scb->sg_length, scb->sg_count);
+          for (i = 0; i < scb->sg_count; i++)
+          {
+            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, 
+                 le32_to_cpu(scb->sg_list[i].address),
+                 le32_to_cpu(scb->sg_list[i].length) );
+          }
+          aic7xxx_error(scb->cmd) = DID_ERROR;
+        }
+        else
+          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+            p->host_no, CTL_OF_SCB(scb));
+      }
+      break;
+
+    case WIDE_RESIDUE:
+      {
+        unsigned char resid_sgcnt, index;
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned int cur_addr, resid_dcnt;
+        unsigned int native_addr, native_length;
+        int i;
+
+        if(scb_index > p->scb_data->numscbs)
+        {
+          printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n",
+            p->host_no, -1, -1, -1);
+          /*
+           * XXX: Add error handling here
+           */
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x "
+                 "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb),
+                 scb->flags, (unsigned long)scb->cmd);
+          break;
+        }
+
+        /*
+         * We have a valid scb to use on this WIDE_RESIDUE message, so
+         * we need to walk the sg list looking for this particular sg
+         * segment, then see if we happen to be at the very beginning of
+         * the segment.  If we are, then we have to back things up to
+         * the previous segment.  If not, then we simply need to remove
+         * one byte from this segments address and add one to the byte
+         * count.
+         */
+        cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
+          (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+        resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
+        resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
+          (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
+          (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
+        index = scb->sg_count - (resid_sgcnt + 1);
+        native_addr = le32_to_cpu(scb->sg_list[index].address);
+        native_length = le32_to_cpu(scb->sg_list[index].length);
+        /*
+         * Make sure this is a valid sg_seg for the given pointer
+         */
+        if(cur_addr < native_addr ||
+           cur_addr > (native_addr + native_length + 1))
+        {
+          printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
+                 p->host_no, CTL_OF_SCB(scb), cur_addr);
+          if(index > 0)
+            printk(WARN_LEAD "  sg_address[-1]:0x%x sg_length[-1]:%d\n",
+                   p->host_no, CTL_OF_SCB(scb),
+                   le32_to_cpu(scb->sg_list[index - 1].address),
+                   le32_to_cpu(scb->sg_list[index - 1].length));
+          printk(WARN_LEAD "  sg_address:0x%x sg_length:%d\n",
+                 p->host_no, CTL_OF_SCB(scb),
+                 native_addr, native_length);
+          if(resid_sgcnt > 1)
+            printk(WARN_LEAD "  sg_address[1]:0x%x sg_length[1]:%d\n",
+                   p->host_no, CTL_OF_SCB(scb),
+                   le32_to_cpu(scb->sg_list[index + 1].address),
+                   le32_to_cpu(scb->sg_list[index + 1].length));
+          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
+                 p->host_no, CTL_OF_SCB(scb),
+                 cur_addr, resid_dcnt);
+          break;
+        }
+
+        if( (resid_sgcnt == 0) &&
+            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
+        {
+          /*
+           * We are at the end of the transfer and this is about a byte
+           * we ignored already (because the sequencer knew this was
+           * the last segment and set the adapter to ignore any wide
+           * residue bytes that might come through, which is only done
+           * on the last scatter gather segment of transfers).
+           */
+          break;
+        }
+        else if(cur_addr == native_addr)
+        {
+          /*
+           * If our current address matches the sg_seg->address then we
+           * have to back up the sg array to the previous segment and set
+           * it up to have only one byte of transfer left to go.
+           */
+          if(index == 0)
+          {
+            printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
+                   "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+            break;
+          }
+          resid_sgcnt++;
+          index--;
+          cur_addr = le32_to_cpu(scb->sg_list[index].address) + 
+            le32_to_cpu(scb->sg_list[index].length) - 1;
+          native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
+            | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
+          native_addr -= SG_SIZEOF;
+          aic_outb(p, resid_sgcnt, SG_COUNT);
+          aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+          aic_outb(p, native_addr & 0xff, SG_NEXT);
+          aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
+          aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
+          aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
+          aic_outb(p, 1, SCB_RESID_DCNT); 
+          aic_outb(p, 0, SCB_RESID_DCNT + 1); 
+          aic_outb(p, 0, SCB_RESID_DCNT + 2); 
+          aic_outb(p, 1, HCNT); 
+          aic_outb(p, 0, HCNT + 1); 
+          aic_outb(p, 0, HCNT + 2); 
+          aic_outb(p, cur_addr & 0xff, HADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+        }
+        else
+        {
+          /*
+           * Back the data pointer up by one and add one to the remaining
+           * byte count.  Then store that in the HCNT and HADDR registers.
+           */
+          cur_addr--;
+          resid_dcnt++;
+          aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); 
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); 
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); 
+          aic_outb(p, resid_dcnt & 0xff, HCNT); 
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); 
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); 
+          aic_outb(p, cur_addr & 0xff, HADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+        }
+        /*
+         * The sequencer actually wants to find the new address and byte
+         * count in the SHCNT and SHADDR register sets.  These registers
+         * are a shadow of the regular HCNT and HADDR registers.  On the
+         * Ultra2 controllers, these registers are read only and the way
+         * we have to set their values is to put the values we want into
+         * the HCNT and HADDR registers and then output PRELOADEN into
+         * the DFCNTRL register which causes the card to latch the current
+         * values in the HADDR and HCNT registers and drop it through to
+         * the shadow registers.  On older cards we copy them directly
+         * across by hand.
+         */
+        if(p->features & AHC_ULTRA2)
+        {
+          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+          i=0;
+          udelay(1);
+          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+          {
+            udelay(1);
+          }
+          aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
+          i=0;
+          udelay(1);
+          while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
+          {
+            udelay(1);
+          }
+        }
+        else
+        {
+          aic_outb(p, resid_dcnt & 0xff, STCNT); 
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
+          aic_outb(p, cur_addr & 0xff, SHADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+        }
+      }
+      break;
+
+        
+#if AIC7XXX_NOT_YET 
+    case TRACEPOINT:
+      {
+        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
+               channel, target, lun);
+      }
+      break;
+
+    case TRACEPOINT2:
+      {
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+               channel, target, lun);
+      }
+      break;
+
+    /* XXX Fill these in later */
+    case MSG_BUFFER_BUSY:
+      printk("aic7xxx: Message buffer busy.\n");
+      break;
+    case MSGIN_PHASEMIS:
+      printk("aic7xxx: Message-in phasemis.\n");
+      break;
+#endif
+
+    default:                   /* unknown */
+      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, channel, target, lun, intstat,
+             aic_inb(p, SCSISIGI));
+      break;
+  }
+
+  /*
+   * Clear the sequencer interrupt and unpause the sequencer.
+   */
+  unpause_sequencer(p, /* unpause always */ TRUE);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_parse_msg
+ *
+ * Description:
+ *   Parses incoming messages into actions on behalf of
+ *   aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int reject, reply, done;
+  unsigned char target_scsirate, tindex;
+  unsigned short target_mask;
+  unsigned char target, channel, lun;
+
+  target = scb->cmd->target;
+  channel = scb->cmd->channel;
+  lun = scb->cmd->lun;
+  reply = reject = done = FALSE;
+  tindex = TARGET_INDEX(scb->cmd);
+  target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+  target_mask = (0x01 << tindex);
+
+  /*
+   * Parse as much of the message as is availible,
+   * rejecting it if we don't support it.  When
+   * the entire message is availible and has been
+   * handled, return TRUE indicating that we have
+   * parsed an entire message.
+   */
+
+  if (p->msg_buf[0] != MSG_EXTENDED)
+  {
+    reject = TRUE;
+  }
+
+  /*
+   * Just accept the length byte outright and perform
+   * more checking once we know the message type.
+   */
+
+  if ( !reject && (p->msg_len > 2) )
+  {
+    switch(p->msg_buf[2])
+    {
+      case MSG_EXT_SDTR:
+      {
+        unsigned int period, offset;
+        unsigned char maxsync, saved_offset, options;
+        struct aic7xxx_syncrate *syncrate;
+        
+        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        saved_offset = offset = p->msg_buf[4];
+        options = 0;
+
+        /*
+         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+         * using the SDTR messages.  We need the PPR messages to enable the
+         * higher speeds that include things like Dual Edge clocking.
+         */
+        if (p->features & AHC_ULTRA2)
+        {
+          if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+               !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+          {
+            maxsync = AHC_SYNCRATE_ULTRA2;
+          }
+          else
+          {
+            maxsync = AHC_SYNCRATE_ULTRA;
+          }
+        }
+        else if (p->features & AHC_ULTRA)
+        {
+          maxsync = AHC_SYNCRATE_ULTRA;
+        }
+        else
+        {
+          maxsync = AHC_SYNCRATE_FAST;
+        }
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
+        {
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
+              !(p->needsdtr_copy & target_mask) &&
+               (p->transinfo[tindex].user_offset) )
+          {
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            if(p->features & AHC_ULTRA2)
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+            }
+            else if (p->transinfo[tindex].cur_width)
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+            }
+            else
+            {
+              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+            }
+            p->needsdtr_copy |= target_mask;
+          }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive SDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          if ( !p->transinfo[tindex].goal_offset )
+            period = 255;
+          if ( p->transinfo[tindex].goal_period > period )
+            period = p->transinfo[tindex].goal_period;
+        }
+  
+        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
+        aic7xxx_validate_offset(p, syncrate, &offset,
+                                target_scsirate & WIDEXFER);
+        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+
+        /*
+         * Did we drop to async?  Or are we sending a reply?  If we are,
+         * then we have to make sure that the reply value reflects the proper
+         * settings so we need to set the goal values according to what
+         * we need to send.
+         */
+        if ( (offset != saved_offset) ||
+             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
+        {
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
+                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+        }
+        
+        /*
+         * Did we start this, if not, or if we went to low and had to
+         * go async, then send an SDTR back to the target
+         */
+        p->needsdtr &= ~target_mask;
+        p->dtr_pending &= ~target_mask;
+        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
+             (offset != saved_offset) )
+        {
+          reply = TRUE;
+          p->dtr_pending |= target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_SDTR;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_WDTR:
+      {
+        unsigned char bus_width;
+          
+        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+        {
+          break;
+        }
+
+        bus_width = p->msg_buf[3];
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                    (aic7xxx_verbose > 0xffff)) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->needwdtr_copy &= ~target_mask;
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              break;
+            }
+          }
+          p->dtr_pending &= ~target_mask;
+          p->needwdtr &= ~target_mask;
+        }
+        else
+        {
+          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+          {
+            /* 
+             * Well, we now know the WDTR and SYNC caps of this device since
+             * it contacted us first, mark it as such and copy the user stuff
+             * over to the goal stuff.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            if(p->transinfo[tindex].user_offset)
+            {
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( p->transinfo[tindex].user_width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
+            }
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
+            p->needwdtr_copy |= target_mask;
+            p->needsdtr_copy |= target_mask;
+          }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          switch(bus_width)
+          {
+            default:
+            {
+              if ( (p->features & AHC_WIDE) &&
+                   (p->transinfo[tindex].goal_width ==
+                    MSG_EXT_WDTR_BUS_16_BIT) )
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              p->needwdtr_copy &= ~target_mask;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic7xxx_set_width(p, target, channel, lun, bus_width,
+                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              break;
+            }
+          }
+          reply = TRUE;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_WDTR;
+          p->needwdtr &= ~target_mask;
+          p->dtr_pending |= target_mask;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        aic7xxx_set_width(p, target, channel, lun, bus_width,
+                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        
+        /*
+         * By virtue of the SCSI spec, a WDTR message negates any existing
+         * SDTR negotiations.  So, even if needsdtr isn't marked for this
+         * device, we still have to do a new SDTR message if the device
+         * supports SDTR at all.  Therefore, we check needsdtr_copy instead
+         * of needstr.
+         */
+        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+        p->needsdtr |= (p->needsdtr_copy & target_mask);
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_PPR:
+      {
+        unsigned char bus_width, trans_options, new_trans_options;
+        unsigned int period, offset;
+        unsigned char maxsync, saved_offset;
+        struct aic7xxx_syncrate *syncrate;
+        
+        if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
+        {
+          break;
+        }
+
+        period = p->msg_buf[3];
+        offset = saved_offset = p->msg_buf[5];
+        bus_width = p->msg_buf[6];
+        trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        {
+          printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
+                 trans_options);
+        }
+
+        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+        {
+          if(p->features & AHC_ULTRA3)
+          {
+            maxsync = AHC_SYNCRATE_ULTRA3;
+          }
+          else
+          {
+            maxsync = AHC_SYNCRATE_ULTRA2;
+          }
+        }
+        else
+        {
+          maxsync = AHC_SYNCRATE_ULTRA;
+        }
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
+        {
+          reply = TRUE;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+	  p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+          {
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            if(p->transinfo[tindex].user_offset)
+            {
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( p->transinfo[tindex].user_width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
+            }
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
+            p->transinfo[tindex].goal_options =
+              p->transinfo[tindex].user_options;
+          }
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive PPR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          if ( !p->transinfo[tindex].goal_offset )
+            period = 255;
+          if ( p->transinfo[tindex].goal_period > period )
+            period = p->transinfo[tindex].goal_period;
+          if ( p->transinfo[tindex].goal_options == 0 )
+            new_trans_options = 0;
+          switch(bus_width)
+          {
+            default:
+            {
+              if ( (p->features & AHC_WIDE) &&
+                   (p->transinfo[tindex].goal_width ==
+                    MSG_EXT_WDTR_BUS_16_BIT) )
+              {
+                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              p->needwdtr_copy &= ~target_mask;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic7xxx_set_width(p, target, channel, lun, bus_width,
+                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              break;
+            }
+          }
+          if ( (p->transinfo[tindex].goal_period > 9) ||
+               (p->transinfo[tindex].goal_options == 0) )
+          {
+            scb->flags &= ~SCB_MSGOUT_BITS;
+            reject = TRUE;
+            reply = FALSE;
+            p->needppr &= ~(1 << tindex);
+            p->needppr_copy &= ~(1 << tindex);
+            if ( p->transinfo[tindex].goal_offset )
+            {
+              p->needsdtr |= (1 << tindex);
+              p->needsdtr_copy |= (1 << tindex);
+            }
+            if ( p->transinfo[tindex].goal_width )
+            {
+              p->needwdtr |= (1 << tindex);
+              p->needwdtr_copy |= (1 << tindex);
+            }
+          }
+        }
+        else
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                    (aic7xxx_verbose > 0xffff)) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              /*
+               * According to the spec, if we aren't wide, we also can't be
+               * Dual Edge so clear the options byte
+               */
+              new_trans_options = 0;
+              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              break;
+            }
+          }
+        }
+
+        if ( !reject )
+        {
+          aic7xxx_set_width(p, target, channel, lun, bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+                               offset, new_trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
+
+        p->dtr_pending &= ~target_mask;
+        p->needppr &= ~target_mask;
+        if(reply)
+        {
+          p->dtr_pending |= target_mask;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        done = TRUE;
+        break;
+      }
+      default:
+      {
+        reject = TRUE;
+        break;
+      }
+    } /* end of switch(p->msg_type) */
+  } /* end of if (!reject && (p->msg_len > 2)) */
+
+  if (!reply && reject)
+  {
+    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+    done = TRUE;
+  }
+  return(done);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_reqinit
+ *
+ * Description:
+ *   Interrupt handler for REQINIT interrupts (used to transfer messages to
+ *    and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char lastbyte;
+  unsigned char phasemis;
+  int done = FALSE;
+
+  switch(p->msg_type)
+  {
+    case MSG_TYPE_INITIATOR_MSGOUT:
+      {
+        if (p->msg_len == 0)
+          panic("aic7xxx: REQINIT with no active message!\n");
+
+        lastbyte = (p->msg_index == (p->msg_len - 1));
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
+
+        if (lastbyte || phasemis)
+        {
+          /* Time to end the message */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+
+          if (phasemis == 0)
+          {
+            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+            aic_outb(p, 0, RETURN_1);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+            if (aic7xxx_verbose > 0xffff)
+              printk(INFO_LEAD "Completed sending of REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+#endif
+          }
+          else
+          {
+            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+            if (aic7xxx_verbose > 0xffff)
+              printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+#endif
+          }
+          unpause_sequencer(p, TRUE);
+        }
+        else
+        {
+          /*
+           * Present the byte on the bus (clearing REQINIT) but don't
+           * unpause the sequencer.
+           */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
+        }
+        break;
+      }
+    case MSG_TYPE_INITIATOR_MSGIN:
+      {
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+        if (phasemis == 0)
+        {
+          p->msg_len++;
+          /* Pull the byte in without acking it */
+          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+          done = aic7xxx_parse_msg(p, scb);
+          /* Ack the byte */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_inb(p, SCSIDATL);
+          p->msg_index++;
+        }
+        if (phasemis || done)
+        {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+          if (aic7xxx_verbose > 0xffff)
+          {
+            if (phasemis)
+              printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+            else
+              printk(INFO_LEAD "Completed receipt of REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+          }
+#endif
+          /* Time to end our message session */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+          unpause_sequencer(p, TRUE);
+        }
+        break;
+      }
+    default:
+      {
+        panic("aic7xxx: Unknown REQINIT message type.\n");
+        break;
+      }
+  } /* End of switch(p->msg_type) */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_scsiint
+ *
+ * Description:
+ *   Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  unsigned char scb_index;
+  unsigned char status;
+  struct aic7xxx_scb *scb;
+
+  scb_index = aic_inb(p, SCB_TAG);
+  status = aic_inb(p, SSTAT1);
+
+  if (scb_index < p->scb_data->numscbs)
+  {
+    scb = p->scb_data->scb_array[scb_index];
+    if ((scb->flags & SCB_ACTIVE) == 0)
+    {
+      scb = NULL;
+    }
+  }
+  else
+  {
+    scb = NULL;
+  }
+
+
+  if ((status & SCSIRSTI) != 0)
+  {
+    int channel;
+
+    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    else
+      channel = 0;
+
+    if (aic7xxx_verbose & VERBOSE_RESET)
+      printk(WARN_LEAD "Someone else reset the channel!!\n",
+           p->host_no, channel, -1, -1);
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
+    /*
+     * Go through and abort all commands for the channel, but do not
+     * reset the channel again.
+     */
+    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    aic7xxx_run_done_queue(p, TRUE);
+    scb = NULL;
+  }
+  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
+  {
+    /*
+     * First look at what phase we were last in.  If it's message-out,
+     * chances are pretty good that the bus free was in response to
+     * one of our abort requests.
+     */
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+    unsigned char target = (saved_tcl >> 4) & 0x0F;
+    int channel;
+    int printerror = TRUE;
+
+    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    else
+      channel = 0;
+
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
+             SCSISEQ);
+    if (lastphase == P_MESGOUT)
+    {
+      unsigned char message;
+
+      message = aic_inb(p, SINDEX);
+
+      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
+      {
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+            CTL_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+        aic7xxx_run_done_queue(p, TRUE);
+        scb = NULL;
+        printerror = 0;
+      }
+      else if (message == MSG_BUS_DEV_RESET)
+      {
+        aic7xxx_handle_device_reset(p, target, channel);
+        scb = NULL;
+        printerror = 0;
+      }
+    }
+    if ( (scb != NULL) &&
+         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+    {
+      /*
+       * This might be a SCSI-3 device that is dropping the bus due to
+       * errors and signalling that we should reduce the transfer speed.
+       * All we have to do is complete this command (since it's a negotiation
+       * command already) and the checksum routine should flag an error and
+       * reduce the speed setting and renegotiate.  We call the reset routing
+       * just to clean out the hardware from this scb.
+       */
+      printerror = 0;
+      aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+      aic7xxx_run_done_queue(p, TRUE);
+      scb = NULL;
+    }
+    if (printerror != 0)
+    {
+      if (scb != NULL)
+      {
+        unsigned char tag;
+
+        if ((scb->hscb->control & TAG_ENB) != 0)
+        {
+          tag = scb->hscb->tag;
+        }
+        else
+        {
+          tag = SCB_LIST_NULL;
+        }
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
+        aic7xxx_run_done_queue(p, TRUE);
+      }
+      else
+      {
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+        aic7xxx_run_done_queue(p, TRUE);
+      }
+      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+      scb = NULL;
+    }
+    aic_outb(p, MSG_NOOP, MSG_OUT);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRBUSFREE, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
+  }
+  else if ((status & SELTO) != 0)
+  {
+    unsigned char scbptr;
+    unsigned char nextscb;
+    Scsi_Cmnd *cmd;
+
+    scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr > p->scb_data->maxhscbs)
+    {
+      /*
+       * I'm still trying to track down exactly how this happens, but until
+       * I find it, this code will make sure we aren't passing bogus values
+       * into the SCBPTR register, even if that register will just wrap
+       * things around, we still don't like having out of range variables.
+       *
+       * NOTE: Don't check the aic7xxx_verbose variable, I want this message
+       * to always be displayed.
+       */
+      printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n",
+             p->host_no, -1, -1, -1, scbptr);
+      if (p->scb_data->maxhscbs > 4)
+        scbptr &= (p->scb_data->maxhscbs - 1);
+      else
+        scbptr &= 0x03;
+    }
+    aic_outb(p, scbptr, SCBPTR);
+    scb_index = aic_inb(p, SCB_TAG);
+
+    scb = NULL;
+    if (scb_index < p->scb_data->numscbs)
+    {
+      scb = p->scb_data->scb_array[scb_index];
+      if ((scb->flags & SCB_ACTIVE) == 0)
+      {
+        scb = NULL;
+      }
+    }
+    if (scb == NULL)
+    {
+      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, -1, -1, -1, scb_index);
+      printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
+             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+      if (aic7xxx_panic_on_abort)
+        aic7xxx_panic_abort(p, NULL);
+    }
+    else
+    {
+      cmd = scb->cmd;
+      cmd->result = (DID_TIME_OUT << 16);
+
+      /*
+       * Clear out this hardware SCB
+       */
+      aic_outb(p, 0, SCB_CONTROL);
+
+      /*
+       * Clear out a few values in the card that are in an undetermined
+       * state.
+       */
+      aic_outb(p, MSG_NOOP, MSG_OUT);
+
+      /*
+       * Shift the waiting for selection queue forward
+       */
+      nextscb = aic_inb(p, SCB_NEXT);
+      aic_outb(p, nextscb, WAITING_SCBH);
+
+      /*
+       * Put this SCB back on the free list.
+       */
+      aic7xxx_add_curscb_to_free_list(p);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
+#endif
+      if (scb->flags & SCB_QUEUED_ABORT)
+      {
+        /*
+         * We know that this particular SCB had to be the queued abort since
+         * the disconnected SCB would have gotten a reconnect instead.
+         * What we need to do then is to let the command timeout again so
+         * we get a reset since this abort just failed.
+         */
+        cmd->result = 0;
+        scb = NULL;
+      }
+      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+      {
+        /*
+         * Turn off the needsdtr, needwdtr, and needppr bits since this device
+         * doesn't seem to exist.
+         */
+        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+      }
+    }
+    /*
+     * Keep the sequencer from trying to restart any selections
+     */
+    aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+    /*
+     * Make sure the data bits on the bus are released
+     * Don't do this on 7770 chipsets, it makes them give us
+     * a BRKADDRINT and kills the card.
+     */
+    if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+      aic_outb(p, 0, SCSIBUSL);
+
+    /*
+     * Delay for the selection timeout delay period then stop the selection
+     */
+    udelay(301);
+    aic_outb(p, CLRSELINGO, CLRSINT0);
+    /*
+     * Clear out all the interrupt status bits
+     */
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    /*
+     * Restarting the sequencer will stop the selection and make sure devices
+     * are allowed to reselect in.
+     */
+    restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
+  }
+  else if (scb == NULL)
+  {
+    printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
+           "during scsiint 0x%x scb(%d)\n"
+           "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
+           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+    /*
+     * Turn off the interrupt and set status to zero, so that it
+     * falls through the rest of the SCSIINT code.
+     */
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  else if (status & SCSIPERR)
+  {
+    /*
+     * Determine the bus phase and queue an appropriate message.
+     */
+    char  *phase;
+    Scsi_Cmnd *cmd;
+    unsigned char mesg_out = MSG_NOOP;
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char sstat2 = aic_inb(p, SSTAT2);
+    unsigned char tindex = TARGET_INDEX(scb->cmd);
+
+    cmd = scb->cmd;
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        phase = "Data-Out";
+        break;
+      case P_DATAIN:
+        phase = "Data-In";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_COMMAND:
+        phase = "Command";
+        break;
+      case P_MESGOUT:
+        phase = "Message-Out";
+        break;
+      case P_STATUS:
+        phase = "Status";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_MESGIN:
+        phase = "Message-In";
+        mesg_out = MSG_PARITY_ERROR;
+        break;
+      default:
+        phase = "unknown";
+        break;
+    }
+
+    /*
+     * A parity error has occurred during a data
+     * transfer phase. Flag it and continue.
+     */
+    if( (p->features & AHC_ULTRA3) && 
+        (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) &&
+        (lastphase == P_DATAIN) )
+    {
+      printk(WARN_LEAD "CRC error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+      if(sstat2 & CRCVALERR)
+      {
+        printk(WARN_LEAD "  CRC error in intermediate CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCENDERR)
+      {
+        printk(WARN_LEAD "  CRC error in ending CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCREQERR)
+      {
+        printk(WARN_LEAD "  Target incorrectly requested a CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & DUAL_EDGE_ERROR)
+      {
+        printk(WARN_LEAD "  Dual Edge transmission error.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+    }
+    else if( (lastphase == P_MESGOUT) &&
+             (cmd == p->dev_dtr_cmnd[tindex]) &&
+             (scb->flags & SCB_MSGOUT_PPR) )
+    {
+      /*
+       * As per the draft specs, any device capable of supporting any of
+       * the option values other than 0 are not allowed to reject the
+       * PPR message.  Instead, they must negotiate out what they do
+       * support instead of rejecting our offering or else they cause
+       * a parity error during msg_out phase to signal that they don't
+       * like our settings.
+       */
+      p->needppr &= ~(1 << tindex);
+      p->needppr_copy &= ~(1 << tindex);
+      aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
+                        MSG_EXT_WDTR_BUS_8_BIT,
+                        (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+      aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
+                           0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+      p->transinfo[tindex].goal_options = 0;
+      p->dtr_pending &= ~(1 << tindex);
+      scb->flags &= ~SCB_MSGOUT_BITS;
+      if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+      {
+        printk(INFO_LEAD "parity error during PPR message, reverting "
+               "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
+      }
+      if ( p->transinfo[tindex].goal_width )
+      {
+        p->needwdtr |= (1 << tindex);
+        p->needwdtr_copy |= (1 << tindex);
+      }
+      if ( p->transinfo[tindex].goal_offset )
+      {
+        if( p->transinfo[tindex].goal_period <= 9 )
+        {
+          p->transinfo[tindex].goal_period = 10;
+        }
+        p->needsdtr |= (1 << tindex);
+        p->needsdtr_copy |= (1 << tindex);
+      }
+      scb = NULL;
+    }
+    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+    {
+      struct aic7xxx_syncrate *syncrate;
+      unsigned int period = p->transinfo[tindex].cur_period;
+      unsigned char options = p->transinfo[tindex].cur_options;
+      /*
+       * oops, we had a failure, lower the transfer rate and try again.  It's
+       * worth noting here that it might be wise to also check for typical
+       * wide setting on narrow cable type problems and try disabling wide
+       * instead of slowing down if those exist.  That's hard to do with simple
+       * checksums though.
+       */
+      printk(WARN_LEAD "Parity error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+      {
+        syncrate++;
+        if( (syncrate->rate[0] != NULL) &&
+            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+        {
+          p->transinfo[tindex].goal_period = syncrate->period;
+          if( p->transinfo[tindex].goal_period > 9 )
+          {
+            p->transinfo[tindex].goal_options = 0;
+            p->needppr &= ~(1<<tindex);
+            p->needsdtr |= (1<<tindex);
+            p->needppr_copy &= ~(1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
+            if (p->transinfo[tindex].goal_width)
+            {
+              p->needwdtr |= (1<<tindex);
+              p->needwdtr_copy |= (1<<tindex);
+            }
+          }
+        }
+        else if (p->transinfo[tindex].goal_width)
+        {
+          p->transinfo[tindex].goal_width = 0;
+          p->needwdtr &= ~(1<<tindex);
+          p->needwdtr_copy &= ~(1<<tindex);
+          p->transinfo[tindex].goal_offset =
+            p->transinfo[tindex].user_offset;
+          p->transinfo[tindex].goal_period =
+            p->transinfo[tindex].user_period;
+          p->transinfo[tindex].goal_options =
+            p->transinfo[tindex].user_options;
+          if( p->transinfo[tindex].goal_period <= 9 )
+          {
+            p->needppr |= (1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needppr_copy |= (1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+          }
+          else
+          {
+            p->needppr &= ~(1<<tindex);
+            p->needsdtr |= (1<<tindex);
+            p->needppr_copy &= ~(1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
+          }
+        }
+        else
+        {
+          p->transinfo[tindex].goal_offset = 0;
+          p->transinfo[tindex].goal_period = 255;
+          p->transinfo[tindex].goal_options = 0;
+          p->transinfo[tindex].goal_width = 0;
+          p->needppr &= ~(1<<tindex);
+          p->needsdtr &= ~(1<<tindex);
+          p->needwdtr &= ~(1<<tindex);
+          p->needppr_copy &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->needwdtr_copy &= ~(1<<tindex);
+        }
+      }
+      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
+    }
+    else
+    {
+      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
+    }
+
+    /*
+     * We've set the hardware to assert ATN if we get a parity
+     * error on "in" phases, so all we need to do is stuff the
+     * message buffer with the appropriate message.  "In" phases
+     * have set mesg_out to something other than MSG_NOP.
+     */
+    if (mesg_out != MSG_NOOP)
+    {
+      aic_outb(p, mesg_out, MSG_OUT);
+      aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+      scb = NULL;
+    }
+    aic_outb(p, CLRSCSIPERR, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    unpause_sequencer(p, /* unpause_always */ TRUE);
+  }
+  else if ( (status & REQINIT) &&
+            (p->flags & AHC_HANDLING_REQINITS) )
+  {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (aic7xxx_verbose > 0xffff)
+      printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no,
+             CTL_OF_SCB(scb), aic_inb(p, SSTAT1));
+#endif
+    aic7xxx_handle_reqinit(p, scb);
+    return;
+  }
+  else
+  {
+    /*
+     * We don't know what's going on. Turn off the
+     * interrupt source and try to continue.
+     */
+    if (aic7xxx_verbose & VERBOSE_SCSIINT)
+      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+        p->host_no, -1, -1, -1, status);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  if (scb != NULL)
+  {
+    aic7xxx_done(p, scb);
+  }
+}
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+static void
+aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
+{
+  unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp;
+  int i, bogus, lost;
+  static unsigned char scb_status[AIC7XXX_MAXSCB];
+
+#define SCB_NO_LIST 0
+#define SCB_FREE_LIST 1
+#define SCB_WAITING_LIST 2
+#define SCB_DISCONNECTED_LIST 4
+#define SCB_CURRENTLY_ACTIVE 8
+
+  /*
+   * Note, these checks will fail on a regular basis once the machine moves
+   * beyond the bus scan phase.  The problem is race conditions concerning
+   * the scbs and where they are linked in.  When you have 30 or so commands
+   * outstanding on the bus, and run this twice with every interrupt, the
+   * chances get pretty good that you'll catch the sequencer with an SCB
+   * only partially linked in.  Therefore, once we pass the scan phase
+   * of the bus, we really should disable this function.
+   */
+  bogus = FALSE;
+  memset(&scb_status[0], 0, sizeof(scb_status));
+  pause_sequencer(p);
+  saved_scbptr = aic_inb(p, SCBPTR);
+  if (saved_scbptr >= p->scb_data->maxhscbs)
+  {
+    printk("Bogus SCBPTR %d\n", saved_scbptr);
+    bogus = TRUE;
+  }
+  scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE;
+  free_scbh = aic_inb(p, FREE_SCBH);
+  if ( (free_scbh != SCB_LIST_NULL) &&
+       (free_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus FREE_SCBH %d\n", free_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = free_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_FREE_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_FREE_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
+
+  dis_scbh = aic_inb(p, DISCONNECTED_SCBH);
+  if ( (dis_scbh != SCB_LIST_NULL) &&
+       (dis_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = dis_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_DISCONNECTED_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_DISCONNECTED_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
+  
+  wait_scbh = aic_inb(p, WAITING_SCBH);
+  if ( (wait_scbh != SCB_LIST_NULL) &&
+       (wait_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus WAITING_SCBH %d\n", wait_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = wait_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_WAITING_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_WAITING_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
+
+  lost=0;
+  for(i=0; i < p->scb_data->maxhscbs; i++)
+  {
+    aic_outb(p, i, SCBPTR);
+    temp = aic_inb(p, SCB_NEXT);
+    if ( ((temp != SCB_LIST_NULL) &&
+          (temp >= p->scb_data->maxhscbs)) )
+    {
+      printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp);
+      bogus = TRUE;
+    }
+    if ( temp == i )
+    {
+      printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
+      bogus = TRUE;
+    }
+    if (scb_status[i] == 0)
+      lost++;
+    if (lost > 1)
+    {
+      printk("Too many lost scbs.\n");
+      bogus=TRUE;
+    }
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  unpause_sequencer(p, FALSE);
+  if (bogus)
+  {
+    printk("Bogus parameters found in card SCB array structures.\n");
+    printk("%s\n", buffer);
+    aic7xxx_panic_abort(p, NULL);
+  }
+  return;
+}
+#endif
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_command_completion_intr
+ *
+ * Description:
+ *   SCSI command completion interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb *scb = NULL;
+  Scsi_Cmnd *cmd;
+  unsigned char scb_index, tindex;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
+    printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
+#endif
+    
+  /*
+   * Read the INTSTAT location after clearing the CMDINT bit.  This forces
+   * any posted PCI writes to flush to memory.  Gerard Roudier suggested
+   * this fix to the possible race of clearing the CMDINT bit but not
+   * having all command bytes flushed onto the qoutfifo.
+   */
+  aic_outb(p, CLRCMDINT, CLRINT);
+  aic_inb(p, INTSTAT);
+  /*
+   * The sequencer will continue running when it
+   * issues this interrupt. There may be >1 commands
+   * finished, so loop until we've processed them all.
+   */
+
+  while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
+  {
+    scb_index = p->qoutfifo[p->qoutfifonext];
+    p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+    if ( scb_index >= p->scb_data->numscbs )
+    {
+      printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+        -1, -1, -1, scb_index);
+      continue;
+    }
+    scb = p->scb_data->scb_array[scb_index];
+    if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+    {
+      printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+        "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+        (unsigned long) scb->cmd);
+      continue;
+    }
+    tindex = TARGET_INDEX(scb->cmd);
+    if (scb->flags & SCB_QUEUED_ABORT)
+    {
+      pause_sequencer(p);
+      if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
+           (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
+      {
+        unpause_sequencer(p, FALSE);
+        continue;
+      }
+      aic7xxx_reset_device(p, scb->cmd->target, scb->cmd->channel,
+        scb->cmd->lun, scb->hscb->tag);
+      scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
+        SCB_QUEUED_ABORT);
+      unpause_sequencer(p, FALSE);
+    }
+    else if (scb->flags & SCB_ABORT)
+    {
+      /*
+       * We started to abort this, but it completed on us, let it
+       * through as successful
+       */
+      scb->flags &= ~(SCB_ABORT|SCB_RESET);
+    }
+    else if (scb->flags & SCB_SENSE)
+    {
+      char *buffer = &scb->cmd->sense_buffer[0];
+      if (scb->cmd == p->dev_dtr_cmnd[tindex])
+      {
+        struct aic7xxx_scb *old_scb;
+        /*
+         * We have valid sense data, send it back immediately.
+         */
+        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
+        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
+        old_scb->hscb->target_status = scb->hscb->target_status;
+        old_scb->cmd->result = scb->hscb->target_status;
+        old_scb->cmd->result |= (DID_ERROR << 16);
+        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
+        scbq_remove(&p->waiting_scbs, old_scb);
+        scbq_remove(&p->delayed_scbs[tindex], old_scb);
+        scb->cmd->next = NULL;
+	aic7xxx_done(p, scb);
+        aic7xxx_done(p, old_scb);
+	continue;
+      } 
+      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+      {
+        /*
+         * SCSI errors, run domain validation and re-run negotiation
+         */
+        p->needdv |= (1<<tindex);
+        /*
+         * Signal that we need to re-negotiate things, this also gets us our
+         * INQUIRY command to re-checksum off of.
+         */
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+    }
+    switch (status_byte(scb->hscb->target_status))
+    {
+      case QUEUE_FULL:
+      case BUSY:
+        scb->hscb->target_status = 0;
+        scb->cmd->result = 0;
+        aic7xxx_error(scb->cmd) = DID_OK;
+        break;
+      default:
+        cmd = scb->cmd;
+        if (scb->hscb->residual_SG_segment_count != 0)
+        {
+          aic7xxx_calculate_residual(p, scb);
+        }
+        cmd->result |= (aic7xxx_error(cmd) << 16);
+        aic7xxx_done(p, scb);
+        break;
+    }      
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   SCSI controller interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct aic7xxx_host *p;
+  unsigned char intstat;
+
+  p = (struct aic7xxx_host *)dev_id;
+
+  /*
+   * Just a few sanity checks.  Make sure that we have an int pending.
+   * Also, if PCI, then we are going to check for a PCI bus error status
+   * should we get too many spurious interrupts.
+   */
+  if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND))
+  {
+#ifdef CONFIG_PCI
+    if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) &&
+        !(p->flags & AHC_HANDLING_REQINITS) )
+    {
+      if ( aic_inb(p, ERROR) & PCIERRSTAT )
+      {
+        aic7xxx_pci_intr(p);
+      }
+      p->spurious_int = 0;
+    }
+    else if ( !(p->flags & AHC_HANDLING_REQINITS) )
+    {
+      p->spurious_int++;
+    }
+#endif
+    return;
+  }
+
+  p->spurious_int = 0;
+
+  /*
+   * Keep track of interrupts for /proc/scsi
+   */
+  p->isr_count++;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
+       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
+    aic7xxx_check_scbs(p, "Bogus settings at start of interrupt.");
+#endif
+
+  /*
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
+   */
+  if (intstat & CMDCMPLT)
+  {
+    aic7xxx_handle_command_completion_intr(p);
+  }
+
+  if (intstat & BRKADRINT)
+  {
+    int i;
+    unsigned char errno = aic_inb(p, ERROR);
+
+    printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
+    for (i = 0; i < NUMBER(hard_error); i++)
+    {
+      if (errno & hard_error[i].errno)
+      {
+        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
+      }
+    }
+    printk(KERN_ERR "(scsi%d)   SEQADDR=0x%x\n", p->host_no,
+      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
+#ifdef CONFIG_PCI
+    if (errno & PCIERRSTAT)
+      aic7xxx_pci_intr(p);
+#endif
+    if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
+    {
+      sti();
+      panic("aic7xxx: unrecoverable BRKADRINT.\n");
+    }
+    if (errno & ILLHADDR)
+    {
+      printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first "
+             "pausing controller!\n", p->host_no);
+    }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (errno & DPARERR)
+    {
+      if (aic_inb(p, DMAPARAMS) & DIRECTION)
+        printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no);
+      else
+        printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no);
+    }
+#endif
+    aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT);
+    unpause_sequencer(p, FALSE);
+  }
+
+  if (intstat & SEQINT)
+  {
+    /*
+     * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
+     */
+    if(p->features & AHC_ULTRA2)
+    {
+      aic_inb(p, CCSCBCTL);
+    }
+    aic7xxx_handle_seqint(p, intstat);
+  }
+
+  if (intstat & SCSIINT)
+  {
+    aic7xxx_handle_scsiint(p, intstat);
+  }
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
+       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
+    aic7xxx_check_scbs(p, "Bogus settings at end of interrupt.");
+#endif
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   do_aic7xxx_isr
+ *
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static void
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long cpu_flags;
+  struct aic7xxx_host *p;
+  
+  p = (struct aic7xxx_host *)dev_id;
+  if(!p)
+    return;
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  if(test_and_set_bit(AHC_IN_ISR_BIT, (void *)&p->flags))
+  {
+    spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+    return;
+  }
+  do
+  {
+    aic7xxx_isr(irq, dev_id, regs);
+  } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
+  aic7xxx_done_cmds_complete(p);
+  aic7xxx_run_waiting_queues(p);
+  clear_bit(AHC_IN_ISR_BIT, (void *)&p->flags);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_device_queue_depth
+ *
+ * Description:
+ *   Determines the queue depth for a given device.  There are two ways
+ *   a queue depth can be obtained for a tagged queueing device.  One
+ *   way is the default queue depth which is determined by whether
+ *   AIC7XXX_CMDS_PER_DEVICE is defined.  If it is defined, then it is used
+ *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
+ *   default queue depth (dependent on the number of hardware SCBs).
+ *   The other way we determine queue depth is through the use of the
+ *   aic7xxx_tag_info array which is enabled by defining
+ *   AIC7XXX_TAGGED_QUEUEING_BY_DEVICE.  This array can be initialized
+ *   with queue depths for individual devices.  It also allows tagged
+ *   queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static int
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+  int default_depth = 3;
+  unsigned char tindex;
+  unsigned short target_mask;
+
+  tindex = device->id | (device->channel << 3);
+  target_mask = (1 << tindex);
+
+  if (p->dev_max_queue_depth[tindex] > 1)
+  {
+    /*
+     * We've already scanned this device, leave it alone
+     */
+    return(p->dev_max_queue_depth[tindex]);
+  }
+
+  device->queue_depth = default_depth;
+  p->dev_temp_queue_depth[tindex] = 1;
+  p->dev_max_queue_depth[tindex] = 1;
+  p->tagenable &= ~target_mask;
+
+  if (device->tagged_supported)
+  {
+    int tag_enabled = TRUE;
+
+    default_depth = AIC7XXX_CMDS_PER_DEVICE;
+ 
+    if (!(p->discenable & target_mask))
+    {
+      if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        printk(INFO_LEAD "Disconnection disabled, unable to "
+             "enable tagged queueing.\n",
+             p->host_no, device->channel, device->id, device->lun);
+    }
+    else
+    {
+      if (p->instance >= NUMBER(aic7xxx_tag_info))
+      {
+        static int print_warning = TRUE;
+        if(print_warning)
+        {
+          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+                           " installed controllers.\n");
+          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+                           " the aic7xxx.c source file.\n");
+          print_warning = FALSE;
+        }
+        device->queue_depth = default_depth;
+      }
+      else
+      {
+
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
+        {
+          tag_enabled = FALSE;
+          device->queue_depth = 3;  /* Tagged queueing is disabled. */
+        }
+        else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
+        {
+          device->queue_depth = default_depth;
+        }
+        else
+        {
+          device->queue_depth =
+            aic7xxx_tag_info[p->instance].tag_commands[tindex];
+        }
+      }
+      if ((device->tagged_queue == 0) && tag_enabled)
+      {
+        if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        {
+              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
+                p->host_no, device->channel, device->id,
+                device->lun, device->queue_depth);
+        }
+        p->dev_max_queue_depth[tindex] = device->queue_depth;
+        p->dev_temp_queue_depth[tindex] = device->queue_depth;
+        p->tagenable |= target_mask;
+        p->orderedtag |= target_mask;
+        device->tagged_queue = 1;
+        device->current_tag = SCB_LIST_NULL;
+      }
+    }
+  }
+  return(p->dev_max_queue_depth[tindex]);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_select_queue_depth
+ *
+ * Description:
+ *   Sets the queue depth for each SCSI device hanging off the input
+ *   host adapter.  We use a queue depth of 2 for devices that do not
+ *   support tagged queueing.  If AIC7XXX_CMDS_PER_LUN is defined, we
+ *   use that for tagged queueing devices; otherwise we use our own
+ *   algorithm for determining the queue depth based on the maximum
+ *   SCBs for the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host *host,
+    Scsi_Device *scsi_devs)
+{
+  Scsi_Device *device;
+  struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  int scbnum;
+
+  scbnum = 0;
+  for (device = scsi_devs; device != NULL; device = device->next)
+  {
+    if (device->host == host)
+    {
+      scbnum += aic7xxx_device_queue_depth(p, device);
+    }
+  }
+  while (scbnum > p->scb_data->numscbs)
+  {
+    /*
+     * Pre-allocate the needed SCBs to get around the possibility of having
+     * to allocate some when memory is more or less exhausted and we need
+     * the SCB in order to perform a swap operation (possible deadlock)
+     */
+    if ( aic7xxx_allocate_scb(p) == 0 )
+      return;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_probe
+ *
+ * Description:
+ *   Probing for EISA boards: it looks like the first two bytes
+ *   are a manufacturer code - three characters, five bits each:
+ *
+ *               BYTE 0   BYTE 1   BYTE 2   BYTE 3
+ *              ?1111122 22233333 PPPPPPPP RRRRRRRR
+ *
+ *   The characters are baselined off ASCII '@', so add that value
+ *   to each to get the real ASCII code for it. The next two bytes
+ *   appear to be a product and revision number, probably vendor-
+ *   specific. This is what is being searched for at each port,
+ *   and what should probably correspond to the ID= field in the
+ *   ECU's .cfg file for the card - if your card is not detected,
+ *   make sure your signature is listed in the array.
+ *
+ *   The fourth byte's lowest bit seems to be an enabled/disabled
+ *   flag (rest of the bits are reserved?).
+ *
+ * NOTE:  This function is only needed on Intel and Alpha platforms,
+ *   the other platforms we support don't have EISA/VLB busses.  So,
+ *   we #ifdef this entire function to avoid compiler warnings about
+ *   an unused function.
+ *-F*************************************************************************/
+#if defined(__i386__) || defined(__alpha__)
+static int
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
+{
+  int i;
+  unsigned char buf[4];
+
+  static struct {
+    int n;
+    unsigned char signature[sizeof(buf)];
+    ahc_chip type;
+    int bios_disabled;
+  } AIC7xxx[] = {
+    { 4, { 0x04, 0x90, 0x77, 0x70 },
+      AHC_AIC7770|AHC_EISA, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x71 },
+      AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x56 },
+      AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 },
+      AHC_AIC7770|AHC_VL, TRUE }   /* 284x BIOS disabled */
+  };
+
+  /*
+   * The VL-bus cards need to be primed by
+   * writing before a signature check.
+   */
+  for (i = 0; i < sizeof(buf); i++)
+  {
+    outb(0x80 + i, base);
+    buf[i] = inb(base + i);
+  }
+
+  for (i = 0; i < NUMBER(AIC7xxx); i++)
+  {
+    /*
+     * Signature match on enabled card?
+     */
+    if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n))
+    {
+      if (inb(base + 4) & 1)
+      {
+        if (AIC7xxx[i].bios_disabled)
+        {
+          *flags |= AHC_USEDEFAULTS;
+        }
+        else
+        {
+          *flags |= AHC_BIOS_ENABLED;
+        }
+        return (i);
+      }
+
+      printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+             "disabled at slot %d, ignored.\n", slot);
+    }
+  }
+
+  return (-1);
+}
+#endif /* (__i386__) || (__alpha__) */
+
+
+/*+F*************************************************************************
+ * Function:
+ *   read_2840_seeprom
+ *
+ * Description:
+ *   Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
+ *   not successful.
+ *
+ *   See read_seeprom (for the 2940) for the instruction set of the 93C46
+ *   chip.
+ *
+ *   The 2840 interface to the 93C46 serial EEPROM is through the
+ *   STATUS_2840 and SEECTL_2840 registers.  The CS_2840, CK_2840, and
+ *   DO_2840 bits of the SEECTL_2840 register are connected to the chip
+ *   select, clock, and data out lines respectively of the serial EEPROM.
+ *   The DI_2840 bit of the STATUS_2840 is connected to the data in line
+ *   of the serial EEPROM.  The EEPROM_TF bit of STATUS_2840 register is
+ *   useful in that it gives us an 800 nsec timer.  After a read from the
+ *   SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
+ *   later.
+ *-F*************************************************************************/
+static int
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
+{
+  int i = 0, k = 0;
+  unsigned char temp;
+  unsigned short checksum = 0;
+  unsigned short *seeprom = (unsigned short *) sc;
+  struct seeprom_cmd {
+    unsigned char len;
+    unsigned char bits[3];
+  };
+  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+#define CLOCK_PULSE(p) \
+  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
+  }                                                \
+  (void) aic_inb(p, SEECTL_2840);
+
+  /*
+   * Read the first 32 registers of the seeprom.  For the 2840,
+   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
+   * but only the first 32 are used by Adaptec BIOS.  The loop
+   * will range from 0 to 31.
+   */
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  {
+    /*
+     * Send chip select for one clock cycle.
+     */
+    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
+    CLOCK_PULSE(p);
+
+    /*
+     * Now we're ready to send the read command followed by the
+     * address of the 16-bit register we want to read.
+     */
+    for (i = 0; i < seeprom_read.len; i++)
+    {
+      temp = CS_2840 | seeprom_read.bits[i];
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+      temp = temp ^ CK_2840;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+    }
+    /*
+     * Send the 6 bit address (MSB first, LSB last).
+     */
+    for (i = 5; i >= 0; i--)
+    {
+      temp = k;
+      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
+      temp = CS_2840 | temp;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+      temp = temp ^ CK_2840;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+    }
+
+    /*
+     * Now read the 16 bit register.  An initial 0 precedes the
+     * register contents which begins with bit 15 (MSB) and ends
+     * with bit 0 (LSB).  The initial 0 will be shifted off the
+     * top of our word as we let the loop run from 0 to 16.
+     */
+    for (i = 0; i <= 16; i++)
+    {
+      temp = CS_2840;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+      temp = temp ^ CK_2840;
+      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+    }
+    /*
+     * The serial EEPROM has a checksum in the last word.  Keep a
+     * running checksum for all words read except for the last
+     * word.  We'll verify the checksum after all words have been
+     * read.
+     */
+    if (k < (sizeof(*sc) / 2) - 1)
+    {
+      checksum = checksum + seeprom[k];
+    }
+
+    /*
+     * Reset the chip select for the next command cycle.
+     */
+    aic_outb(p, 0, SEECTL_2840);
+    CLOCK_PULSE(p);
+    aic_outb(p, CK_2840, SEECTL_2840);
+    CLOCK_PULSE(p);
+    aic_outb(p, 0, SEECTL_2840);
+    CLOCK_PULSE(p);
+  }
+
+#if 0
+  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+  printk("Serial EEPROM:");
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  {
+    if (((k % 8) == 0) && (k != 0))
+    {
+      printk("\n              ");
+    }
+    printk(" 0x%x", seeprom[k]);
+  }
+  printk("\n");
+#endif
+
+  if (checksum != sc->checksum)
+  {
+    printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+    return (0);
+  }
+
+  return (1);
+#undef CLOCK_PULSE
+}
+
+#define CLOCK_PULSE(p)                                               \
+  do {                                                               \
+    int limit = 0;                                                   \
+    do {                                                             \
+      mb();                                                          \
+      pause_sequencer(p);  /* This is just to generate some PCI */   \
+                           /* traffic so the PCI read is flushed */  \
+                           /* it shouldn't be needed, but some */    \
+                           /* chipsets do indeed appear to need */   \
+                           /* something to force PCI reads to get */ \
+                           /* flushed */                             \
+      udelay(1);           /* Do nothing */                          \
+    } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \
+  } while(0)
+
+/*+F*************************************************************************
+ * Function:
+ *   acquire_seeprom
+ *
+ * Description:
+ *   Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+
+  /*
+   * Request access of the memory port.  When access is
+   * granted, SEERDY will go high.  We use a 1 second
+   * timeout which should be near 1 second more than
+   * is needed.  Reason: after the 7870 chip reset, there
+   * should be no contention.
+   */
+  aic_outb(p, SEEMS, SEECTL);
+  CLOCK_PULSE(p);
+  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
+  {
+    aic_outb(p, 0, SEECTL);
+    return (0);
+  }
+  return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   release_seeprom
+ *
+ * Description:
+ *   Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static void
+release_seeprom(struct aic7xxx_host *p)
+{
+  /*
+   * Make sure the SEEPROM is ready before we release it.
+   */
+  CLOCK_PULSE(p);
+  aic_outb(p, 0, SEECTL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   read_seeprom
+ *
+ * Description:
+ *   Reads the serial EEPROM and returns 1 if successful and 0 if
+ *   not successful.
+ *
+ *   The instruction set of the 93C46/56/66 chips is as follows:
+ *
+ *               Start  OP
+ *     Function   Bit  Code  Address    Data     Description
+ *     -------------------------------------------------------------------
+ *     READ        1    10   A5 - A0             Reads data stored in memory,
+ *                                               starting at specified address
+ *     EWEN        1    00   11XXXX              Write enable must precede
+ *                                               all programming modes
+ *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
+ *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
+ *     ERAL        1    00   10XXXX              Erase all registers
+ *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
+ *     EWDS        1    00   00XXXX              Disables all programming
+ *                                               instructions
+ *     *Note: A value of X for address is a don't care condition.
+ *     *Note: The 93C56 and 93C66 have 8 address bits.
+ * 
+ *
+ *   The 93C46 has a four wire interface: clock, chip select, data in, and
+ *   data out.  In order to perform one of the above functions, you need
+ *   to enable the chip select for a clock period (typically a minimum of
+ *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
+ *   respectively.  While the chip select remains high, you can clock in
+ *   the instructions (above) starting with the start bit, followed by the
+ *   OP code, Address, and Data (if needed).  For the READ instruction, the
+ *   requested 16-bit register contents is read from the data out line but
+ *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
+ *   first).  The clock cycling from low to high initiates the next data
+ *   bit to be sent from the chip.
+ *
+ *   The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
+ *   register.  After successful arbitration for the memory port, the
+ *   SEECS bit of the SEECTL register is connected to the chip select.
+ *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
+ *   and data in lines respectively.  The SEERDY bit of SEECTL is useful
+ *   in that it gives us an 800 nsec timer.  After a write to the SEECTL
+ *   register, the SEERDY goes high 800 nsec later.  The one exception
+ *   to this is when we first request access to the memory port.  The
+ *   SEERDY goes high to signify that access has been granted and, for
+ *   this case, has no implied timing.
+ *-F*************************************************************************/
+static int
+read_seeprom(struct aic7xxx_host *p, int offset, 
+    unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
+{
+  int i = 0, k;
+  unsigned char temp;
+  unsigned short checksum = 0;
+  struct seeprom_cmd {
+    unsigned char len;
+    unsigned char bits[3];
+  };
+  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+  /*
+   * Request access of the memory port.
+   */
+  if (acquire_seeprom(p) == 0)
+  {
+    return (0);
+  }
+
+  /*
+   * Read 'len' registers of the seeprom.  For the 7870, the 93C46
+   * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+   * the first 32 are used by Adaptec BIOS.  Some adapters use the
+   * 93C56 SEEPROM which is a 2048-bit device.  The loop will range
+   * from 0 to 'len' - 1.
+   */
+  for (k = 0; k < len; k++)
+  {
+    /*
+     * Send chip select for one clock cycle.
+     */
+    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
+    CLOCK_PULSE(p);
+
+    /*
+     * Now we're ready to send the read command followed by the
+     * address of the 16-bit register we want to read.
+     */
+    for (i = 0; i < seeprom_read.len; i++)
+    {
+      temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+      temp = temp ^ SEECK;
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+    }
+    /*
+     * Send the 6 or 8 bit address (MSB first, LSB last).
+     */
+    for (i = ((int) chip - 1); i >= 0; i--)
+    {
+      temp = k + offset;
+      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
+      temp = SEEMS | SEECS | (temp << 1);
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+      temp = temp ^ SEECK;
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+    }
+
+    /*
+     * Now read the 16 bit register.  An initial 0 precedes the
+     * register contents which begins with bit 15 (MSB) and ends
+     * with bit 0 (LSB).  The initial 0 will be shifted off the
+     * top of our word as we let the loop run from 0 to 16.
+     */
+    for (i = 0; i <= 16; i++)
+    {
+      temp = SEEMS | SEECS;
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+      temp = temp ^ SEECK;
+      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+    }
+
+    /*
+     * The serial EEPROM should have a checksum in the last word.
+     * Keep a running checksum for all words read except for the
+     * last word.  We'll verify the checksum after all words have
+     * been read.
+     */
+    if (k < (len - 1))
+    {
+      checksum = checksum + scarray[k];
+    }
+
+    /*
+     * Reset the chip select for the next command cycle.
+     */
+    aic_outb(p, SEEMS, SEECTL);
+    CLOCK_PULSE(p);
+    aic_outb(p, SEEMS | SEECK, SEECTL);
+    CLOCK_PULSE(p);
+    aic_outb(p, SEEMS, SEECTL);
+    CLOCK_PULSE(p);
+  }
+
+  /*
+   * Release access to the memory port and the serial EEPROM.
+   */
+  release_seeprom(p);
+
+#if 0
+  printk("Computed checksum 0x%x, checksum read 0x%x\n",
+         checksum, scarray[len - 1]);
+  printk("Serial EEPROM:");
+  for (k = 0; k < len; k++)
+  {
+    if (((k % 8) == 0) && (k != 0))
+    {
+      printk("\n              ");
+    }
+    printk(" 0x%x", scarray[k]);
+  }
+  printk("\n");
+#endif
+  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
+  {
+    return (0);
+  }
+
+  return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   read_brdctl
+ *
+ * Description:
+ *   Reads the BRDCTL register.
+ *-F*************************************************************************/
+static unsigned char
+read_brdctl(struct aic7xxx_host *p)
+{
+  unsigned char brdctl, value;
+
+  /*
+   * Make sure the SEEPROM is ready before we access it
+   */
+  CLOCK_PULSE(p);
+  if (p->features & AHC_ULTRA2)
+  {
+    brdctl = BRDRW_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    value = aic_inb(p, BRDCTL);
+    CLOCK_PULSE(p);
+    return(value);
+  }
+  brdctl = BRDRW;
+  if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
+        (p->flags & AHC_CHNLB) )
+  {
+    brdctl |= BRDCS;
+  }
+  aic_outb(p, brdctl, BRDCTL);
+  CLOCK_PULSE(p);
+  value = aic_inb(p, BRDCTL);
+  CLOCK_PULSE(p);
+  aic_outb(p, 0, BRDCTL);
+  CLOCK_PULSE(p);
+  return (value);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   write_brdctl
+ *
+ * Description:
+ *   Writes a value to the BRDCTL register.
+ *-F*************************************************************************/
+static void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
+{
+  unsigned char brdctl;
+
+  /*
+   * Make sure the SEEPROM is ready before we access it
+   */
+  CLOCK_PULSE(p);
+  if (p->features & AHC_ULTRA2)
+  {
+    brdctl = value;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl |= BRDSTB_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl &= ~BRDSTB_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    read_brdctl(p);
+    CLOCK_PULSE(p);
+  }
+  else
+  {
+    brdctl = BRDSTB;
+    if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
+          (p->flags & AHC_CHNLB) )
+    {
+      brdctl |= BRDCS;
+    }
+    brdctl = BRDSTB | BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl |= value;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl &= ~BRDSTB;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl &= ~BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic785x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  CLOCK_PULSE(p);
+  aic_outb(p, 0, BRDCTL);
+  CLOCK_PULSE(p);
+  brdctl = aic_inb(p, BRDCTL);
+  CLOCK_PULSE(p);
+  *int_50 = !(brdctl & BRDDAT5);
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
+}
+
+#undef CLOCK_PULSE
+
+/*+F*************************************************************************
+ * Function:
+ *   aic2940_uwpro_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on the 2940-UWPro cards
+ *
+ * NOTE: This function assumes the SEEPROM will have already been acquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68,
+    int *ext_68, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the internal 68 connector.  BRDDAT6
+   * is don't care, BRDDAT7 is internal 68.  The cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_68 = !(brdctl & BRDDAT6);
+  *eeprom = !(brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This function assumes the SEEPROM will have already been acquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the two internal connectors.  BRDDAT6
+   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_50 = !(brdctl & BRDDAT6);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = !(brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_ultra2_term_detect
+ *
+ * Description:
+ *   Detect the termination settings present on ultra2 class controllers
+ *
+ * NOTE: This function assumes the SEEPROM will have already been acquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low,
+                           int *enableSE_high, int *enableLVD_low,
+                           int *enableLVD_high, int *eprom_present)
+{
+  unsigned char brdctl;
+
+  brdctl = read_brdctl(p);
+
+  *eprom_present  = (brdctl & BRDDAT7);
+  *enableSE_high  = (brdctl & BRDDAT6);
+  *enableSE_low   = (brdctl & BRDDAT5);
+  *enableLVD_high = (brdctl & BRDDAT4);
+  *enableLVD_low  = (brdctl & BRDDAT3);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   configure_termination
+ *
+ * Description:
+ *   Configures the termination settings on PCI adapters that have
+ *   SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p)
+{
+  int internal50_present = 0;
+  int internal68_present = 0;
+  int external_present = 0;
+  int eprom_present = 0;
+  int enableSE_low = 0;
+  int enableSE_high = 0;
+  int enableLVD_low = 0;
+  int enableLVD_high = 0;
+  unsigned char brddat = 0;
+  unsigned char max_target = 0;
+  unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1);
+
+  if (acquire_seeprom(p))
+  {
+    if (p->features & (AHC_WIDE|AHC_TWIN))
+      max_target = 16;
+    else
+      max_target = 8;
+    aic_outb(p, SEEMS | SEECS, SEECTL);
+    sxfrctl1 &= ~STPWEN;
+    /*
+     * The termination/cable detection logic is split into three distinct
+     * groups.  Ultra2 and later controllers, 2940UW-Pro controllers, and
+     * older 7850, 7860, 7870, 7880, and 7895 controllers.  Each has its
+     * own unique way of detecting their cables and writing the results
+     * back to the card.
+     */
+    if (p->features & AHC_ULTRA2)
+    {
+      /*
+       * As long as user hasn't overridden term settings, always check the
+       * cable detection logic
+       */
+      if (aic7xxx_override_term == -1)
+      {
+        aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
+                                   &enableLVD_low, &enableLVD_high,
+                                   &eprom_present);
+      }
+      
+      /*
+       * If the user is overriding settings, then they have been preserved
+       * to here as fake adapter_control entries.  Parse them and allow
+       * them to override the detected settings (if we even did detection).
+       */
+      if (!(p->adapter_control & CFSEAUTOTERM))
+      {
+        enableSE_low = (p->adapter_control & CFSTERM);
+        enableSE_high = (p->adapter_control & CFWSTERM);
+      }
+      if (!(p->adapter_control & CFAUTOTERM))
+      {
+        enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
+      }
+
+      /*
+       * Now take those settings that we have and translate them into the
+       * values that must be written into the registers.
+       *
+       * Flash Enable = BRDDAT7
+       * Secondary High Term Enable = BRDDAT6
+       * Secondary Low Term Enable = BRDDAT5
+       * LVD/Primary High Term Enable = BRDDAT4
+       * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1
+       */
+      if (enableLVD_low != 0)
+      {
+        sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_LVD;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination "
+                 "Enabled\n", p->host_no);
+      }
+          
+      if (enableLVD_high != 0)
+      {
+        brddat |= BRDDAT4;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination "
+                 "Enabled\n", p->host_no);
+      }
+
+      if (enableSE_low != 0)
+      {
+        brddat |= BRDDAT5;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) Secondary Low byte termination "
+                 "Enabled\n", p->host_no);
+      }
+
+      if (enableSE_high != 0)
+      {
+        brddat |= BRDDAT6;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) Secondary High byte termination "
+                 "Enabled\n", p->host_no);
+      }
+    }
+    else if (p->features & AHC_NEW_AUTOTERM)
+    {
+      /*
+       * The 50 pin connector termination is controlled by STPWEN in the
+       * SXFRCTL1 register.  Since the Adaptec docs typically say the
+       * controller is not allowed to be in the middle of a cable and
+       * this is the only connection on that stub of the bus, there is
+       * no need to even check for narrow termination, it's simply
+       * always on.
+       */
+      sxfrctl1 |= STPWEN;
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n",
+               p->host_no);
+
+      if (p->adapter_control & CFAUTOTERM)
+      {
+        aic2940_uwpro_wide_cable_detect(p, &internal68_present,
+                                        &external_present,
+                                        &eprom_present);
+        printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
+               "Ext-68 %s)\n", p->host_no,
+               "Don't Care",
+               internal68_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
+               eprom_present ? "is" : "is not");
+        if (internal68_present && external_present)
+        {
+          brddat = 0;
+          p->flags &= ~AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n",
+                   p->host_no);
+        }
+        else
+        {
+          brddat = BRDDAT6;
+          p->flags |= AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
+                   p->host_no);
+        }
+      }
+      else
+      {
+        /*
+         * The termination of the Wide channel is done more like normal
+         * though, and the setting of this termination is done by writing
+         * either a 0 or 1 to BRDDAT6 of the BRDDAT register
+         */
+        if (p->adapter_control & CFWSTERM)
+        {
+          brddat = BRDDAT6;
+          p->flags |= AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
+                   p->host_no);
+        }
+        else
+        {
+          brddat = 0;
+        }
+      }
+    }
+    else
+    {
+      if (p->adapter_control & CFAUTOTERM)
+      {
+        if (p->flags & AHC_MOTHERBOARD)
+        {
+          printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
+                 p->host_no);
+          printk(KERN_INFO "(scsi%d) Please verify driver detected settings "
+            "are correct.\n", p->host_no);
+          printk(KERN_INFO "(scsi%d) If not, then please properly set the "
+            "device termination\n", p->host_no);
+          printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting "
+            "CTRL-A when prompted\n", p->host_no);
+          printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no);
+        }
+        /* Configure auto termination. */
+
+        if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
+        {
+          aic787x_cable_detect(p, &internal50_present, &internal68_present,
+            &external_present, &eprom_present);
+        }
+        else
+        {
+          aic785x_cable_detect(p, &internal50_present, &external_present,
+            &eprom_present);
+        }
+
+        if (max_target <= 8)
+          internal68_present = 0;
+
+        if (max_target > 8)
+        {
+          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
+                 "Ext-68 %s)\n", p->host_no,
+                 internal50_present ? "YES" : "NO",
+                 internal68_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
+        }
+        else
+        {
+          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n",
+                 p->host_no,
+                 internal50_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
+        }
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
+               eprom_present ? "is" : "is not");
+
+        /*
+         * Now set the termination based on what we found.  BRDDAT6
+         * controls wide termination enable.
+         * Flash Enable = BRDDAT7
+         * SE High Term Enable = BRDDAT6
+         */
+        if (internal50_present && internal68_present && external_present)
+        {
+          printk(KERN_INFO "(scsi%d) Illegal cable configuration!!  Only two\n",
+                 p->host_no);
+          printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
+                 "in use at a time!\n", p->host_no);
+          /*
+           * Force termination (low and high byte) on.  This is safer than
+           * leaving it completely off, especially since this message comes
+           * most often from motherboard controllers that don't even have 3
+           * connectors, but instead are failing the cable detection.
+           */
+          internal50_present = external_present = 0;
+          enableSE_high = enableSE_low = 1;
+        }
+
+        if ((max_target > 8) &&
+            ((external_present == 0) || (internal68_present == 0)) )
+        {
+          brddat |= BRDDAT6;
+          p->flags |= AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                   p->host_no);
+        }
+
+        if ( ((internal50_present ? 1 : 0) +
+              (internal68_present ? 1 : 0) +
+              (external_present   ? 1 : 0)) <= 1 )
+        {
+          sxfrctl1 |= STPWEN;
+          p->flags |= AHC_TERM_ENB_SE_LOW;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+                   p->host_no);
+        }
+      }
+      else /* p->adapter_control & CFAUTOTERM */
+      {
+        if (p->adapter_control & CFSTERM)
+        {
+          sxfrctl1 |= STPWEN;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+                   p->host_no);
+        }
+
+        if (p->adapter_control & CFWSTERM)
+        {
+          brddat |= BRDDAT6;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                   p->host_no);
+        }
+      }
+    }
+
+    aic_outb(p, sxfrctl1, SXFRCTL1);
+    write_brdctl(p, brddat);
+    release_seeprom(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   detect_maxscb
+ *
+ * Description:
+ *   Detects the maximum number of SCBs for the controller and returns
+ *   the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+  int i;
+
+  /*
+   * It's possible that we've already done this for multichannel
+   * adapters.
+   */
+  if (p->scb_data->maxhscbs == 0)
+  {
+    /*
+     * We haven't initialized the SCB settings yet.  Walk the SCBs to
+     * determince how many there are.
+     */
+    aic_outb(p, 0, FREE_SCBH);
+
+    for (i = 0; i < AIC7XXX_MAXSCB; i++)
+    {
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, i, SCB_CONTROL);
+      if (aic_inb(p, SCB_CONTROL) != i)
+        break;
+      aic_outb(p, 0, SCBPTR);
+      if (aic_inb(p, SCB_CONTROL) != 0)
+        break;
+
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
+      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS);  /* no busy untagged */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2);
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3);
+    }
+
+    /* Make sure the last SCB terminates the free list. */
+    aic_outb(p, i - 1, SCBPTR);
+    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+
+    /* Ensure we clear the first (0) SCBs control byte. */
+    aic_outb(p, 0, SCBPTR);
+    aic_outb(p, 0, SCB_CONTROL);
+
+    p->scb_data->maxhscbs = i;
+    /*
+     * Use direct indexing instead for speed
+     */
+    if ( i == AIC7XXX_MAXSCB )
+      p->flags &= ~AHC_PAGESCBS;
+  }
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_register
+ *
+ * Description:
+ *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+  int reset_delay)
+{
+  int i, result;
+  int max_targets;
+  int found = 1;
+  unsigned char term, scsi_conf;
+  struct Scsi_Host *host;
+
+  host = p->host;
+
+  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+  host->can_queue = AIC7XXX_MAXSCB;
+  host->cmd_per_lun = 3;
+  host->sg_tablesize = AIC7XXX_MAX_SG;
+  host->select_queue_depths = aic7xxx_select_queue_depth;
+  host->this_id = p->scsi_id;
+  host->io_port = p->base;
+  host->n_io_port = 0xFF;
+  host->base = p->mbase;
+  host->irq = p->irq;
+  if (p->features & AHC_WIDE)
+  {
+    host->max_id = 16;
+  }
+  if (p->features & AHC_TWIN)
+  {
+    host->max_channel = 1;
+  }
+
+  p->host = host;
+  p->host_no = host->host_no;
+  host->unique_id = p->instance;
+  p->isr_count = 0;
+  p->next = NULL;
+  p->completeq.head = NULL;
+  p->completeq.tail = NULL;
+  scbq_init(&p->scb_data->free_scbs);
+  scbq_init(&p->waiting_scbs);
+  init_timer(&p->dev_timer);
+  p->dev_timer.data = (unsigned long)p;
+  p->dev_timer.function = (void *)aic7xxx_timer;
+  p->dev_timer_active = 0;
+
+  /*
+   * We currently have no commands of any type
+   */
+  p->qinfifonext = 0;
+  p->qoutfifonext = 0;
+
+  for (i = 0; i < MAX_TARGETS; i++)
+  {
+    p->dev_commands_sent[i] = 0;
+    p->dev_flags[i] = 0;
+    p->dev_active_cmds[i] = 0;
+    p->dev_last_queue_full[i] = 0;
+    p->dev_last_queue_full_count[i] = 0;
+    p->dev_max_queue_depth[i] = 1;
+    p->dev_temp_queue_depth[i] = 1;
+    p->dev_expires[i] = 0;
+    scbq_init(&p->delayed_scbs[i]);
+  }
+
+  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+    board_names[p->board_name_index]);
+  switch(p->chip)
+  {
+    case (AHC_AIC7770|AHC_EISA):
+      printk("EISA slot %d\n", p->pci_device_fn);
+      break;
+    case (AHC_AIC7770|AHC_VL):
+      printk("VLB slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
+        PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if (p->features & AHC_TWIN)
+  {
+    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+           p->host_no, p->scsi_id, p->scsi_id_b);
+  }
+  else
+  {
+    char *channel;
+
+    channel = "";
+
+    if ((p->flags & AHC_MULTI_CHANNEL) != 0)
+    {
+      channel = " A";
+
+      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+      {
+        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+    }
+    if (p->features & AHC_WIDE)
+    {
+      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
+    }
+    else
+    {
+      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
+    }
+    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
+  }
+  aic_outb(p, 0, SEQ_FLAGS);
+
+  detect_maxscb(p);
+
+  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+  {
+    printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+      p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+      p->base, p->irq);
+    printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at 0x%lx\n",
+      p->host_no, p->mbase, (unsigned long)p->maddr);
+  }
+
+#ifdef CONFIG_PCI
+  /*
+   * Now that we know our instance number, we can set the flags we need to
+   * force termination if need be.
+   */
+  if (aic7xxx_stpwlev != -1)
+  {
+    /*
+     * This option only applies to PCI controllers.
+     */
+    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+    {
+      unsigned char devconfig;
+
+      pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig);
+      if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
+      {
+        devconfig |= STPWLEVEL;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no);
+      }
+      else
+      {
+        devconfig &= ~STPWLEVEL;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
+      }
+      pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
+    }
+  }
+#endif
+
+  /*
+   * That took care of devconfig and stpwlev, now for the actual termination
+   * settings.
+   */
+  if (aic7xxx_override_term != -1)
+  {
+    /*
+     * Again, this only applies to PCI controllers.  We don't have problems
+     * with the termination on 274x controllers to the best of my knowledge.
+     */
+    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+    {
+      unsigned char term_override;
+
+      term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f);
+      p->adapter_control &= 
+        ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM);
+      if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) )
+      {
+        p->adapter_control |= CFLVDSTERM;
+      }
+      if (term_override & 0x02)
+      {
+        p->adapter_control |= CFWSTERM;
+      }
+      if (term_override & 0x01)
+      {
+        p->adapter_control |= CFSTERM;
+      }
+    }
+  }
+
+  if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) )
+  {
+    if (p->features & AHC_SPIOCAP)
+    {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
+      /*
+       * Update the settings in sxfrctl1 to match the termination
+       * settings.
+       */
+        configure_termination(p);
+    }
+    else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870)
+    {
+      configure_termination(p);
+    }
+  }
+
+  /*
+   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
+   */
+  if (p->features & AHC_TWIN)
+  {
+    /* Select channel B */
+    aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
+
+    if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
+      term = (aic_inb(p, SXFRCTL1) & STPWEN);
+    else
+      term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0);
+
+    aic_outb(p, p->scsi_id_b, SCSIID);
+    scsi_conf = aic_inb(p, SCSICONF + 1);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, 0, SIMODE0);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    aic_outb(p, 0, SCSIRATE);
+
+    /* Select channel A */
+    aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
+  }
+
+  if (p->features & AHC_ULTRA2)
+  {
+    aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
+  }
+  else
+  {
+    aic_outb(p, p->scsi_id, SCSIID);
+  }
+  if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
+    term = (aic_inb(p, SXFRCTL1) & STPWEN);
+  else
+    term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0);
+  scsi_conf = aic_inb(p, SCSICONF);
+  aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, 0, SIMODE0);
+  /*
+   * If we are a cardbus adapter then don't enable SCSI reset detection.
+   * We shouldn't likely be sharing SCSI busses with someone else, and
+   * if we don't have a cable currently plugged into the controller then
+   * we won't have a power source for the SCSI termination, which means
+   * we'll see infinite incoming bus resets.
+   */
+  if(p->flags & AHC_NO_STPWEN)
+    aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
+  else
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  aic_outb(p, 0, SCSIRATE);
+  if ( p->features & AHC_ULTRA2)
+    aic_outb(p, 0, SCSIOFFSET);
+
+  /*
+   * Look at the information that board initialization or the board
+   * BIOS has left us. In the lower four bits of each target's
+   * scratch space any value other than 0 indicates that we should
+   * initiate synchronous transfers. If it's zero, the user or the
+   * BIOS has decided to disable synchronous negotiation to that
+   * target so we don't activate the needsdtr flag.
+   */
+  if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0)
+  {
+    max_targets = 8;
+  }
+  else
+  {
+    max_targets = 16;
+  }
+
+  if (!(aic7xxx_no_reset))
+  {
+    /*
+     * If we reset the bus, then clear the transfer settings, else leave
+     * them be
+     */
+    for (i = 0; i < max_targets; i++)
+    {
+      aic_outb(p, 0, TARG_SCSIRATE + i);
+      if (p->features & AHC_ULTRA2)
+      {
+        aic_outb(p, 0, TARG_OFFSET + i);
+      }
+      p->transinfo[i].cur_offset = 0;
+      p->transinfo[i].cur_period = 0;
+      p->transinfo[i].cur_width = MSG_EXT_WDTR_BUS_8_BIT;
+    }
+
+    /*
+     * If we reset the bus, then clear the transfer settings, else leave
+     * them be.
+     */
+    aic_outb(p, 0, ULTRA_ENB);
+    aic_outb(p, 0, ULTRA_ENB + 1);
+    p->ultraenb = 0;
+  }
+
+  /*
+   * Allocate enough hardware scbs to handle the maximum number of
+   * concurrent transactions we can have.  We have to make sure that
+   * the allocated memory is contiguous memory.  The Linux kmalloc
+   * routine should only allocate contiguous memory, but note that
+   * this could be a problem if kmalloc() is changed.
+   */
+  {
+    size_t array_size;
+    unsigned int hscb_physaddr;
+
+    array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+    if (p->scb_data->hscbs == NULL)
+    {
+      /* pci_alloc_consistent enforces the alignment already and
+       * clears the area as well.
+       */
+      p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size,
+						&p->scb_data->hscbs_dma);
+      /* We have to use pci_free_consistent, not kfree */
+      p->scb_data->hscb_kmalloc_ptr = NULL;
+      p->scb_data->hscbs_dma_len = array_size;
+    }
+    if (p->scb_data->hscbs == NULL)
+    {
+      printk("(scsi%d) Unable to allocate hardware SCB array; "
+             "failing detection.\n", p->host_no);
+      aic_outb(p, 0, SIMODE1);
+      p->irq = 0;
+      return(0);
+    }
+
+    hscb_physaddr = p->scb_data->hscbs_dma;
+    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
+
+    /* Set up the fifo areas at the same time */
+    p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma);
+    if (p->untagged_scbs == NULL)
+    {
+      printk("(scsi%d) Unable to allocate hardware FIFO arrays; "
+             "failing detection.\n", p->host_no);
+      p->irq = 0;
+      return(0);
+    }
+
+    p->qoutfifo = p->untagged_scbs + 256;
+    p->qinfifo = p->qoutfifo + 256;
+    for (i = 0; i < 256; i++)
+    {
+      p->untagged_scbs[i] = SCB_LIST_NULL;
+      p->qinfifo[i] = SCB_LIST_NULL;
+      p->qoutfifo[i] = SCB_LIST_NULL;
+    }
+
+    hscb_physaddr = p->fifo_dma;
+    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+  }
+
+  /* The Q-FIFOs we just set up are all empty */
+  aic_outb(p, 0, QINPOS);
+  aic_outb(p, 0, KERNEL_QINPOS);
+  aic_outb(p, 0, QOUTPOS);
+
+  if(p->features & AHC_QUEUE_REGS)
+  {
+    aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA);
+    aic_outb(p, 0, SDSCB_QOFF);
+    aic_outb(p, 0, SNSCB_QOFF);
+    aic_outb(p, 0, HNSCB_QOFF);
+  }
+
+  /*
+   * We don't have any waiting selections or disconnected SCBs.
+   */
+  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+
+  /*
+   * Message out buffer starts empty
+   */
+  aic_outb(p, MSG_NOOP, MSG_OUT);
+  aic_outb(p, MSG_NOOP, LAST_MSG);
+
+  /*
+   * Set all the other asundry items that haven't been set yet.
+   * This includes just dumping init values to a lot of registers simply
+   * to make sure they've been touched and are ready for use parity wise
+   * speaking.
+   */
+  aic_outb(p, 0, TMODE_CMDADDR);
+  aic_outb(p, 0, TMODE_CMDADDR + 1);
+  aic_outb(p, 0, TMODE_CMDADDR + 2);
+  aic_outb(p, 0, TMODE_CMDADDR + 3);
+  aic_outb(p, 0, TMODE_CMDADDR_NEXT);
+
+  /*
+   * Link us into the list of valid hosts
+   */
+  p->next = first_aic7xxx;
+  first_aic7xxx = p;
+
+  /*
+   * Allocate the first set of scbs for this controller.  This is to stream-
+   * line code elsewhere in the driver.  If we have to check for the existence
+   * of scbs in certain code sections, it slows things down.  However, as
+   * soon as we register the IRQ for this card, we could get an interrupt that
+   * includes possibly the SCSI_RSTI interrupt.  If we catch that interrupt
+   * then we are likely to segfault if we don't have at least one chunk of
+   * SCBs allocated or add checks all through the reset code to make sure
+   * that the SCBs have been allocated which is an invalid running condition
+   * and therefore I think it's preferable to simply pre-allocate the first
+   * chunk of SCBs.
+   */
+  aic7xxx_allocate_scb(p);
+
+  /*
+   * Load the sequencer program, then re-enable the board -
+   * resetting the AIC-7770 disables it, leaving the lights
+   * on with nobody home.
+   */
+  aic7xxx_loadseq(p);
+
+  /*
+   * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+   */
+  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+  {
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
+  }
+
+  if ( !(aic7xxx_no_reset) )
+  {
+    if (p->features & AHC_TWIN)
+    {
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
+      aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
+      aic7xxx_reset_current_bus(p);
+      aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
+    }
+    /* Reset SCSI bus A. */
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
+      char *channel = "";
+      if (p->flags & AHC_MULTI_CHANNEL)
+      {
+        channel = " A";
+        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+    }
+    
+    aic7xxx_reset_current_bus(p);
+
+    /*
+     * Delay for the reset delay by setting the timer, this will delay
+     * future commands sent to any devices.
+     */
+    p->flags |= AHC_RESET_DELAY;
+    for(i=0; i<MAX_TARGETS; i++)
+    {
+      p->dev_expires[i] = jiffies + (4 * HZ);
+      p->dev_timer_active |= (0x01 << i);
+    }
+    p->dev_timer.expires = p->dev_expires[p->scsi_id];
+    add_timer(&p->dev_timer);
+    p->dev_timer_active |= (0x01 << MAX_TARGETS);
+  }
+  else
+  {
+    if (!reset_delay)
+    {
+      printk(KERN_INFO "(scsi%d) Not resetting SCSI bus.  Note: Don't use "
+             "the no_reset\n", p->host_no);
+      printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
+             "for it.\n", p->host_no);
+    }
+  }
+  
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if (!(p->chip & AHC_PCI))
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
+    if (result < 0)
+    {
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
+    }
+  }
+  if (result < 0)
+  {
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
+           "controller.\n", p->host_no, p->irq);
+    aic_outb(p, 0, SIMODE1);
+    p->irq = 0;
+    return (0);
+  }
+
+  if(aic_inb(p, INTSTAT) & INT_PEND)
+    printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n",
+      p->host_no, -1, -1 , -1);
+  aic7xxx_clear_intstat(p);
+
+  unpause_sequencer(p, /* unpause_always */ TRUE);
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_chip_reset
+ *
+ * Description:
+ *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
+ *   is paused upon return.
+ *-F*************************************************************************/
+int
+aic7xxx_chip_reset(struct aic7xxx_host *p)
+{
+  unsigned char sblkctl;
+  int wait;
+
+  /*
+   * For some 274x boards, we must clear the CHIPRST bit and pause
+   * the sequencer. For some reason, this makes the driver work.
+   */
+  aic_outb(p, PAUSE | CHIPRST, HCNTRL);
+
+  /*
+   * In the future, we may call this function as a last resort for
+   * error handling.  Let's be nice and not do any unecessary delays.
+   */
+  wait = 1000;  /* 1 msec (1000 * 1 msec) */
+  while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
+  {
+    udelay(1);  /* 1 usec */
+  }
+
+  pause_sequencer(p);
+
+  sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE);
+  if (p->chip & AHC_PCI)
+    sblkctl &= ~SELBUSB;
+  switch( sblkctl )
+  {
+    case 0:  /* normal narrow card */
+      break;
+    case 2:  /* Wide card */
+      p->features |= AHC_WIDE;
+      break;
+    case 8:  /* Twin card */
+      p->features |= AHC_TWIN;
+      p->flags |= AHC_MULTI_CHANNEL;
+      break;
+    default: /* hmmm...we don't know what this is */
+      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+        aic_inb(p, SBLKCTL) & 0x0a);
+      return(-1);
+  }
+  return(0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_alloc
+ *
+ * Description:
+ *   Allocate and initialize a host structure.  Returns NULL upon error
+ *   and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
+{
+  struct aic7xxx_host *p = NULL;
+  struct Scsi_Host *host;
+  int i;
+
+  /*
+   * Allocate a storage area by registering us with the mid-level
+   * SCSI layer.
+   */
+  host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+  if (host != NULL)
+  {
+    p = (struct aic7xxx_host *) host->hostdata;
+    memset(p, 0, sizeof(struct aic7xxx_host));
+    *p = *temp;
+    p->host = host;
+
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
+    {
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
+    }
+    else
+    {
+      /*
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the aic7xxx_host struct, and return NULL.
+       */
+      release_region(p->base, MAXREG - MINREG);
+      scsi_unregister(host);
+      return(NULL);
+    }
+    p->host_no = host->host_no;
+    p->tagenable = 0;
+    p->orderedtag = 0;
+    for (i=0; i<MAX_TARGETS; i++)
+    {
+      p->transinfo[i].goal_period = 255;
+      p->transinfo[i].goal_offset = 0;
+      p->transinfo[i].goal_options = 0;
+      p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+    }
+    DRIVER_LOCK_INIT
+  }
+  return (p);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free
+ *
+ * Description:
+ *   Frees and releases all resources associated with an instance of
+ *   the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free(struct aic7xxx_host *p)
+{
+  int i;
+
+  /*
+   * Free the allocated hardware SCB space.
+   */
+  if (p->scb_data != NULL)
+  {
+    struct aic7xxx_scb_dma *scb_dma = NULL;
+    if (p->scb_data->hscbs != NULL)
+    {
+      pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len,
+			  p->scb_data->hscbs, p->scb_data->hscbs_dma);
+      p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
+    }
+    /*
+     * Free the driver SCBs.  These were allocated on an as-need
+     * basis.  We allocated these in groups depending on how many
+     * we could fit into a given amount of RAM.  The tail SCB for
+     * these allocations has a pointer to the alloced area.
+     */
+    for (i = 0; i < p->scb_data->numscbs; i++)
+    {
+      if (p->scb_data->scb_array[i]->scb_dma != scb_dma)
+      {
+	scb_dma = p->scb_data->scb_array[i]->scb_dma;
+	pci_free_consistent(p->pdev, scb_dma->dma_len,
+			    (void *)((unsigned long)scb_dma->dma_address
+                                     - scb_dma->dma_offset),
+			    scb_dma->dma_address);
+      }
+      if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
+        kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
+      p->scb_data->scb_array[i] = NULL;
+    }
+  
+    /*
+     * Free the SCB data area.
+     */
+    kfree(p->scb_data);
+  }
+
+  /*
+   * Free any alloced Scsi_Cmnd structures that might be around for
+   * negotiation purposes....
+   */
+  for (i = 0; i < MAX_TARGETS; i++)
+  {
+    if(p->dev_dtr_cmnd[i])
+    {
+      if(p->dev_dtr_cmnd[i]->request_buffer)
+      {
+        kfree(p->dev_dtr_cmnd[i]->request_buffer);
+      }
+      kfree(p->dev_dtr_cmnd[i]);
+    }
+  }
+
+  pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_load_seeprom
+ *
+ * Description:
+ *   Load the seeprom and configure adapter and target settings.
+ *   Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+  int have_seeprom = 0;
+  int i, max_targets, mask;
+  unsigned char scsirate, scsi_conf;
+  unsigned short scarray[128];
+  struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+  {
+    printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+  }
+  switch (p->chip)
+  {
+    case (AHC_AIC7770|AHC_EISA):  /* None of these adapters have seeproms. */
+      if (aic_inb(p, SCSICONF) & TERM_ENB)
+        p->flags |= AHC_TERM_ENB_A;
+      if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) )
+        p->flags |= AHC_TERM_ENB_B;
+      break;
+
+    case (AHC_AIC7770|AHC_VL):
+      have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+      break;
+
+    default:
+      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, p->sc_size, p->sc_type);
+      if (!have_seeprom)
+      {
+        if(p->sc_type == C46)
+          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                      scarray, p->sc_size, C56_66);
+        else
+          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                      scarray, p->sc_size, C46);
+      }
+      if (!have_seeprom)
+      {
+        p->sc_size = 128;
+        have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                    scarray, p->sc_size, p->sc_type);
+        if (!have_seeprom)
+        {
+          if(p->sc_type == C46)
+            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C56_66);
+          else
+            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C46);
+        }
+      }
+      break;
+  }
+
+  if (!have_seeprom)
+  {
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("\naic7xxx: No SEEPROM available.\n");
+    }
+    p->flags |= AHC_NEWEEPROM_FMT;
+    if (aic_inb(p, SCSISEQ) == 0)
+    {
+      p->flags |= AHC_USEDEFAULTS;
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->scsi_id = p->scsi_id_b = 7;
+      *sxfrctl1 |= STPWEN;
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+      {
+        printk("aic7xxx: Using default values.\n");
+      }
+    }
+    else if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("aic7xxx: Using leftover BIOS values.\n");
+    }
+    if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
+    {
+      p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      sc->adapter_control &= ~CFAUTOTERM;
+      sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
+    }
+    if (aic7xxx_extended)
+      p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+    else
+      p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+  }
+  else
+  {
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("done\n");
+    }
+
+    /*
+     * Note things in our flags
+     */
+    p->flags |= AHC_SEEPROM_FOUND;
+
+    /*
+     * Update the settings in sxfrctl1 to match the termination settings.
+     */
+    *sxfrctl1 = 0;
+
+    /*
+     * Get our SCSI ID from the SEEPROM setting...
+     */
+    p->scsi_id = (sc->brtime_id & CFSCSIID);
+
+    /*
+     * First process the settings that are different between the VLB
+     * and PCI adapter seeproms.
+     */
+    if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770)
+    {
+      /* VLB adapter seeproms */
+      if (sc->bios_control & CF284XEXTEND)
+        p->flags |= AHC_EXTEND_TRANS_A;
+
+      if (sc->adapter_control & CF284XSTERM)
+      {
+        *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      }
+    }
+    else
+    {
+      /* PCI adapter seeproms */
+      if (sc->bios_control & CFEXTEND)
+        p->flags |= AHC_EXTEND_TRANS_A;
+      if (sc->bios_control & CFBIOSEN)
+        p->flags |= AHC_BIOS_ENABLED;
+      else
+        p->flags &= ~AHC_BIOS_ENABLED;
+
+      if (sc->adapter_control & CFSTERM)
+      {
+        *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      }
+    }
+    memcpy(&p->sc, sc, sizeof(struct seeprom_config));
+  }
+
+  p->discenable = 0;
+    
+  /*
+   * Limit to 16 targets just in case.  The 2842 for one is known to
+   * blow the max_targets setting, future cards might also.
+   */
+  max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
+
+  if (have_seeprom)
+  {
+    for (i = 0; i < max_targets; i++)
+    {
+      if( ((p->features & AHC_ULTRA) &&
+          !(sc->adapter_control & CFULTRAEN) &&
+           (sc->device_flags[i] & CFSYNCHISULTRA)) ||
+          (sc->device_flags[i] & CFNEWULTRAFORMAT) )
+      {
+        p->flags |= AHC_NEWEEPROM_FMT;
+        break;
+      }
+    }
+  }
+
+  for (i = 0; i < max_targets; i++)
+  {
+    mask = (0x01 << i);
+    if (!have_seeprom)
+    {
+      if (aic_inb(p, SCSISEQ) != 0)
+      {
+        /*
+         * OK...the BIOS set things up and left behind the settings we need.
+         * Just make our sc->device_flags[i] entry match what the card has
+         * set for this device.
+         */
+        p->discenable = 
+          ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
+        p->ultraenb =
+          (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) );
+        sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
+        if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER)
+          sc->device_flags[i] |= CFWIDEB;
+        if (p->features & AHC_ULTRA2)
+        {
+          if (aic_inb(p, TARG_OFFSET + i))
+          {
+            sc->device_flags[i] |= CFSYNCH;
+            sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07);
+            if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 )
+              sc->device_flags[i] |= CFSYNCHISULTRA;
+          }
+        }
+        else
+        {
+          if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER)
+          {
+            sc->device_flags[i] |= CFSYNCH;
+            if (p->features & AHC_ULTRA)
+              sc->device_flags[i] |= ((p->ultraenb & mask) ?
+                                      CFSYNCHISULTRA : 0);
+          }
+        }
+      }
+      else
+      {
+        /*
+         * Assume the BIOS has NOT been run on this card and nothing between
+         * the card and the devices is configured yet.
+         */
+        sc->device_flags[i] = CFDISC;
+        if (p->features & AHC_WIDE)
+          sc->device_flags[i] |= CFWIDEB;
+        if (p->features & AHC_ULTRA3)
+          sc->device_flags[i] |= 2;
+        else if (p->features & AHC_ULTRA2)
+          sc->device_flags[i] |= 3;
+        else if (p->features & AHC_ULTRA)
+          sc->device_flags[i] |= CFSYNCHISULTRA;
+        sc->device_flags[i] |= CFSYNCH;
+        aic_outb(p, 0, TARG_SCSIRATE + i);
+        if (p->features & AHC_ULTRA2)
+          aic_outb(p, 0, TARG_OFFSET + i);
+      }
+    }
+    if (sc->device_flags[i] & CFDISC)
+    {
+      p->discenable |= mask;
+    }
+    if (p->flags & AHC_NEWEEPROM_FMT)
+    {
+      if ( !(p->features & AHC_ULTRA2) )
+      {
+        /*
+         * I know of two different Ultra BIOSes that do this differently.
+         * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+         * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s
+         * while on the IBM Netfinity 5000 they want the same thing
+         * to be something else, while flags[i] & CFXFER == 0x03 and
+         * SYNCHISULTRA false should be 40MByte/s.  So, we set both to
+         * 40MByte/s and the lower speeds be damned.  People will have
+         * to select around the conversely mapped lower speeds in order
+         * to select lower speeds on these boards.
+         */
+        if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+            ((sc->device_flags[i] & CFXFER) == 0x03) )
+        {
+          sc->device_flags[i] &= ~CFXFER;
+          sc->device_flags[i] |= CFSYNCHISULTRA;
+        }
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= mask;
+        }
+      }
+      else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+                 (p->features & AHC_ULTRA2) &&
+		 (sc->device_flags[i] & CFSYNCHISULTRA) )
+      {
+        p->ultraenb |= mask;
+      }
+    }
+    else if (sc->adapter_control & CFULTRAEN)
+    {
+      p->ultraenb |= mask;
+    }
+    if ( (sc->device_flags[i] & CFSYNCH) == 0)
+    {
+      sc->device_flags[i] &= ~CFXFER;
+      p->ultraenb &= ~mask;
+      p->transinfo[i].user_offset = 0;
+      p->transinfo[i].user_period = 0;
+      p->transinfo[i].user_options = 0;
+      p->transinfo[i].cur_offset = 0;
+      p->transinfo[i].cur_period = 0;
+      p->transinfo[i].cur_options = 0;
+      p->needsdtr_copy &= ~mask;
+    }
+    else
+    {
+      if (p->features & AHC_ULTRA3)
+      {
+        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        if( (sc->device_flags[i] & CFXFER) < 0x03 )
+        {
+          scsirate = (sc->device_flags[i] & CFXFER);
+          p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
+          if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
+          {
+            p->transinfo[i].cur_options = 
+              ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
+                 MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
+          }
+          else
+          {
+            p->transinfo[i].cur_options = 0;
+          }
+        }
+        else
+        {
+          scsirate = (sc->device_flags[i] & CFXFER) |
+                     ((p->ultraenb & mask) ? 0x18 : 0x10);
+          p->transinfo[i].user_options = 0;
+          p->transinfo[i].cur_options = 0;
+        }
+        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA3);
+        p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                       aic_inb(p, TARG_SCSIRATE + i),
+                                       AHC_SYNCRATE_ULTRA3);
+      }
+      else if (p->features & AHC_ULTRA2)
+      {
+        p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+        p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+        scsirate = (sc->device_flags[i] & CFXFER) |
+                   ((p->ultraenb & mask) ? 0x18 : 0x10);
+        p->transinfo[i].user_options = 0;
+        p->transinfo[i].cur_options = 0;
+        p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA2);
+        p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                       aic_inb(p, TARG_SCSIRATE + i),
+                                       AHC_SYNCRATE_ULTRA2);
+      }
+      else
+      {
+        scsirate = (sc->device_flags[i] & CFXFER) << 4;
+        p->transinfo[i].user_options = 0;
+        p->transinfo[i].cur_options = 0;
+        p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+        if (p->features & AHC_ULTRA)
+        {
+          short ultraenb;
+          ultraenb = aic_inb(p, ULTRA_ENB) |
+            (aic_inb(p, ULTRA_ENB + 1) << 8);
+          p->transinfo[i].user_period = aic7xxx_find_period(p,
+                                          scsirate,
+                                          (p->ultraenb & mask) ?
+                                          AHC_SYNCRATE_ULTRA :
+                                          AHC_SYNCRATE_FAST);
+          p->transinfo[i].cur_period = aic7xxx_find_period(p,
+                                         aic_inb(p, TARG_SCSIRATE + i),
+                                         (ultraenb & mask) ? 
+                                         AHC_SYNCRATE_ULTRA :
+                                         AHC_SYNCRATE_FAST);
+        }
+        else
+          p->transinfo[i].user_period = aic7xxx_find_period(p,
+                                          scsirate, AHC_SYNCRATE_FAST);
+      }
+      p->needsdtr_copy |= mask;
+    }
+    if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) )
+    {
+      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT;
+      p->needwdtr_copy |= mask;
+    }
+    else
+    {
+      p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT;
+      p->needwdtr_copy &= ~mask;
+    }
+    p->transinfo[i].cur_width =
+      (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ?
+      MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT;
+  }
+  aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+  aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+  p->needppr = p->needppr_copy = p->needdv = 0;
+  p->needwdtr = p->needwdtr_copy;
+  p->needsdtr = p->needsdtr_copy;
+  p->dtr_pending = 0;
+
+  /*
+   * We set the p->ultraenb from the SEEPROM to begin with, but now we make
+   * it match what is already down in the card.  If we are doing a reset
+   * on the card then this will get put back to a default state anyway.
+   * This allows us to not have to pre-emptively negotiate when using the
+   * no_reset option.
+   */
+  if (p->features & AHC_ULTRA)
+    p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8);
+
+  
+  scsi_conf = (p->scsi_id & HSCSIID);
+
+  if(have_seeprom)
+  {
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
+
+    switch (p->chip & AHC_CHIPID_MASK)
+    {
+      case AHC_AIC7895:
+      case AHC_AIC7896:
+      case AHC_AIC7899:
+        if (p->adapter_control & CFBPRIMARY)
+          p->flags |= AHC_CHANNEL_B_PRIMARY;
+      default:
+        break;
+    }
+
+    if (sc->adapter_control & CFSPARITY)
+      scsi_conf |= ENSPCHK;
+  }
+  else
+  {
+    scsi_conf |= ENSPCHK | RESET_SCSI;
+  }
+
+  /*
+   * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card.
+   * The 2842 and 2742 cards already have these registers set and we don't
+   * want to muck with them since we don't set all the bits they do.
+   */
+  if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+  {
+    /* Set the host ID */
+    aic_outb(p, scsi_conf, SCSICONF);
+    /* In case we are a wide card */
+    aic_outb(p, p->scsi_id, SCSICONF + 1);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_detect
+ *
+ * Description:
+ *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe().  A sequence of
+ *       probe(), attach()/detach(), and init() makes more sense than
+ *       one do-it-all function.  This may be useful when (and if) the
+ *       mid-level SCSI code is overhauled.
+ *-F*************************************************************************/
+int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
+  int found = 0;
+#if defined(__i386__) || defined(__alpha__)
+  ahc_flag_type flags = 0;
+  int type;
+#endif
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
+
+#ifdef MODULE
+  /*
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
+   */
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx);
+  if(dummy_buffer[0] != 'P')
+    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
+      "/scsi/README.aic7xxx\n"
+      "aic7xxx: to see the proper way to specify options to the aic7xxx "
+      "module\n"
+      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
+      "aic7xxx: insmod or else it might trash certain memory areas.\n");
+#endif
+
+  template->proc_name = "aic7xxx";
+  template->sg_tablesize = AIC7XXX_MAX_SG;
+
+
+#ifdef CONFIG_PCI
+  /*
+   * PCI-bus probe.
+   */
+  if (pci_present())
+  {
+    struct
+    {
+      unsigned short      vendor_id;
+      unsigned short      device_id;
+      ahc_chip            chip;
+      ahc_flag_type       flags;
+      ahc_feature         features;
+      int                 board_name_index;
+      unsigned short      seeprom_size;
+      unsigned short      seeprom_type;
+    } const aic_pdevs[] = {
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+       AHC_FNONE, AHC_FENONE,                                1,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+       AHC_PAGESCBS, AHC_AIC7850_FE,                         5,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+       AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       8,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+       AHC_AIC7870_FE,                                       9,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     10,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7870_FE,                                      11,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7870_FE,                                      12,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     13,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+       AHC_AIC7880_FE,                                      14,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     15,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7880_FE,                                      16,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7880_FE,                                      17,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7895_FE,                                      20,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      21,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      21,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      22,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      23,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      24,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      25,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      26,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN,
+       AHC_AIC7860_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+    };
+
+    unsigned short command;
+    unsigned int  devconfig, i, oldverbose;
+    struct pci_dev *pdev = NULL;
+
+    for (i = 0; i < NUMBER(aic_pdevs); i++)
+    {
+      pdev = NULL;
+      while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
+                                     aic_pdevs[i].device_id,
+                                     pdev))) {
+	if (pci_enable_device(pdev))
+		continue;
+        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
+        {
+          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
+          {
+            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+              "supported by\n");
+            printk(KERN_INFO "         this driver, we are ignoring it.\n");
+          }
+        }
+        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+                                    GFP_ATOMIC)) != NULL )
+        {
+          memset(temp_p, 0, sizeof(struct aic7xxx_host));
+          temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
+          temp_p->flags = aic_pdevs[i].flags;
+          temp_p->features = aic_pdevs[i].features;
+          temp_p->board_name_index = aic_pdevs[i].board_name_index;
+          temp_p->sc_size = aic_pdevs[i].seeprom_size;
+          temp_p->sc_type = aic_pdevs[i].seeprom_type;
+
+          /*
+           * Read sundry information from PCI BIOS.
+           */
+          temp_p->irq = pdev->irq;
+          temp_p->pdev = pdev;
+          temp_p->pci_bus = pdev->bus->number;
+          temp_p->pci_device_fn = pdev->devfn;
+          temp_p->base = pci_resource_start(pdev, 0);
+          temp_p->mbase = pci_resource_start(pdev, 1);
+          current_p = list_p;
+	  while(current_p && temp_p)
+	  {
+	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
+	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
+                 (temp_p->base && (current_p->base == temp_p->base)) ||
+                 (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
+	    {
+              /* duplicate PCI entry, skip it */
+	      kfree(temp_p);
+	      temp_p = NULL;
+	    }
+	    current_p = current_p->next;
+	  }
+	  if ( temp_p == NULL )
+            continue;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(pdev->devfn),
+              PCI_FUNC(pdev->devfn));
+          pci_read_config_word(pdev, PCI_COMMAND, &command);
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+          {
+            printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
+              (int)command);
+          }
+#ifdef AIC7XXX_STRICT_PCI_SETUP
+          command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#else
+          command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#endif
+          command &= ~PCI_COMMAND_INVALIDATE;
+          if (aic7xxx_pci_parity == 0)
+            command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+          pci_write_config_word(pdev, PCI_COMMAND, command);
+#ifdef AIC7XXX_STRICT_PCI_SETUP
+          pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+          {
+            printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
+          }
+          devconfig |= 0x80000040;
+          pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#endif /* AIC7XXX_STRICT_PCI_SETUP */
+
+          if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
+          {
+            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              temp_p->pci_bus,
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
+            printk("aic7xxx: I/O ports already in use, ignoring.\n");
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
+          }
+
+          temp_p->unpause = INTEN;
+          temp_p->pause = temp_p->unpause | PAUSE;
+          if ( ((temp_p->base == 0) &&
+                (temp_p->mbase == 0)) ||
+               (temp_p->irq == 0) )
+          {
+            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              temp_p->pci_bus,
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
+            printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
+          }
+
+#ifdef MMAPIO
+          if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
+               ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
+                (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
+          {
+            unsigned long page_offset, base;
+
+            base = temp_p->mbase & PAGE_MASK;
+            page_offset = temp_p->mbase - base;
+            temp_p->maddr = ioremap_nocache(base, page_offset + 256);
+            if(temp_p->maddr)
+            {
+              temp_p->maddr += page_offset;
+              /*
+               * We need to check the I/O with the MMAPed address.  Some machines
+               * simply fail to work with MMAPed I/O and certain controllers.
+               */
+              if(aic_inb(temp_p, HCNTRL) == 0xff)
+              {
+                /*
+                 * OK.....we failed our test....go back to programmed I/O
+                 */
+                printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                  board_names[aic_pdevs[i].board_name_index],
+                  temp_p->pci_bus,
+                  PCI_SLOT(temp_p->pci_device_fn),
+                  PCI_FUNC(temp_p->pci_device_fn));
+                printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
+                                 "Programmed I/O.\n");
+                iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+                temp_p->maddr = 0;
+                if(temp_p->base == 0)
+                {
+                  printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+                  kfree(temp_p);
+                  temp_p = NULL;
+                  continue;
+                }
+              }
+            }
+          }
+#endif
+
+          /*
+           * Lock out other contenders for our i/o space.
+           */
+          if(temp_p->base)
+            request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+
+          /*
+           * We HAVE to make sure the first pause_sequencer() and all other
+           * subsequent I/O that isn't PCI config space I/O takes place
+           * after the MMAPed I/O region is configured and tested.  The
+           * problem is the PowerPC architecture that doesn't support
+           * programmed I/O at all, so we have to have the MMAP I/O set up
+           * for this pause to even work on those machines.
+           */
+          pause_sequencer(temp_p);
+
+          /*
+           * Clear out any pending PCI error status messages.  Also set
+           * verbose to 0 so that we don't emit strange PCI error messages
+           * while cleaning out the current status bits.
+           */
+          oldverbose = aic7xxx_verbose;
+          aic7xxx_verbose = 0;
+          aic7xxx_pci_intr(temp_p);
+          aic7xxx_verbose = oldverbose;
+
+          temp_p->bios_address = 0;
+
+          /*
+           * Remember how the card was setup in case there is no seeprom.
+           */
+          if (temp_p->features & AHC_ULTRA2)
+            temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID;
+          else
+            temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          /*
+           * Get current termination setting
+           */
+          sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
+
+          if (aic7xxx_chip_reset(temp_p) == -1)
+          {
+            release_region(temp_p->base, MAXREG - MINREG);
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
+          }
+          /*
+           * Very quickly put the term setting back into the register since
+           * the chip reset may cause odd things to happen.  This is to keep
+           * LVD busses with lots of drives from draining the power out of
+           * the diffsense line before we get around to running the
+           * configure_termination() function.  Also restore the STPWLEVEL
+           * bit of DEVCONFIG
+           */
+          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+          pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
+          sxfrctl1 &= STPWEN;
+
+          /*
+           * We need to set the CHNL? assignments before loading the SEEPROM
+           * The 3940 and 3985 cards (original stuff, not any of the later
+           * stuff) are 7870 and 7880 class chips.  The Ultra2 stuff falls
+           * under 7896 and 7897.  The 7895 is in a class by itself :)
+           */
+          switch (temp_p->chip & AHC_CHIPID_MASK)
+          {
+            case AHC_AIC7870: /* 3840 / 3985 */
+            case AHC_AIC7880: /* 3840 UW / 3985 UW */
+              if(temp_p->flags & AHC_MULTI_CHANNEL)
+              {
+                switch(PCI_SLOT(temp_p->pci_device_fn))
+                {
+                  case 5:
+                    temp_p->flags |= AHC_CHNLB;
+                    break;
+                  case 8:
+                    temp_p->flags |= AHC_CHNLB;
+                    break;
+                  case 12:
+                    temp_p->flags |= AHC_CHNLC;
+                    break;
+                  default:
+                    break;
+                }
+              }
+              break;
+
+            case AHC_AIC7895: /* 7895 */
+            case AHC_AIC7896: /* 7896/7 */
+            case AHC_AIC7899: /* 7899 */
+              if (PCI_FUNC(pdev->devfn) != 0)
+              {
+                temp_p->flags |= AHC_CHNLB;
+              }
+              /*
+               * The 7895 is the only chipset that sets the SCBSIZE32 param
+               * in the DEVCONFIG register.  The Ultra2 chipsets use
+               * the DSCOMMAND0 register instead.
+               */
+              if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+              {
+                pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+                devconfig |= SCBSIZE32;
+                pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * Loading of the SEEPROM needs to come after we've set the flags
+           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
+           * on 394x and 398x cards we'll end up reading the wrong settings
+           * for channels B and C
+           */
+          switch (temp_p->chip & AHC_CHIPID_MASK)
+          {
+            case AHC_AIC7892:
+            case AHC_AIC7899:
+              aic_outb(temp_p, 0, SCAMCTL);
+              /*
+               * Switch to the alt mode of the chip...
+               */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
+              /*
+               * Set our options...the last two items set our CRC after x byte
+	       * count in target mode...
+               */
+              aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
+	      aic_outb(temp_p, 0x00, 0x0b);
+	      aic_outb(temp_p, 0x10, 0x0a);
+              /*
+               * switch back to normal mode...
+               */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
+              aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
+			       TARGCRCENDEN | TARGCRCCNTEN,
+                       CRCCONTROL1);
+              aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
+                                 MPARCKEN | CIOPARCKEN | CACHETHEN) & 
+                               ~DPARCKEN), DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7890:
+            case AHC_AIC7896:
+              aic_outb(temp_p, 0, SCAMCTL);
+              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                CACHETHEN | MPARCKEN | USCBSIZE32 |
+                                CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7850:
+            case AHC_AIC7860:
+              /*
+               * Set the DSCOMMAND0 register on these cards different from
+               * on the 789x cards.  Also, read the SEEPROM as well.
+               */
+              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                CACHETHEN | MPARCKEN) & ~DPARCKEN,
+                       DSCOMMAND0);
+              /* FALLTHROUGH */
+            default:
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7880:
+              /*
+               * Check the rev of the chipset before we change DSCOMMAND0
+               */
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              if ((devconfig & 0xff) >= 1)
+              {
+                aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                  CACHETHEN | MPARCKEN) & ~DPARCKEN,
+                         DSCOMMAND0);
+              }
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+          }
+          
+
+          /*
+           * and then we need another switch based on the type in order to
+           * make sure the channel B primary flag is set properly on 7895
+           * controllers....Arrrgggghhh!!!  We also have to catch the fact
+           * that when you disable the BIOS on the 7895 on the Intel DK440LX
+           * motherboard, and possibly others, it only sets the BIOS disabled
+           * bit on the A channel...I think I'm starting to lean towards
+           * going postal....
+           */
+          switch(temp_p->chip & AHC_CHIPID_MASK)
+          {
+            case AHC_AIC7895:
+            case AHC_AIC7896:
+            case AHC_AIC7899:
+              current_p = list_p;
+              while(current_p != NULL)
+              {
+                if ( (current_p->pci_bus == temp_p->pci_bus) &&
+                     (PCI_SLOT(current_p->pci_device_fn) ==
+                      PCI_SLOT(temp_p->pci_device_fn)) )
+                {
+                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+                  {
+                    temp_p->flags |= 
+                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+                    temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
+                    temp_p->flags |=
+                      (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
+                  }
+                  else
+                  {
+                    current_p->flags |=
+                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                    current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
+                    current_p->flags |=
+                      (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
+                  }
+                }
+                current_p = current_p->next;
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * We only support external SCB RAM on the 7895/6/7 chipsets.
+           * We could support it on the 7890/1 easy enough, but I don't
+           * know of any 7890/1 based cards that have it.  I do know
+           * of 7895/6/7 cards that have it and they work properly.
+           */
+          switch(temp_p->chip & AHC_CHIPID_MASK)
+          {
+            default:
+              break;
+            case AHC_AIC7895:
+            case AHC_AIC7896:
+            case AHC_AIC7899:
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              if (temp_p->features & AHC_ULTRA2)
+              {
+                if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
+                     (aic7xxx_scbram) )
+                {
+                  aic_outb(temp_p,
+                           aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
+                           DSCOMMAND0);
+                  temp_p->flags |= AHC_EXTERNAL_SRAM;
+                  devconfig |= EXTSCBPEN;
+                }
+                else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+                {
+                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: external SCB RAM detected, "
+                         "but not enabled\n");
+                }
+              }
+              else
+              {
+                if ((devconfig & RAMPSM) && (aic7xxx_scbram))
+                {
+                  devconfig &= ~SCBRAMSEL;
+                  devconfig |= EXTSCBPEN;
+                  temp_p->flags |= AHC_EXTERNAL_SRAM;
+                }
+                else if (devconfig & RAMPSM)
+                {
+                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: external SCB RAM detected, "
+                         "but not enabled\n");
+                }
+              }
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+              if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
+                   (temp_p->flags & AHC_CHNLB) )
+                aic_outb(temp_p, 1, CCSCBBADDR);
+              break;
+          }
+
+          /*
+           * Take the LED out of diagnostic mode
+           */
+          aic_outb(temp_p, 
+            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+            SBLKCTL);
+
+          /*
+           * We don't know where this is set in the SEEPROM or by the
+           * BIOS, so we default to 100%.  On Ultra2 controllers, use 75%
+           * instead.
+           */
+          if (temp_p->features & AHC_ULTRA2)
+          {
+            aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
+          }
+          else
+          {
+            aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
+          }
+
+          if ( list_p == NULL )
+          {
+            list_p = current_p = temp_p;
+          }
+          else
+          {
+            current_p = list_p;
+            while(current_p->next != NULL)
+              current_p = current_p->next;
+            current_p->next = temp_p;
+          }
+          temp_p->next = NULL;
+          found++;
+        }  /* Found an Adaptec PCI device. */
+        else /* Well, we found one, but we couldn't get any memory */
+        {
+          printk("aic7xxx: Found <%s>\n", 
+            board_names[aic_pdevs[i].board_name_index]);
+          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+            "skipping.\n");
+        }
+      } /* while(pdev=....) */
+    } /* for PCI_DEVICES */
+  } /* PCI BIOS present */
+#endif CONFIG_PCI
+
+#if defined(__i386__) || defined(__alpha__)
+  /*
+   * EISA/VL-bus card signature probe.
+   */
+  slot = MINSLOT;
+  while ( (slot <= MAXSLOT) && 
+         !(aic7xxx_no_probe) )
+  {
+    base = SLOTBASE(slot) + MINREG;
+
+    if (check_region(base, MAXREG - MINREG))
+    {
+      /*
+       * Some other driver has staked a
+       * claim to this i/o region already.
+       */
+      slot++;
+      continue; /* back to the beginning of the for loop */
+    }
+    flags = 0;
+    type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
+    if (type == -1)
+    {
+      slot++;
+      continue;
+    }
+    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+    if (temp_p == NULL)
+    {
+      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+      slot++;
+      continue; /* back to the beginning of the while loop */
+    }
+    /*
+     * Lock out other contenders for our i/o space.
+     */
+    request_region(base, MAXREG - MINREG, "aic7xxx");
+
+    /*
+     * Pause the card preserving the IRQ type.  Allow the operator
+     * to override the IRQ trigger.
+     */
+    if (aic7xxx_irq_trigger == 1)
+      hcntrl = IRQMS;  /* Level */
+    else if (aic7xxx_irq_trigger == 0)
+      hcntrl = 0;  /* Edge */
+    else
+      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+    memset(temp_p, 0, sizeof(struct aic7xxx_host));
+    temp_p->unpause = hcntrl | INTEN;
+    temp_p->pause = hcntrl | PAUSE | INTEN;
+    temp_p->base = base;
+    temp_p->mbase = 0;
+    temp_p->maddr = 0;
+    temp_p->pci_bus = 0;
+    temp_p->pci_device_fn = slot;
+    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+    if (aic7xxx_chip_reset(temp_p) == -1)
+      temp_p->irq = 0;
+    else
+      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    temp_p->flags |= AHC_PAGESCBS;
+
+    switch (temp_p->irq)
+    {
+      case 9:
+      case 10:
+      case 11:
+      case 12:
+      case 14:
+      case 15:
+        break;
+
+      default:
+        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level %d, ignoring.\n", temp_p->irq);
+        kfree(temp_p);
+        release_region(base, MAXREG - MINREG);
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
+
+    /*
+     * We are commited now, everything has been checked and this card
+     * has been found, now we just set it up
+     */
+
+    /*
+     * Insert our new struct into the list at the end
+     */
+    if (list_p == NULL)
+    {
+      list_p = current_p = temp_p;
+    }
+    else
+    {
+      current_p = list_p;
+      while (current_p->next != NULL)
+        current_p = current_p->next;
+      current_p->next = temp_p;
+    }
+
+    switch (type)
+    {
+      case 0:
+        temp_p->board_name_index = 2;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[2], slot);
+        /* FALLTHROUGH */
+      case 1:
+      {
+        temp_p->chip = AHC_AIC7770 | AHC_EISA;
+        temp_p->features |= AHC_AIC7770_FE;
+        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
+
+        /*
+         * Get the primary channel information.  Right now we don't
+         * do anything with this, but someday we will be able to inform
+         * the mid-level SCSI code which channel is primary.
+         */
+        if (temp_p->board_name_index == 0)
+        {
+          temp_p->board_name_index = 3;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at EISA %d\n",
+                 board_names[3], slot);
+        }
+        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
+        {
+          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
+        }
+
+        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+        {
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        }
+        else
+        {
+          temp_p->flags &= ~AHC_USEDEFAULTS;
+          temp_p->flags |= AHC_BIOS_ENABLED;
+          if ( (temp_p->bios_control & 0x20) == 0 )
+          {
+            temp_p->bios_address = 0xcc000;
+            temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
+          }
+          else
+          {
+            temp_p->bios_address = 0xd0000;
+            temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
+          }
+        }
+        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+        if (temp_p->features & AHC_WIDE)
+        {
+          temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
+          temp_p->scsi_id_b = temp_p->scsi_id;
+        }
+        else
+        {
+          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
+        }
+        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+        break;
+      }
+
+      case 2:
+      case 3:
+        temp_p->chip = AHC_AIC7770 | AHC_VL;
+        temp_p->features |= AHC_AIC7770_FE;
+        if (type == 2)
+          temp_p->flags |= AHC_BIOS_ENABLED;
+        else
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
+          sxfrctl1 = STPWEN;
+        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+        temp_p->board_name_index = 4;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at VLB %d\n",
+               board_names[2], slot);
+        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
+        {
+          case 0x00:
+            temp_p->bios_address = 0xe0000;
+            break;
+          case 0x20:
+            temp_p->bios_address = 0xc8000;
+            break;
+          case 0x40:
+            temp_p->bios_address = 0xd0000;
+            break;
+          case 0x60:
+            temp_p->bios_address = 0xd8000;
+            break;
+          default:
+            break; /* can't get here */
+        }
+        break;
+
+      default:  /* Won't get here. */
+        break;
+    }
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+        temp_p->irq,
+        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
+    }
+
+    /*
+     * Set the FIFO threshold and the bus off time.
+     */
+    hostconf = aic_inb(temp_p, HOSTCONF);
+    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+    slot++;
+    found++;
+  }
+
+#endif /* defined(__i386__) || defined(__alpha__) */
+
+  /*
+   * Now, we re-order the probed devices by BIOS address and BUS class.
+   * In general, we follow this algorithm to make the adapters show up
+   * in the same order under linux that the computer finds them.
+   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+   *     address, going from lowest to highest.
+   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+   *     address, going from lowest to highest.
+   *  3: Remaining VLB/EISA controllers going in slot order.
+   *  4: Remaining PCI controllers, going in PCI device order (reversable)
+   */
+
+  {
+    struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL };
+    struct aic7xxx_host *vlb, *pci;
+    struct aic7xxx_host *prev_p;
+    struct aic7xxx_host *p;
+    unsigned char left;
+
+    prev_p = vlb = pci = NULL;
+
+    temp_p = list_p;
+    while (temp_p != NULL)
+    {
+      switch(temp_p->chip & ~AHC_CHIPID_MASK)
+      {
+        case AHC_EISA:
+        case AHC_VL:
+        {
+          p = temp_p;
+          if (p->flags & AHC_BIOS_ENABLED)
+            vlb = sort_list[0];
+          else
+            vlb = sort_list[2];
+
+          if (vlb == NULL)
+          {
+            vlb = temp_p;
+            temp_p = temp_p->next;
+            vlb->next = NULL;
+          }
+          else
+          {
+            current_p = vlb;
+            prev_p = NULL;
+            while ( (current_p != NULL) &&
+                    (current_p->bios_address < temp_p->bios_address))
+            {
+              prev_p = current_p;
+              current_p = current_p->next;
+            }
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              vlb = temp_p;
+              temp_p = temp_p->next;
+              vlb->next = current_p;
+            }
+          }
+          
+          if (p->flags & AHC_BIOS_ENABLED)
+            sort_list[0] = vlb;
+          else
+            sort_list[2] = vlb;
+          
+          break;
+        }
+        default:  /* All PCI controllers fall through to default */
+        {
+
+          p = temp_p;
+          if (p->flags & AHC_BIOS_ENABLED) 
+            pci = sort_list[1];
+          else
+            pci = sort_list[3];
+
+          if (pci == NULL)
+          {
+            pci = temp_p;
+            temp_p = temp_p->next;
+            pci->next = NULL;
+          }
+          else
+          {
+            current_p = pci;
+            prev_p = NULL;
+            if (!aic7xxx_reverse_scan)
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) < 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            else
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) > 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            /*
+             * Are we dealing with a 7895/6/7/9 where we need to sort the
+             * channels as well, if so, the bios_address values should
+             * be the same
+             */
+            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+                 (temp_p->pci_bus == current_p->pci_bus) &&
+                 (PCI_SLOT(temp_p->pci_device_fn) ==
+                  PCI_SLOT(current_p->pci_device_fn)) )
+            {
+              if (temp_p->flags & AHC_CHNLB)
+              {
+                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+              else
+              {
+                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+            }
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              pci = temp_p;
+              temp_p = temp_p->next;
+              pci->next = current_p;
+            }
+          }
+
+          if (p->flags & AHC_BIOS_ENABLED)
+            sort_list[1] = pci;
+          else
+            sort_list[3] = pci;
+
+          break;
+        }
+      }  /* End of switch(temp_p->type) */
+    } /* End of while (temp_p != NULL) */
+    /*
+     * At this point, the cards have been broken into 4 sorted lists, now
+     * we run through the lists in order and register each controller
+     */
+    {
+      int i;
+      
+      left = found;
+      for (i=0; i<NUMBER(sort_list); i++)
+      {
+        temp_p = sort_list[i];
+        while(temp_p != NULL)
+        {
+          template->name = board_names[temp_p->board_name_index];
+          p = aic7xxx_alloc(template, temp_p);
+          if (p != NULL)
+          {
+            p->instance = found - left;
+            if (aic7xxx_register(template, p, (--left)) == 0)
+            {
+              found--;
+              aic7xxx_release(p->host);
+              scsi_unregister(p->host);
+            }
+            else if (aic7xxx_dump_card)
+            {
+              pause_sequencer(p);
+              aic7xxx_print_card(p);
+              aic7xxx_print_scratch_ram(p);
+              unpause_sequencer(p, TRUE);
+            }
+          }
+          current_p = temp_p;
+          temp_p = (struct aic7xxx_host *)temp_p->next;
+          kfree(current_p);
+        }
+      }
+    }
+  }
+  return (found);
+}
+
+static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
+                                           Scsi_Cmnd *old_cmd, int tindex);
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_allocate_negotiation_command
+ *
+ * Description:
+ *   allocate the actual command struct and fill in the gaps...
+ *-F*************************************************************************/
+static Scsi_Cmnd *
+aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
+                                     Scsi_Cmnd *old_cmd, int tindex)
+{
+  Scsi_Cmnd *cmd;
+  char *buffer;
+
+  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+  {
+    return(NULL);
+  }
+  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
+  {
+    kfree(p->dev_dtr_cmnd[tindex]);
+    p->dev_dtr_cmnd[tindex] = NULL;
+    return(NULL);
+  }
+  cmd = p->dev_dtr_cmnd[tindex];
+  memset(cmd, 0, sizeof(Scsi_Cmnd));
+  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+  cmd->lun = 0;
+  cmd->request_bufflen = 255;
+  cmd->request_buffer = buffer;
+  cmd->sc_data_direction = SCSI_DATA_READ;
+  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+  cmd->bufflen = 0;
+  cmd->buffer = NULL;
+  cmd->underflow = 0;
+  cmd->cmd_len = 6;
+  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
+  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
+  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
+  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
+  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
+  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
+  return(cmd);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_negotiation_complete
+ *
+ * Description:
+ *   Handle completion events for our Negotiation commands.  Clear out the
+ *   struct and get it ready for its next use.
+ *-F*************************************************************************/
+static void
+aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
+{
+  unsigned int checksum;
+  int i;
+  int *ibuffer;
+  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_syncrate *syncrate;
+
+  /*
+   * perform our minimalistic domain validation
+   */
+  if(p->dev_flags[tindex] & DEVICE_SCANNED)
+  {
+    ibuffer = (int *)cmd->request_buffer;
+    checksum = 0;
+    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
+    {
+      checksum += ibuffer[i];
+    }
+    if( (checksum != p->dev_checksum[tindex]) &&
+        (p->transinfo[tindex].cur_offset != 0) )
+    {
+      unsigned int period = p->transinfo[tindex].cur_period;
+      unsigned char options = p->transinfo[tindex].cur_options;
+
+      if (p->needdv & (1<<tindex))
+      {
+        /*
+         * oops, we had a failure, lower the transfer rate and try again.  It's
+         * worth noting here that it might be wise to also check for typical
+         * wide setting on narrow cable type problems and try disabling wide
+         * instead of slowing down if those exist.  That's hard to do with simple
+         * checksums though.
+         */
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
+        {
+          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
+                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
+        }
+        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+        {
+          syncrate++;
+          if( (syncrate->rate[0] != NULL) &&
+              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+          {
+            p->transinfo[tindex].goal_period = syncrate->period;
+            if( p->transinfo[tindex].goal_period > 9 )
+            {
+              p->transinfo[tindex].goal_options = 0;
+              p->needppr &= ~(1<<tindex);
+              p->needsdtr |= (1<<tindex);
+              p->needppr_copy &= ~(1<<tindex);
+              p->needsdtr_copy |= (1<<tindex);
+              if (p->transinfo[tindex].goal_width)
+              {
+                p->needwdtr |= (1<<tindex);
+                p->needwdtr_copy |= (1<<tindex);
+              }
+            }
+          }
+          else if (p->transinfo[tindex].goal_width)
+          {
+            p->transinfo[tindex].goal_width = 0;
+            p->needwdtr &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
+            p->transinfo[tindex].goal_offset =
+              p->transinfo[tindex].user_offset;
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_options =
+              p->transinfo[tindex].user_options;
+            if( p->transinfo[tindex].goal_period <= 9 )
+            {
+              p->needppr |= (1<<tindex);
+              p->needsdtr &= ~(1<<tindex);
+              p->needppr_copy |= (1<<tindex);
+              p->needsdtr_copy &= ~(1<<tindex);
+            }
+            else
+            {
+              p->needppr &= ~(1<<tindex);
+              p->needsdtr |= (1<<tindex);
+              p->needppr_copy &= ~(1<<tindex);
+              p->needsdtr_copy |= (1<<tindex);
+            }
+          }
+          else
+          {
+            p->transinfo[tindex].goal_offset = 0;
+            p->transinfo[tindex].goal_period = 255;
+            p->transinfo[tindex].goal_options = 0;
+            p->transinfo[tindex].goal_width = 0;
+            p->needppr &= ~(1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needwdtr &= ~(1<<tindex);
+            p->needppr_copy &= ~(1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
+          }
+        }
+        p->needdv &= ~(1<<tindex);
+      }
+      else
+      {
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
+        {
+          printk(INFO_LEAD "Performing Domain validation.\n",
+                 p->host_no, CTL_OF_CMD(cmd));
+        }
+        /*
+         * Update the checksum in case the INQUIRY data has changed, maybe
+         * in relation to a change in the mode pages, or whatever.
+         */
+        p->dev_checksum[tindex] = checksum;
+        /*
+         * Signal that we are trying out the domain validation
+         */
+        p->needdv |= (1<<tindex);
+        /*
+         * Signal that we need to re-negotiate things, this also gets us our
+         * INQUIRY command to re-checksum off of.
+         */
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+    } 
+    else
+    {
+      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+          (p->needdv & (1<<tindex)) )
+      {
+        printk(INFO_LEAD "Successfully completed Domain validation.\n",
+               p->host_no, CTL_OF_CMD(cmd));
+      }
+      /*
+       * We successfully did our checksum, so don't leave the needdv flag set
+       * in case we might have set it last time through.
+       */
+      p->needdv &= ~(1<<tindex);
+    }
+  }
+
+  p->dtr_pending &= ~(0x01 << tindex);
+  /*
+   * This looks recursive in the extreme, but if this was a WDTR negotiation
+   * and we didn't follow up with SDTR yet, then this will get it started.
+   * For all other cases, this should work out to be a no-op, unless we are
+   * doing domain validation and happen to need a new negotiation command.
+   *
+   * In case we don't want this to go any further, the cmdcmplt interrupt
+   * handler will NULL out the cmd->next entry so that the real SCSI command
+   * can be sent back to the mid layer code with SENSE data intact.  We'll
+   * finish things up when the cmd gets sent back down to us, so no worries.
+   */
+  if(cmd->next)
+  {
+    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+  }
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_build_negotiation_command
+ *
+ * Description:
+ *   Build a Scsi_Cmnd structure to perform negotiation with or else send
+ *   a pre-built command specifically for this purpose.
+ *-F*************************************************************************/
+static void
+aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
+  int tindex)
+{
+
+  if ( !(p->dtr_pending & (1<<tindex)) &&
+       ( (p->needppr & (1<<tindex)) ||
+         (p->needwdtr & (1<<tindex)) ||
+         (p->needsdtr & (1<<tindex)) ) )
+  {
+    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
+         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
+    {
+      return;
+    }
+    /*
+     * Before sending this thing out, we also make the cmd->next pointer
+     * point to the real command so we can stuff any possible SENSE data
+     * into the real command instead of this fake command.  This has to be
+     * done each time the command is built, not just the first time, hence
+     * it's outside of the above if()...
+     */
+    p->dev_dtr_cmnd[tindex]->next = old_cmd;
+    /*
+     * Clear the buffer so checksums come out right....
+     */
+    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
+           p->dev_dtr_cmnd[tindex]->request_bufflen);
+    /*
+     * Remove any commands for this particular device that might be on the
+     * waiting_scbs queue or qinfifo so that this command goes out first.
+     * This is vital for our implementation of domain validation.
+     */
+    pause_sequencer(p);
+    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
+                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
+    unpause_sequencer(p, FALSE);
+    {
+      struct aic7xxx_scb *scb, *next;
+
+      scb = p->waiting_scbs.head;
+      while(scb != NULL)
+      {
+        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
+                              ALL_LUNS, SCB_LIST_NULL) )
+        {
+          next = scb->q_next;
+          scbq_remove(&p->waiting_scbs, scb);
+          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+          scb = next;
+        }
+        else
+        {
+          scb = scb->q_next;
+        }
+      }
+    }
+    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
+                  aic7xxx_negotiation_complete);
+  }
+}
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_scb
+ *
+ * Description:
+ *   Dump the byte codes for an about to be sent SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i;
+  unsigned char *x;  
+
+  x = (unsigned char *)&scb->hscb->control;
+
+  for(i=0; i<32; i++)
+  {
+    printk("%02x ", x[i]);
+  }
+  printk("\n");
+}
+#endif
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_buildscb
+ *
+ * Description:
+ *   Build a SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
+    struct aic7xxx_scb *scb)
+{
+  unsigned short mask;
+  struct aic7xxx_hwscb *hscb;
+  unsigned char tindex = TARGET_INDEX(cmd);
+
+  mask = (0x01 << tindex);
+  hscb = scb->hscb;
+
+  /*
+   * Setup the control byte if we need negotiation and have not
+   * already requested it.
+   */
+  hscb->control = 0;
+  scb->tag_action = 0;
+  cmd->tag = hscb->tag;
+  if (p->discenable & mask)
+  {
+    hscb->control |= DISCENB;
+    if ( (p->tagenable & mask) &&
+         (cmd->cmnd[0] != TEST_UNIT_READY) )
+    {
+      p->dev_commands_sent[tindex]++;
+      if (p->dev_commands_sent[tindex] < 200)
+      {
+        hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
+      }
+      else
+      {
+        if (p->orderedtag & mask)
+        {
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+        }
+        else
+        {
+          hscb->control |= MSG_SIMPLE_Q_TAG;
+          scb->tag_action = MSG_SIMPLE_Q_TAG;
+        }
+        p->dev_commands_sent[tindex] = 0;
+      }
+    }
+  }
+  if ( cmd == p->dev_dtr_cmnd[tindex] )
+  {
+    p->dtr_pending |= mask;
+    scb->tag_action = 0;
+    if (p->dev_flags[tindex] & DEVICE_SCANNED)
+    {
+      hscb->control &= DISCENB;
+      hscb->control |= MK_MESSAGE;
+      if(p->needppr & mask)
+      {
+        scb->flags |= SCB_MSGOUT_PPR;
+      }
+      else if(p->needwdtr & mask)
+      {
+        scb->flags |= SCB_MSGOUT_WDTR;
+      }
+      else if(p->needsdtr & mask)
+      {
+        scb->flags |= SCB_MSGOUT_SDTR;
+      }
+    }
+  }
+  if ( !(p->dtr_pending & mask) &&
+        ( (p->needppr & mask) ||
+          (p->needwdtr & mask) ||
+          (p->needsdtr & mask) ) )
+  {
+    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
+  }
+  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+
+  /*
+   * The interpretation of request_buffer and request_bufflen
+   * changes depending on whether or not use_sg is zero; a
+   * non-zero use_sg indicates the number of elements in the
+   * scatter-gather array.
+   */
+
+  /*
+   * XXX - this relies on the host data being stored in a
+   *       little-endian format.
+   */
+  hscb->SCSI_cmd_length = cmd->cmd_len;
+  memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
+  hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
+
+  if (cmd->use_sg)
+  {
+    struct scatterlist *sg;  /* Must be mid-level SCSI code scatterlist */
+
+    /*
+     * We must build an SG list in adapter format, as the kernel's SG list
+     * cannot be used directly because of data field size (__alpha__)
+     * differences and the kernel SG list uses virtual addresses where
+     * we need physical addresses.
+     */
+    int i, use_sg;
+
+    sg = (struct scatterlist *)cmd->request_buffer;
+    scb->sg_length = 0;
+    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+    /*
+     * Copy the segments into the SG array.  NOTE!!! - We used to
+     * have the first entry both in the data_pointer area and the first
+     * SG element.  That has changed somewhat.  We still have the first
+     * entry in both places, but now we download the address of
+     * scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
+     */
+    for (i = 0; i < use_sg; i++)
+    {
+      unsigned int len = sg_dma_len(sg+i);
+      scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+      scb->sg_list[i].length = cpu_to_le32(len);
+      scb->sg_length += len;
+    }
+    /* Copy the first SG into the data pointer area. */
+    hscb->data_pointer = scb->sg_list[0].address;
+    hscb->data_count = scb->sg_list[0].length;
+    scb->sg_count = i;
+    hscb->SG_segment_count = i;
+    hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
+  }
+  else
+  {
+    if (cmd->request_bufflen)
+    {
+      unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
+					    cmd->request_bufflen,
+                                            scsi_to_pci_dma_dir(cmd->sc_data_direction));
+      aic7xxx_mapping(cmd) = address;
+      scb->sg_list[0].address = cpu_to_le32(address);
+      scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+      scb->sg_count = 1;
+      scb->sg_length = cmd->request_bufflen;
+      hscb->SG_segment_count = 1;
+      hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
+      hscb->data_count = scb->sg_list[0].length;
+      hscb->data_pointer = scb->sg_list[0].address;
+    }
+    else
+    {
+      scb->sg_count = 0;
+      scb->sg_length = 0;
+      hscb->SG_segment_count = 0;
+      hscb->SG_list_pointer = 0;
+      hscb->data_count = 0;
+      hscb->data_pointer = 0;
+    }
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_queue
+ *
+ * Description:
+ *   Queue a SCB to the controller.
+ *-F*************************************************************************/
+int
+aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+  struct aic7xxx_host *p;
+  struct aic7xxx_scb *scb;
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  int tindex = TARGET_INDEX(cmd);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  /*
+   * Check to see if channel was scanned.
+   */
+  
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
+  {
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 0, -1, -1);
+    p->flags |= AHC_A_SCANNED;
+  }
+  else
+  {
+    if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
+    {
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(INFO_LEAD "Scanning channel for devices.\n",
+          p->host_no, 1, -1, -1);
+      p->flags |= AHC_B_SCANNED;
+    }
+  }
+
+  if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1))
+  {
+    printk(WARN_LEAD "Commands queued exceeds queue "
+           "depth, active=%d\n",
+           p->host_no, CTL_OF_CMD(cmd), 
+           p->dev_active_cmds[tindex]);
+    if ( p->dev_active_cmds[tindex] > 220 )
+      p->dev_active_cmds[tindex] = 0;
+  }
+#endif
+
+  scb = scbq_remove_head(&p->scb_data->free_scbs);
+  if (scb == NULL)
+  {
+    DRIVER_LOCK
+    aic7xxx_allocate_scb(p);
+    DRIVER_UNLOCK
+    scb = scbq_remove_head(&p->scb_data->free_scbs);
+  }
+  if (scb == NULL)
+  {
+    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+           CTL_OF_CMD(cmd));
+    cmd->result = (DID_BUS_BUSY << 16);
+    DRIVER_LOCK
+    aic7xxx_queue_cmd_complete(p, cmd);
+    DRIVER_UNLOCK
+    return 0;
+  }
+  else
+  {
+    scb->cmd = cmd;
+    aic7xxx_position(cmd) = scb->hscb->tag;
+
+    /*
+     * Construct the SCB beforehand, so the sequencer is
+     * paused a minimal amount of time.
+     */
+    aic7xxx_buildscb(p, cmd, scb);
+
+    /*
+     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+     * is set up properly, and the parity error flag is reset, then send
+     * the SCB to the sequencer and watch the fun begin.
+     */
+    cmd->scsi_done = fn;
+    cmd->result = DID_OK;
+    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+    aic7xxx_error(cmd) = DID_OK;
+    aic7xxx_status(cmd) = 0;
+    cmd->host_scribble = NULL;
+
+    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+
+    DRIVER_LOCK
+    scbq_insert_tail(&p->waiting_scbs, scb);
+    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+    {
+      aic7xxx_run_waiting_queues(p);
+    }
+    DRIVER_UNLOCK
+  }
+  return (0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_bus_device_reset
+ *
+ * Description:
+ *   Abort or reset the current SCSI command(s).  If the scb has not
+ *   previously been aborted, then we attempt to send a BUS_DEVICE_RESET
+ *   message to the target.  If the scb has previously been unsuccessfully
+ *   aborted, then we will reset the channel and have all devices renegotiate.
+ *   Returns an enumerated type that indicates the status of the operation.
+ *-F*************************************************************************/
+static int
+aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+{
+  struct aic7xxx_scb   *scb;
+  struct aic7xxx_hwscb *hscb;
+  int result = -1;
+  int channel;
+  unsigned char saved_scbptr, lastphase;
+  unsigned char hscb_index;
+  int disconnected;
+
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  hscb = scb->hscb;
+
+  lastphase = aic_inb(p, LASTPHASE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+  {
+    printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
+         p->host_no, CTL_OF_SCB(scb), scb->flags);
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        printk("Data-Out phase\n");
+        break;
+      case P_DATAIN:
+        printk("Data-In phase\n");
+        break;
+      case P_COMMAND:
+        printk("Command phase\n");
+        break;
+      case P_MESGOUT:
+        printk("Message-Out phase\n");
+        break;
+      case P_STATUS:
+        printk("Status phase\n");
+        break;
+      case P_MESGIN:
+        printk("Message-In phase\n");
+        break;
+      default:
+      /*
+       * We're not in a valid phase, so assume we're idle.
+       */
+        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
+        break;
+    }
+    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+         aic_inb(p, SCSISIGI),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+  }
+
+  channel = cmd->channel;
+
+    /*
+     * Send a Device Reset Message:
+     * The target that is holding up the bus may not be the same as
+     * the one that triggered this timeout (different commands have
+     * different timeout lengths).  Our strategy here is to queue an
+     * abort message to the timed out target if it is disconnected.
+     * Otherwise, if we have an active target we stuff the message buffer
+     * with an abort message and assert ATN in the hopes that the target
+     * will let go of the bus and go to the mesgout phase.  If this
+     * fails, we'll get another timeout a few seconds later which will
+     * attempt a bus reset.
+     */
+  saved_scbptr = aic_inb(p, SCBPTR);
+  disconnected = FALSE;
+
+  if (lastphase != P_BUSFREE)
+  {
+    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
+    {
+      printk(WARN_LEAD "Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no,
+            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
+      return(SCSI_RESET_ERROR);
+    }
+    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
+    { 
+      if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
+      {
+        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+          printk(INFO_LEAD "Device reset message in "
+                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        /* Send the abort message to the active SCB. */
+        aic_outb(p, HOST_MSG, MSG_OUT);
+        aic_outb(p, lastphase | ATNO, SCSISIGO);
+        return(SCSI_RESET_PENDING);
+      }
+      else
+      {
+        /* We want to send out the message, but it could screw an already */
+        /* in place and being used message.  Instead, we return an error  */
+        /* to try and start the bus reset phase since this command is     */
+        /* probably hung (aborts failed, and now reset is failing).  We   */
+        /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
+        /* any more on this device, but instead will escalate to a bus or */
+        /* host reset (additionally, we won't try to abort any more).     */
+        printk(WARN_LEAD "Device reset, Message buffer "
+                "in use\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+        p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+                BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_ERROR);
+      }
+    }
+  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
+  hscb_index = aic7xxx_find_scb(p, scb);
+  if (hscb_index == SCB_LIST_NULL)
+  {
+    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
+  }
+  else
+  {
+    aic_outb(p, hscb_index, SCBPTR);
+    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
+    {
+      disconnected = TRUE;
+    }
+  }
+  if (disconnected)
+  {
+        /*
+         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+         * the rest on a reconnect.
+         */
+    scb->hscb->control |= MK_MESSAGE;
+    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+    p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
+        BUS_DEVICE_RESET_PENDING;
+    if (hscb_index != SCB_LIST_NULL)
+    {
+      unsigned char scb_control;
+
+      aic_outb(p, hscb_index, SCBPTR);
+      scb_control = aic_inb(p, SCB_CONTROL);
+      aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
+    }
+        /*
+         * Actually requeue this SCB in case we can select the
+         * device before it reconnects.  If the transaction we
+         * want to abort is not tagged, then this will be the only
+         * outstanding command and we can simply shove it on the
+         * qoutfifo and be done.  If it is tagged, then it goes right
+         * in with all the others, no problem :)  We need to add it
+         * to the qinfifo and let the sequencer know it is there.
+         * Now, the only problem left to deal with is, *IF* this
+         * command completes, in spite of the MK_MESSAGE bit in the
+         * control byte, then we need to pick that up in the interrupt
+         * routine and clean things up.  This *shouldn't* ever happen.
+         */
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Queueing device reset "
+           "command.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    scb->flags |= SCB_QUEUED_ABORT;
+    result = SCSI_RESET_PENDING;
+  }
+  else if (result == -1)
+  {
+    result = SCSI_RESET_ERROR;
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  return (result);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+{
+
+  printk("aic7xxx driver version %s/%s\n", AIC7XXX_C_VERSION,
+         UTS_RELEASE);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  printk("p->flags=0x%lx, p->chip=0x%x, p->features=0x%x, "
+         "sequencer %s paused\n",
+     p->flags, p->chip, p->features,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  pause_sequencer(p);
+  disable_irq(p->irq);
+  aic7xxx_print_card(p);
+  aic7xxx_print_scratch_ram(p);
+  spin_unlock_irq(&io_request_lock);
+  for(;;) barrier();
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+int
+aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+  struct aic7xxx_scb  *scb = NULL;
+  struct aic7xxx_host *p;
+  int    result, found=0;
+  unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+  Scsi_Cmnd *cmd_next, *cmd_prev;
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p, cmd);
+
+  DRIVER_LOCK
+
+/*
+ *  Run the isr to grab any command in the QOUTFIFO and any other misc.
+ *  assundry tasks.  This should also set up the bh handler if there is
+ *  anything to be done, but it won't run until we are done here since
+ *  we are following a straight code path without entering the scheduler
+ *  code.
+ */
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+  {
+    aic7xxx_isr(p->irq, p, (void *)NULL);
+    pause_sequencer(p);
+    aic7xxx_done_cmds_complete(p);
+  }
+
+  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+                      /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range or doesn't even match it's own*/
+                      /*  timeout serial number.                        */
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
+  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
+                        /*  has already been recycled for another command   */
+                        /*  Either way, this SCB has nothing to do with this*/
+                        /*  command and we need to deal with cmd without    */
+                        /*  touching the SCB.                               */
+                        /*  The theory here is to return a value that will  */
+                        /*  make the queued for complete command actually   */
+                        /*  finish successfully, or to indicate that we     */
+                        /*  don't have this cmd any more and the mid level  */
+                        /*  code needs to find it.                          */
+    cmd_next = p->completeq.head;
+    cmd_prev = NULL;
+    while (cmd_next != NULL) 
+    {
+      if (cmd_next == cmd) 
+      {
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "Abort called for command "
+          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        if ( cmd_prev == NULL )
+          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+        else
+          cmd_prev->host_scribble = cmd_next->host_scribble;
+        cmd_next->scsi_done(cmd_next);
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+                                         * completion */
+      }                                  
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called for already completed"
+        " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+    
+/*   At this point we know the following:
+ *     the SCB pointer is valid
+ *     the command pointer passed in to us and the scb->cmd pointer match
+ *     this then means that the command we need to abort is the same as the
+ *     command held by the scb pointer and is a valid abort request.
+ *   Now, we just have to figure out what to do from here.  Current plan is:
+ *     if we have already been here on this command, escalate to a reset
+ *     if scb is on waiting list or QINFIFO, send it back as aborted, but
+ *       we also need to be aware of the possibility that we could be using
+ *       a faked negotiation command that is holding this command up,  if
+ *       so we need to take care of that command instead, which means we
+ *       would then treat this one like it was sitting around disconnected
+ *       instead.
+ *     if scb is on WAITING_SCB list in sequencer, free scb and send back
+ *     if scb is disconnected and not completed, abort with abort message
+ *     if scb is currently running, then it may be causing the bus to hang
+ *       so we want a return value that indicates a reset would be appropriate
+ *       if the command does not finish shortly
+ *     if scb is already complete but not on completeq, we're screwed because
+ *       this can't happen (except if the command is in the QOUTFIFO, in which
+ *       case we would like it to complete successfully instead of having to
+ *       to be re-done)
+ *   All other scenarios already dealt with by previous code.
+ */
+
+  if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB aborted once already, "
+        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_SNOOZE);
+  }
+  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
+          (p->dev_flags[TARGET_INDEX(scb->cmd)] & 
+           BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "Reset/Abort pending for this "
+        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_PENDING);
+  }
+
+  found = 0;
+  p->flags |= AHC_IN_ABORT;
+  if (aic7xxx_verbose & VERBOSE_ABORT)
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+
+/*
+ *   First, let's check to see if the currently running command is our target
+ *    since if it is, the return is fairly easy and quick since we don't want
+ *    to touch the command in case it might complete, but we do want a timeout
+ *    in case it's actually hung, so we really do nothing, but tell the mid
+ *    level code to reset the timeout.
+ */
+
+  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
+  {
+   /*
+    *  Check to see if the sequencer is just sitting on this command, or
+    *   if it's actively being run.
+    */
+    result = aic_inb(p, LASTPHASE);
+    switch (result)
+    {
+      case P_DATAOUT:    /*    For any of these cases, we can assume we are */
+      case P_DATAIN:     /*    an active command and act according.  For    */
+      case P_COMMAND:    /*    anything else we are going to fall on through*/
+      case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
+      case P_MESGOUT:    /*    chances to finish and then escalate to a     */
+      case P_MESGIN:     /*    reset call                                   */
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB is currently active.  "
+                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, FALSE);
+        p->flags &= ~AHC_IN_ABORT;
+        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
+        DRIVER_UNLOCK                   /*  muck with other SCBs if this   */
+        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
+        break;                          /*  out.                           */
+      default:
+        break;
+    }
+  }
+
+  if ((found == 0) && (scb->flags & SCB_WAITINGQ))
+  {
+    int tindex = TARGET_INDEX(cmd);
+    unsigned short mask;
+
+    mask = (1 << tindex);
+
+    if (p->dtr_pending & mask)
+    {
+      if (p->dev_dtr_cmnd[tindex]->next != cmd)
+        found = 1;
+      else
+        found = 0;
+    }
+    else
+    {
+      found = 1;
+    }
+    if (found == 0)
+    {
+      /*
+       * OK..this means the command we are currently getting an abort
+       * for has an outstanding negotiation command in front of it.
+       * We don't really have a way to tie back into the negotiation
+       * commands, so we just send this back as pending, then it
+       * will get reset in 2 seconds.
+       */
+      unpause_sequencer(p, TRUE);
+      scb->flags |= SCB_ABORT;
+      DRIVER_UNLOCK
+      return(SCSI_ABORT_PENDING);
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+      printk(INFO_LEAD "SCB found on waiting list and "
+          "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+    scbq_remove(&p->waiting_scbs, scb);
+    scbq_remove(&p->delayed_scbs[tindex], scb);
+    p->dev_active_cmds[tindex]++;
+    p->activescbs++;
+    scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+    found = 1;
+  }
+
+/*
+ *  We just checked the waiting_q, now for the QINFIFO
+ */
+  if ( found == 0 )
+  {
+    if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
+                     cmd->channel,
+                     cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                     FALSE, NULL)) != 0) &&
+                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "SCB found in QINFIFO and "
+        "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+  }
+
+/*
+ *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
+ */
+
+  if ( found == 0 )
+  {
+    unsigned char scb_next_ptr;
+    prev_hscbptr = SCB_LIST_NULL;
+    saved_hscbptr = aic_inb(p, SCBPTR);
+    next_hscbptr = aic_inb(p, WAITING_SCBH);
+    while ( next_hscbptr != SCB_LIST_NULL )
+    {
+      aic_outb(p,  next_hscbptr, SCBPTR );
+      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
+      {
+        found = 1;
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB found on hardware waiting"
+            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+        if ( prev_hscbptr == SCB_LIST_NULL )
+        {
+            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
+            /* stop the selection since we just
+             * grabbed the scb out from under the
+             * card
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
+        }
+        else
+        {
+            scb_next_ptr = aic_inb(p, SCB_NEXT);
+            aic_outb(p, prev_hscbptr, SCBPTR);
+            aic_outb(p, scb_next_ptr, SCB_NEXT);
+            aic_outb(p, next_hscbptr, SCBPTR);
+        }
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        aic7xxx_add_curscb_to_free_list(p);
+        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+        break;
+      }
+      prev_hscbptr = next_hscbptr;
+      next_hscbptr = aic_inb(p, SCB_NEXT);
+    }
+    aic_outb(p,  saved_hscbptr, SCBPTR );
+  }
+        
+/*
+ *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
+ *  OK...the sequencer's paused, interrupts are off, and we haven't found the
+ *  command anyplace where it could be easily aborted.  Time for the hard
+ *  work.  We also know the command is valid.  This essentially means the
+ *  command is disconnected, or connected but not into any phases yet, which
+ *  we know due to the tests we ran earlier on the current active scb phase.
+ *  At this point we can queue the abort tag and go on with life.
+ */
+
+  if ( found == 0 )
+  {
+    p->flags |= AHC_ABORT_PENDING;
+    scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+    scb->hscb->control |= MK_MESSAGE;
+    result=aic7xxx_find_scb(p, scb);
+    if ( result != SCB_LIST_NULL ) 
+    {
+      saved_hscbptr = aic_inb(p, SCBPTR);
+      aic_outb(p, result, SCBPTR);
+      tmp_char = aic_inb(p, SCB_CONTROL);
+      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
+      aic_outb(p, saved_hscbptr, SCBPTR);
+    }
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
+        " SCB.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+  }
+  if (found)
+  {
+    aic7xxx_run_done_queue(p, TRUE);
+    aic7xxx_run_waiting_queues(p);
+  }
+  p->flags &= ~AHC_IN_ABORT;
+  unpause_sequencer(p, FALSE);
+  DRIVER_UNLOCK
+
+/*
+ *  On the return value.  If we found the command and aborted it, then we know
+ *  it's already sent back and there is no reason for a further timeout, so
+ *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
+ *  there hasn't been a bus hang or something that might keep the abort from
+ *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time this
+ *  is passed back, the timeout on the command gets extended, the second time
+ *  we pass this back, the mid level SCSI code calls our reset function, which
+ *  would shake loose a hung bus.
+ */
+  if ( found != 0 )
+    return(SCSI_ABORT_SUCCESS);
+  else
+    return(SCSI_ABORT_PENDING); 
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset
+ *
+ * Description:
+ *   Resetting the bus always succeeds - is has to, otherwise the
+ *   kernel will panic! Try a surgical technique - sending a BUS
+ *   DEVICE RESET message - on the offending target before pulling
+ *   the SCSI bus reset line.
+ *-F*************************************************************************/
+int
+aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
+{
+  struct aic7xxx_scb *scb = NULL;
+  struct aic7xxx_host *p;
+  int    tindex;
+  int    result = -1;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+#define DEVICE_RESET 0x01
+#define BUS_RESET    0x02
+#define HOST_RESET   0x04
+#define FAIL         0x08
+#define RESET_DELAY  0x10
+  int        action;
+  Scsi_Cmnd *cmd_prev, *cmd_next;
+
+
+  if ( cmd == NULL )
+  {
+    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
+      "pointer, failing.\n");
+    return(SCSI_RESET_SNOOZE);
+  }
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  tindex = TARGET_INDEX(cmd);
+
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p, cmd);
+
+  DRIVER_LOCK
+
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+  {
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
+    aic7xxx_done_cmds_complete(p);
+  }
+
+  if (scb == NULL)
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+    {
+      action = HOST_RESET;
+    }
+    else
+    {
+      action = BUS_RESET;
+    }
+  }
+  else if (scb->cmd != cmd) 
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+    printk(INFO_LEAD "Reset called with recycled SCB "
+        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    cmd_prev = NULL;
+    cmd_next = p->completeq.head;
+    while ( cmd_next != NULL )
+    {
+      if (cmd_next == cmd)
+      {
+        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+          printk(INFO_LEAD "Reset, found cmd on completeq"
+          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        unpause_sequencer(p, FALSE);
+        DRIVER_UNLOCK
+        return(SCSI_RESET_NOT_RUNNING);
+      }
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
+    {
+      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "Reset, cmd not found,"
+          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_NOT_RUNNING);
+    }
+    else
+    {
+      if (aic7xxx_verbose & VERBOSE_RESET_MID)
+        printk(INFO_LEAD "Reset called, no scb, "
+          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
+      scb = NULL;
+      action = HOST_RESET;
+    }
+  }
+  else
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called, scb %d, flags "
+        "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
+    {
+      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
+          CTL_OF_SCB(scb));
+      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
+        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
+          CTL_OF_SCB(scb));
+      aic7xxx_handle_command_completion_intr(p);
+      aic7xxx_done_cmds_complete(p);
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_SUCCESS);
+    }
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+    {
+      action = HOST_RESET;
+    }
+    else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
+    {
+      action = BUS_RESET;
+    }
+    else 
+    {
+      action = DEVICE_RESET;
+    }
+  }
+  if ( (action & DEVICE_RESET) && 
+        (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Bus device reset already sent to "
+        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) &&
+       (scb->flags & SCB_QUEUED_ABORT) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Have already attempted to reach "
+        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "message, will escalate to bus "
+        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
+    }
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) && 
+       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+     printk(INFO_LEAD "Bus device reset stupid when "
+        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) )
+  {
+    action = HOST_RESET;
+  }
+  if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
+       !(action & (HOST_RESET | BUS_RESET)))
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    {
+      printk(INFO_LEAD "Reset called too soon after last "
+        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
+      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
+        CTL_OF_CMD(cmd));
+    }
+    action = BUS_RESET;
+  }
+  if ( (p->flags & AHC_RESET_DELAY) &&
+       (action & (HOST_RESET | BUS_RESET)) )
+  {
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Reset called too soon after "
+        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = RESET_DELAY;
+  }
+/*
+ *  By this point, we want to already know what we are going to do and
+ *  only have the following code implement our course of action.
+ */
+  switch (action)
+  {
+    case RESET_DELAY:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_PENDING);
+      break;
+    case FAIL:
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(SCSI_RESET_ERROR);
+      break;
+    case DEVICE_RESET:
+      p->flags |= AHC_IN_RESET;
+      result = aic7xxx_bus_device_reset(p, cmd);
+      aic7xxx_run_done_queue(p, TRUE);
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      p->flags &= ~AHC_IN_RESET;
+      DRIVER_UNLOCK
+      return(result);
+      break;
+    case BUS_RESET:
+    case HOST_RESET:
+    default:
+      p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
+      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+      p->dev_timer_active |= (0x01 << p->scsi_id);
+      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+            time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
+      {
+        mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+      }
+      aic7xxx_reset_channel(p, cmd->channel, TRUE);
+      if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
+      {
+        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
+        restart_sequencer(p);
+      }
+      if (action != HOST_RESET)
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+      else
+      {
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
+          SIMODE1);
+        aic7xxx_clear_intstat(p);
+        p->flags &= ~AHC_HANDLING_REQINITS;
+        p->msg_type = MSG_TYPE_NONE;
+        p->msg_index = 0;
+        p->msg_len = 0;
+      }
+      aic7xxx_run_done_queue(p, TRUE);
+      /*
+       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
+       * in need of being re-started, so send it on through to aic7xxx_queue
+       * and let it set until the delay is over.  This keeps it from dying
+       * entirely and avoids getting a bogus dead command back through the
+       * mid-level code due to too many retries.
+       */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+      if ( flags & SCSI_RESET_SYNCHRONOUS )
+      {
+        cmd->result = DID_BUS_BUSY << 16;
+        cmd->done(cmd);
+      }
+#endif
+      p->flags &= ~AHC_IN_RESET;
+      /*
+       * We can't rely on run_waiting_queues to unpause the sequencer for
+       * PCI based controllers since we use AAP.  NOTE: this also sets
+       * the timer for the one command we might have queued in the case
+       * of a synch reset.
+       */
+      aic7xxx_run_waiting_queues(p);
+      unpause_sequencer(p, FALSE);
+      DRIVER_UNLOCK
+      return(result);
+      break;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_biosparam
+ *
+ * Description:
+ *   Return the disk geometry for the given SCSI device.
+ *-F*************************************************************************/
+int
+aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
+{
+  int heads, sectors, cylinders, ret;
+  struct aic7xxx_host *p;
+  struct buffer_head *bh;
+
+  p = (struct aic7xxx_host *) disk->device->host->hostdata;
+  bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
+
+  if ( bh )
+  {
+    ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+    brelse(bh);
+    if ( ret != -1 )
+      return(ret);
+  }
+  
+  heads = 64;
+  sectors = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
+  {
+    heads = 255;
+    sectors = 63;
+    cylinders = disk->capacity / (heads * sectors);
+  }
+
+  geom[0] = heads;
+  geom[1] = sectors;
+  geom[2] = cylinders;
+
+  return (0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_release
+ *
+ * Description:
+ *   Free the passed in Scsi_Host memory structures prior to unloading the
+ *   module.
+ *-F*************************************************************************/
+int
+aic7xxx_release(struct Scsi_Host *host)
+{
+  struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  struct aic7xxx_host *next, *prev;
+
+  if(p->irq)
+    free_irq(p->irq, p);
+  if(p->base)
+    release_region(p->base, MAXREG - MINREG);
+#ifdef MMAPIO
+  if(p->maddr)
+  {
+    iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK));
+  }
+#endif /* MMAPIO */
+  prev = NULL;
+  next = first_aic7xxx;
+  while(next != NULL)
+  {
+    if(next == p)
+    {
+      if(prev == NULL)
+        first_aic7xxx = next->next;
+      else
+        prev->next = next->next;
+    }
+    else
+    {
+      prev = next;
+    }
+    next = next->next;
+  }
+  aic7xxx_free(p);
+  return(0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_card
+ *
+ * Description:
+ *   Print out all of the control registers on the card
+ *
+ *   NOTE: This function is not yet safe for use on the VLB and EISA
+ *   controllers, so it isn't used on those controllers at all.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_card(struct aic7xxx_host *p)
+{
+  int i, j, k, chip;
+  static struct register_ranges {
+    int num_ranges;
+    int range_val[32];
+  } cards_ds[] = {
+    { 0, {0,} }, /* none */
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} },
+    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/
+          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/
+          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
+          0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a,
+          0x9f, 0x9f, 0xe0, 0xf1} },
+    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
+          0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
+  };
+  chip = p->chip & AHC_CHIPID_MASK;
+  printk("%s at ",
+         board_names[p->board_name_index]);
+  switch(p->chip & ~AHC_CHIPID_MASK)
+  {
+    case AHC_VL:
+      printk("VLB Slot %d.\n", p->pci_device_fn);
+      break;
+    case AHC_EISA:
+      printk("EISA Slot %d.\n", p->pci_device_fn);
+      break;
+    case AHC_PCI:
+    default:
+      printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
+             PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+
+  /*
+   * the registers on the card....
+   */
+  printk("Card Dump:\n");
+  k = 0;
+  for(i=0; i<cards_ds[chip].num_ranges; i++)
+  {
+    for(j  = cards_ds[chip].range_val[ i * 2 ];
+        j <= cards_ds[chip].range_val[ i * 2 + 1 ] ;
+        j++)
+    {
+      printk("%02x:%02x ", j, aic_inb(p, j));
+      if(++k == 13)
+      {
+        printk("\n");
+        k=0;
+      }
+    }
+  }
+  if(k != 0)
+    printk("\n");
+
+  /*
+   * If this was an Ultra2 controller, then we just hosed the card in terms
+   * of the QUEUE REGS.  This function is only called at init time or by
+   * the panic_abort function, so it's safe to assume a generic init time
+   * setting here
+   */
+
+  if(p->features & AHC_QUEUE_REGS)
+  {
+    aic_outb(p, 0, SDSCB_QOFF);
+    aic_outb(p, 0, SNSCB_QOFF);
+    aic_outb(p, 0, HNSCB_QOFF);
+  }
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_scratch_ram
+ *
+ * Description:
+ *   Print out the scratch RAM values on the card.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_scratch_ram(struct aic7xxx_host *p)
+{
+  int i, k;
+
+  k = 0;
+  printk("Scratch RAM:\n");
+  for(i = SRAM_BASE; i < SEQCTL; i++)
+  {
+    printk("%02x:%02x ", i, aic_inb(p, i));
+    if(++k == 13)
+    {
+      printk("\n");
+      k=0;
+    }
+  }
+  if (p->features & AHC_MORE_SRAM)
+  {
+    for(i = TARG_OFFSET; i < 0x80; i++)
+    {
+      printk("%02x:%02x ", i, aic_inb(p, i));
+      if(++k == 13)
+      {
+        printk("\n");
+        k=0;
+      }
+    }
+  }
+  printk("\n");
+}
+
+
+#include "aic7xxx_old/aic7xxx_proc.c"
+
+/* Eventually this will go into an include file, but this will be later */
+static Scsi_Host_Template driver_template = AIC7XXX;
+
+#include "scsi_module.c"
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's 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: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.4.2/linux/drivers/scsi/aic7xxx_proc.c	Wed Jun 21 17:25:03 2000
+++ linux/drivers/scsi/aic7xxx_proc.c	Wed Dec 31 16:00:00 1969
@@ -1,413 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver proc support for Linux.
- *
- * Copyright (c) 1995, 1996 Dean W. Gehnert
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * ----------------------------------------------------------------
- *  o Modified from the EATA-DMA /proc support.
- *  o Additional support for device block statistics provided by
- *    Matthew Jacob.
- *  o Correction of overflow by Heinz Mauelshagen
- *  o Adittional corrections by Doug Ledford
- *
- *  Dean W. Gehnert, deang@teleport.com, 05/01/96
- *
- *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
- *-M*************************************************************************/
-
-#include <linux/config.h>
-
-#define	BLS	(&aic7xxx_buffer[size])
-#define HDRB \
-"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
-
-#ifdef PROC_DEBUG
-extern int vsprintf(char *, const char *, va_list);
-
-static void
-proc_debug(const char *fmt, ...)
-{
-  va_list ap;
-  char buf[256];
-
-  va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
-  printk(buf);
-  va_end(ap);
-}
-#else /* PROC_DEBUG */
-#  define proc_debug(fmt, args...)
-#endif /* PROC_DEBUG */
-
-static int aic7xxx_buffer_size = 0;
-static char *aic7xxx_buffer = NULL;
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_set_info
- *
- * Description:
- *   Set parameters for the driver from the /proc filesystem.
- *-F*************************************************************************/
-int
-aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
-{
-  proc_debug("aic7xxx_set_info(): %s\n", buffer);
-  return (-ENOSYS);  /* Currently this is a no-op */
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_proc_info
- *
- * Description:
- *   Return information to handle /proc support for the driver.
- *-F*************************************************************************/
-int
-aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
-                    int hostno, int inout)
-{
-  struct Scsi_Host *HBAptr;
-  struct aic7xxx_host *p;
-  int    size = 0;
-  unsigned char i;
-  struct aic7xxx_xferstats *sp;
-  unsigned char target;
-
-  HBAptr = NULL;
-
-  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
-    ;
-
-  if (!p)
-  {
-    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
-    if (size > length)
-    {
-      return (size);
-    }
-    else
-    {
-      return (length);
-    }
-  }
-
-  HBAptr = p->host;
-
-  if (inout == TRUE) /* Has data been written to the file? */ 
-  {
-    return (aic7xxx_set_info(buffer, length, HBAptr));
-  }
-
-  p = (struct aic7xxx_host *) HBAptr->hostdata;
-
-  /*
-   * It takes roughly 1K of space to hold all relevant card info, not
-   * counting any proc stats, so we start out with a 1.5k buffer size and
-   * if proc_stats is defined, then we sweep the stats structure to see
-   * how many drives we will be printing out for and add 384 bytes per
-   * device with active stats.
-   *
-   * Hmmmm...that 1.5k seems to keep growing as items get added so they
-   * can be easily viewed for debugging purposes.  So, we bumped that
-   * 1.5k to 4k so we can quit having to bump it all the time.
-   */
-
-  size = 4096;
-  for (target = 0; target < MAX_TARGETS; target++)
-  {
-    if (p->dev_flags[target] & DEVICE_PRESENT)
-#ifdef AIC7XXX_PROC_STATS
-      size += 512;
-#else
-      size += 256;
-#endif
-  }
-  if (aic7xxx_buffer_size != size)
-  {
-    if (aic7xxx_buffer != NULL) 
-    {
-      kfree(aic7xxx_buffer);
-      aic7xxx_buffer_size = 0;
-    }
-    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
-  }
-  if (aic7xxx_buffer == NULL)
-  {
-    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
-        __LINE__);
-    return size;
-  }
-  aic7xxx_buffer_size = size;
-
-  size = 0;
-  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
-  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
-  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
-  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
-#else
-  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
-#endif
-#ifdef AIC7XXX_PROC_STATS
-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
-#endif
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Adapter Configuration:\n");
-  size += sprintf(BLS, "           SCSI Adapter: %s\n",
-      board_names[p->board_name_index]);
-  if (p->flags & AHC_TWIN)
-    size += sprintf(BLS, "                         Twin Channel Controller ");
-  else
-  {
-    char *channel = "";
-    char *ultra = "";
-    char *wide = "Narrow ";
-    if (p->flags & AHC_MULTI_CHANNEL)
-    {
-      channel = " Channel A";
-      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
-        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
-    }
-    if (p->features & AHC_WIDE)
-      wide = "Wide ";
-    if (p->features & AHC_ULTRA3)
-    {
-      switch(p->chip & AHC_CHIPID_MASK)
-      {
-        case AHC_AIC7892:
-        case AHC_AIC7899:
-          ultra = "Ultra-160/m LVD/SE ";
-          break;
-        default:
-          ultra = "Ultra-3 LVD/SE ";
-          break;
-      }
-    }
-    else if (p->features & AHC_ULTRA2)
-      ultra = "Ultra-2 LVD/SE ";
-    else if (p->features & AHC_ULTRA)
-      ultra = "Ultra ";
-    size += sprintf(BLS, "                           %s%sController%s ",
-      ultra, wide, channel);
-  }
-  switch(p->chip & ~AHC_CHIPID_MASK)
-  {
-    case AHC_VL:
-      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
-      break;
-    case AHC_EISA:
-      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
-      break;
-    default:
-      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
-        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
-      break;
-  }
-  if( !(p->maddr) )
-  {
-    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
-  }
-  else
-  {
-    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
-  }
-  if( (p->chip & (AHC_VL | AHC_EISA)) )
-  {
-    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
-  }
-  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
-          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
-         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
-           "SEEPROM not found, using leftover BIOS values.") );
-  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
-          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
-  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
-  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
-            p->activescbs, p->max_activescbs);
-  size += sprintf(BLS, "                         Allocated %d, HW %d, "
-            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
-            p->scb_data->maxscbs);
-  if (p->flags & AHC_EXTERNAL_SRAM)
-    size += sprintf(BLS, "                         Using External SCB SRAM\n");
-  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
-  if (p->chip & AHC_EISA)
-  {
-    size += sprintf(BLS, " %s\n",
-        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
-  }
-  else
-  {
-    size += sprintf(BLS, "\n");
-  }
-  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
-            p->bios_control);
-  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
-            p->adapter_control);
-  size += sprintf(BLS, "   Extended Translation: %sabled\n",
-      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
-  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
-  {
-    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
-  }
-  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
-  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
-  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
-                       "instance %d:\n", p->instance);
-  size += sprintf(BLS, "      {");
-  for(i=0; i < (MAX_TARGETS - 1); i++)
-    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
-  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
-  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
-                       "instance %d:\n", p->instance);
-  size += sprintf(BLS, "      {");
-  for(i=0; i < (MAX_TARGETS - 1); i++)
-    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
-  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
-
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Statistics:\n\n");
-  for (target = 0; target < MAX_TARGETS; target++)
-  {
-    sp = &p->stats[target];
-    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
-    {
-      continue;
-    }
-    if (p->features & AHC_TWIN)
-    {
-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-          p->host_no, (target >> 3), (target & 0x7), 0);
-    }
-    else
-    {
-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-          p->host_no, 0, target, 0);
-    }
-    size += sprintf(BLS, "  Device using %s/%s",
-          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
-          "Wide" : "Narrow",
-          (p->transinfo[target].cur_offset != 0) ?
-          "Sync transfers at " : "Async transfers.\n" );
-    if (p->transinfo[target].cur_offset != 0)
-    {
-      struct aic7xxx_syncrate *sync_rate;
-      unsigned char options = p->transinfo[target].cur_options;
-      int period = p->transinfo[target].cur_period;
-      int rate = (p->transinfo[target].cur_width ==
-                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
-
-      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
-      if (sync_rate != NULL)
-      {
-        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
-                        sync_rate->rate[rate],
-                        p->transinfo[target].cur_offset );
-      }
-      else
-      {
-        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
-                        p->transinfo[target].cur_offset );
-      }
-    }
-    size += sprintf(BLS, "  Transinfo settings: ");
-    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
-                    p->transinfo[target].cur_period,
-                    p->transinfo[target].cur_offset,
-                    p->transinfo[target].cur_width,
-                    p->transinfo[target].cur_options);
-    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
-                    p->transinfo[target].goal_period,
-                    p->transinfo[target].goal_offset,
-                    p->transinfo[target].goal_width,
-                    p->transinfo[target].goal_options);
-    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
-                    p->transinfo[target].user_period,
-                    p->transinfo[target].user_offset,
-                    p->transinfo[target].user_width,
-                    p->transinfo[target].user_options);
-#ifdef AIC7XXX_PROC_STATS
-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
-    size += sprintf(BLS, "%s\n", HDRB);
-    size += sprintf(BLS, "   Reads:");
-    for (i = 0; i < NUMBER(sp->r_bins); i++)
-    {
-      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
-    }
-    size += sprintf(BLS, "\n");
-    size += sprintf(BLS, "  Writes:");
-    for (i = 0; i < NUMBER(sp->w_bins); i++)
-    {
-      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
-    }
-    size += sprintf(BLS, "\n");
-#else
-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
-#endif /* AIC7XXX_PROC_STATS */
-    size += sprintf(BLS, "\n\n");
-  }
-
-  if (size >= aic7xxx_buffer_size)
-  {
-    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
-  }
-
-  if (offset > size - 1)
-  {
-    kfree(aic7xxx_buffer);
-    aic7xxx_buffer = NULL;
-    aic7xxx_buffer_size = length = 0;
-    *start = NULL;
-  }
-  else
-  {
-    *start = buffer;
-    length = MIN(length, size - offset);
-    memcpy(buffer, &aic7xxx_buffer[offset], length);
-  }
-
-  return (length);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's 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: 2
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -2
- * c-argdecl-indent: 2
- * c-label-offset: -2
- * c-continued-statement-offset: 2
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
--- v2.4.2/linux/drivers/scsi/aic7xxx_reg.h	Thu Feb 10 19:00:35 2000
+++ linux/drivers/scsi/aic7xxx_reg.h	Wed Dec 31 16:00:00 1969
@@ -1,629 +0,0 @@
-/*
-  * DO NOT EDIT - This file is automatically generated.
-  */
-
-#define	SCSISEQ         		0x00
-#define		TEMODE          	0x80
-#define		ENSELO          	0x40
-#define		ENSELI          	0x20
-#define		ENRSELI         	0x10
-#define		ENAUTOATNO      	0x08
-#define		ENAUTOATNI      	0x04
-#define		ENAUTOATNP      	0x02
-#define		SCSIRSTO        	0x01
-
-#define	SXFRCTL0        		0x01
-#define		DFON            	0x80
-#define		DFPEXP          	0x40
-#define		FAST20          	0x20
-#define		CLRSTCNT        	0x10
-#define		SPIOEN          	0x08
-#define		SCAMEN          	0x04
-#define		CLRCHN          	0x02
-
-#define	SXFRCTL1        		0x02
-#define		BITBUCKET       	0x80
-#define		SWRAPEN         	0x40
-#define		ENSPCHK         	0x20
-#define		STIMESEL        	0x18
-#define		ENSTIMER        	0x04
-#define		ACTNEGEN        	0x02
-#define		STPWEN          	0x01
-
-#define	SCSISIGO        		0x03
-#define		CDO             	0x80
-#define		IOO             	0x40
-#define		MSGO            	0x20
-#define		ATNO            	0x10
-#define		SELO            	0x08
-#define		BSYO            	0x04
-#define		REQO            	0x02
-#define		ACKO            	0x01
-
-#define	SCSISIGI        		0x03
-#define		ATNI            	0x10
-#define		SELI            	0x08
-#define		BSYI            	0x04
-#define		REQI            	0x02
-#define		ACKI            	0x01
-
-#define	SCSIRATE        		0x04
-#define		WIDEXFER        	0x80
-#define		SXFR_ULTRA2     	0x7f
-#define		SXFR            	0x70
-#define		SOFS            	0x0f
-
-#define	SCSIID          		0x05
-#define	SCSIOFFSET      		0x05
-#define		SOFS_ULTRA2     	0x7f
-
-#define	SCSIDATL        		0x06
-
-#define	SCSIDATH        		0x07
-
-#define	STCNT           		0x08
-
-#define	OPTIONMODE      		0x08
-#define		AUTORATEEN      	0x80
-#define		AUTOACKEN       	0x40
-#define		ATNMGMNTEN      	0x20
-#define		BUSFREEREV      	0x10
-#define		EXPPHASEDIS     	0x08
-#define		SCSIDATL_IMGEN  	0x04
-#define		AUTO_MSGOUT_DE  	0x02
-#define		DIS_MSGIN_DUALEDGE	0x01
-
-#define	CLRSINT0        		0x0b
-#define		CLRSELDO        	0x40
-#define		CLRSELDI        	0x20
-#define		CLRSELINGO      	0x10
-#define		CLRSWRAP        	0x08
-#define		CLRSPIORDY      	0x02
-
-#define	SSTAT0          		0x0b
-#define		TARGET          	0x80
-#define		SELDO           	0x40
-#define		SELDI           	0x20
-#define		SELINGO         	0x10
-#define		IOERR           	0x08
-#define		SWRAP           	0x08
-#define		SDONE           	0x04
-#define		SPIORDY         	0x02
-#define		DMADONE         	0x01
-
-#define	CLRSINT1        		0x0c
-#define		CLRSELTIMEO     	0x80
-#define		CLRATNO         	0x40
-#define		CLRSCSIRSTI     	0x20
-#define		CLRBUSFREE      	0x08
-#define		CLRSCSIPERR     	0x04
-#define		CLRPHASECHG     	0x02
-#define		CLRREQINIT      	0x01
-
-#define	SSTAT1          		0x0c
-#define		SELTO           	0x80
-#define		ATNTARG         	0x40
-#define		SCSIRSTI        	0x20
-#define		PHASEMIS        	0x10
-#define		BUSFREE         	0x08
-#define		SCSIPERR        	0x04
-#define		PHASECHG        	0x02
-#define		REQINIT         	0x01
-
-#define	SSTAT2          		0x0d
-#define		OVERRUN         	0x80
-#define		SHVALID         	0x40
-#define		WIDE_RES        	0x20
-#define		SFCNT           	0x1f
-#define		EXP_ACTIVE      	0x10
-#define		CRCVALERR       	0x08
-#define		CRCENDERR       	0x04
-#define		CRCREQERR       	0x02
-#define		DUAL_EDGE_ERROR 	0x01
-
-#define	SSTAT3          		0x0e
-#define		SCSICNT         	0xf0
-#define		OFFCNT          	0x0f
-
-#define	SCSIID_ULTRA2   		0x0f
-#define		OID             	0x0f
-
-#define	SIMODE0         		0x10
-#define		ENSELDO         	0x40
-#define		ENSELDI         	0x20
-#define		ENSELINGO       	0x10
-#define		ENIOERR         	0x08
-#define		ENSWRAP         	0x08
-#define		ENSDONE         	0x04
-#define		ENSPIORDY       	0x02
-#define		ENDMADONE       	0x01
-
-#define	SIMODE1         		0x11
-#define		ENSELTIMO       	0x80
-#define		ENATNTARG       	0x40
-#define		ENSCSIRST       	0x20
-#define		ENPHASEMIS      	0x10
-#define		ENBUSFREE       	0x08
-#define		ENSCSIPERR      	0x04
-#define		ENPHASECHG      	0x02
-#define		ENREQINIT       	0x01
-
-#define	SCSIBUSL        		0x12
-
-#define	SCSIBUSH        		0x13
-
-#define	SHADDR          		0x14
-
-#define	SELTIMER        		0x18
-#define		STAGE6          	0x20
-#define		STAGE5          	0x10
-#define		STAGE4          	0x08
-#define		STAGE3          	0x04
-#define		STAGE2          	0x02
-#define		STAGE1          	0x01
-
-#define	SELID           		0x19
-#define		SELID_MASK      	0xf0
-#define		ONEBIT          	0x08
-
-#define	SPIOCAP         		0x1b
-#define		SOFT1           	0x80
-#define		SOFT0           	0x40
-#define		SOFTCMDEN       	0x20
-#define		HAS_BRDCTL      	0x10
-#define		SEEPROM         	0x08
-#define		EEPROM          	0x04
-#define		ROM             	0x02
-#define		SSPIOCPS        	0x01
-
-#define	BRDCTL          		0x1d
-#define		BRDDAT7         	0x80
-#define		BRDDAT6         	0x40
-#define		BRDDAT5         	0x20
-#define		BRDDAT4         	0x10
-#define		BRDSTB          	0x10
-#define		BRDCS           	0x08
-#define		BRDDAT3         	0x08
-#define		BRDDAT2         	0x04
-#define		BRDRW           	0x04
-#define		BRDRW_ULTRA2    	0x02
-#define		BRDCTL1         	0x02
-#define		BRDCTL0         	0x01
-#define		BRDSTB_ULTRA2   	0x01
-
-#define	SEECTL          		0x1e
-#define		EXTARBACK       	0x80
-#define		EXTARBREQ       	0x40
-#define		SEEMS           	0x20
-#define		SEERDY          	0x10
-#define		SEECS           	0x08
-#define		SEECK           	0x04
-#define		SEEDO           	0x02
-#define		SEEDI           	0x01
-
-#define	SBLKCTL         		0x1f
-#define		DIAGLEDEN       	0x80
-#define		DIAGLEDON       	0x40
-#define		AUTOFLUSHDIS    	0x20
-#define		ENAB40          	0x08
-#define		ENAB20          	0x04
-#define		SELWIDE         	0x02
-#define		XCVR            	0x01
-
-#define	SRAM_BASE       		0x20
-
-#define	TARG_SCSIRATE   		0x20
-
-#define	ULTRA_ENB       		0x30
-
-#define	DISC_DSB        		0x32
-
-#define	MSG_OUT         		0x34
-
-#define	DMAPARAMS       		0x35
-#define		PRELOADEN       	0x80
-#define		WIDEODD         	0x40
-#define		SCSIEN          	0x20
-#define		SDMAENACK       	0x10
-#define		SDMAEN          	0x10
-#define		HDMAEN          	0x08
-#define		HDMAENACK       	0x08
-#define		DIRECTION       	0x04
-#define		FIFOFLUSH       	0x02
-#define		FIFORESET       	0x01
-
-#define	SEQ_FLAGS       		0x36
-#define		IDENTIFY_SEEN   	0x80
-#define		SCBPTR_VALID    	0x20
-#define		DPHASE          	0x10
-#define		AMTARGET        	0x08
-#define		WIDE_BUS        	0x02
-#define		TWIN_BUS        	0x01
-
-#define	SAVED_TCL       		0x37
-
-#define	SG_COUNT        		0x38
-
-#define	SG_NEXT         		0x39
-
-#define	LASTPHASE       		0x3d
-#define		P_MESGIN        	0xe0
-#define		PHASE_MASK      	0xe0
-#define		P_STATUS        	0xc0
-#define		P_MESGOUT       	0xa0
-#define		P_COMMAND       	0x80
-#define		CDI             	0x80
-#define		IOI             	0x40
-#define		P_DATAIN        	0x40
-#define		MSGI            	0x20
-#define		P_BUSFREE       	0x01
-#define		P_DATAOUT       	0x00
-
-#define	WAITING_SCBH    		0x3e
-
-#define	DISCONNECTED_SCBH		0x3f
-
-#define	FREE_SCBH       		0x40
-
-#define	HSCB_ADDR       		0x41
-
-#define	SCBID_ADDR      		0x45
-
-#define	TMODE_CMDADDR   		0x49
-
-#define	KERNEL_QINPOS   		0x4d
-
-#define	QINPOS          		0x4e
-
-#define	QOUTPOS         		0x4f
-
-#define	TMODE_CMDADDR_NEXT		0x50
-
-#define	ARG_1           		0x51
-#define	RETURN_1        		0x51
-#define		SEND_MSG        	0x80
-#define		SEND_SENSE      	0x40
-#define		SEND_REJ        	0x20
-#define		MSGOUT_PHASEMIS 	0x10
-
-#define	ARG_2           		0x52
-#define	RETURN_2        		0x52
-
-#define	LAST_MSG        		0x53
-
-#define	PREFETCH_CNT    		0x54
-
-#define	SCSICONF        		0x5a
-#define		TERM_ENB        	0x80
-#define		RESET_SCSI      	0x40
-#define		HWSCSIID        	0x0f
-#define		HSCSIID         	0x07
-
-#define	HOSTCONF        		0x5d
-
-#define	HA_274_BIOSCTRL 		0x5f
-#define		BIOSMODE        	0x30
-#define		BIOSDISABLED    	0x30
-#define		CHANNEL_B_PRIMARY	0x08
-
-#define	SEQCTL          		0x60
-#define		PERRORDIS       	0x80
-#define		PAUSEDIS        	0x40
-#define		FAILDIS         	0x20
-#define		FASTMODE        	0x10
-#define		BRKADRINTEN     	0x08
-#define		STEP            	0x04
-#define		SEQRESET        	0x02
-#define		LOADRAM         	0x01
-
-#define	SEQRAM          		0x61
-
-#define	SEQADDR0        		0x62
-
-#define	SEQADDR1        		0x63
-#define		SEQADDR1_MASK   	0x01
-
-#define	ACCUM           		0x64
-
-#define	SINDEX          		0x65
-
-#define	DINDEX          		0x66
-
-#define	ALLONES         		0x69
-
-#define	ALLZEROS        		0x6a
-
-#define	NONE            		0x6a
-
-#define	FLAGS           		0x6b
-#define		ZERO            	0x02
-#define		CARRY           	0x01
-
-#define	SINDIR          		0x6c
-
-#define	DINDIR          		0x6d
-
-#define	FUNCTION1       		0x6e
-
-#define	STACK           		0x6f
-
-#define	TARG_OFFSET     		0x70
-
-#define	BCTL            		0x84
-#define		ACE             	0x08
-#define		ENABLE          	0x01
-
-#define	DSCOMMAND0      		0x84
-#define		INTSCBRAMSEL    	0x08
-#define		RAMPS           	0x04
-#define		USCBSIZE32      	0x02
-#define		CIOPARCKEN      	0x01
-
-#define	DSCOMMAND       		0x84
-#define		CACHETHEN       	0x80
-#define		DPARCKEN        	0x40
-#define		MPARCKEN        	0x20
-#define		EXTREQLCK       	0x10
-
-#define	BUSTIME         		0x85
-#define		BOFF            	0xf0
-#define		BON             	0x0f
-
-#define	BUSSPD          		0x86
-#define		DFTHRSH         	0xc0
-#define		STBOFF          	0x38
-#define		STBON           	0x07
-
-#define	DSPCISTATUS     		0x86
-#define		DFTHRSH_100     	0xc0
-
-#define	HCNTRL          		0x87
-#define		POWRDN          	0x40
-#define		SWINT           	0x10
-#define		IRQMS           	0x08
-#define		PAUSE           	0x04
-#define		INTEN           	0x02
-#define		CHIPRST         	0x01
-#define		CHIPRSTACK      	0x01
-
-#define	HADDR           		0x88
-
-#define	HCNT            		0x8c
-
-#define	SCBPTR          		0x90
-
-#define	INTSTAT         		0x91
-#define		SEQINT_MASK     	0xf1
-#define		DATA_OVERRUN    	0xe1
-#define		MSGIN_PHASEMIS  	0xd1
-#define		TRACEPOINT2     	0xc1
-#define		TRACEPOINT      	0xb1
-#define		AWAITING_MSG    	0xa1
-#define		RESIDUAL        	0x81
-#define		BAD_STATUS      	0x71
-#define		REJECT_MSG      	0x61
-#define		WIDE_RESIDUE    	0x51
-#define		EXTENDED_MSG    	0x41
-#define		NO_MATCH        	0x31
-#define		NO_IDENT        	0x21
-#define		SEND_REJECT     	0x11
-#define		INT_PEND        	0x0f
-#define		BRKADRINT       	0x08
-#define		SCSIINT         	0x04
-#define		CMDCMPLT        	0x02
-#define		BAD_PHASE       	0x01
-#define		SEQINT          	0x01
-
-#define	CLRINT          		0x92
-#define		CLRPARERR       	0x10
-#define		CLRBRKADRINT    	0x08
-#define		CLRSCSIINT      	0x04
-#define		CLRCMDINT       	0x02
-#define		CLRSEQINT       	0x01
-
-#define	ERROR           		0x92
-#define		CIOPARERR       	0x80
-#define		PCIERRSTAT      	0x40
-#define		MPARERR         	0x20
-#define		DPARERR         	0x10
-#define		SQPARERR        	0x08
-#define		ILLOPCODE       	0x04
-#define		DSCTMOUT        	0x02
-#define		ILLSADDR        	0x02
-#define		ILLHADDR        	0x01
-
-#define	DFCNTRL         		0x93
-
-#define	DFSTATUS        		0x94
-#define		PRELOAD_AVAIL   	0x80
-#define		DWORDEMP        	0x20
-#define		MREQPEND        	0x10
-#define		HDONE           	0x08
-#define		DFTHRESH        	0x04
-#define		FIFOFULL        	0x02
-#define		FIFOEMP         	0x01
-
-#define	DFDAT           		0x99
-
-#define	SCBCNT          		0x9a
-#define		SCBAUTO         	0x80
-#define		SCBCNT_MASK     	0x1f
-
-#define	QINFIFO         		0x9b
-
-#define	QINCNT          		0x9c
-
-#define	SCSIDATL_IMG    		0x9c
-
-#define	QOUTFIFO        		0x9d
-
-#define	CRCCONTROL1     		0x9d
-#define		CRCONSEEN       	0x80
-#define		CRCVALCHKEN     	0x40
-#define		CRCENDCHKEN     	0x20
-#define		CRCREQCHKEN     	0x10
-#define		TARGCRCENDEN    	0x08
-#define		TARGCRCCNTEN    	0x04
-
-#define	QOUTCNT         		0x9e
-
-#define	SCSIPHASE       		0x9e
-#define		SP_STATUS       	0x20
-#define		SP_COMMAND      	0x10
-#define		SP_MSG_IN       	0x08
-#define		SP_MSG_OUT      	0x04
-#define		SP_DATA_IN      	0x02
-#define		SP_DATA_OUT     	0x01
-
-#define	SFUNCT          		0x9f
-#define		ALT_MODE        	0x80
-
-#define	SCB_CONTROL     		0xa0
-#define		MK_MESSAGE      	0x80
-#define		DISCENB         	0x40
-#define		TAG_ENB         	0x20
-#define		DISCONNECTED    	0x04
-#define		SCB_TAG_TYPE    	0x03
-
-#define	SCB_BASE        		0xa0
-
-#define	SCB_TCL         		0xa1
-#define		TID             	0xf0
-#define		SELBUSB         	0x08
-#define		LID             	0x07
-
-#define	SCB_TARGET_STATUS		0xa2
-
-#define	SCB_SGCOUNT     		0xa3
-
-#define	SCB_SGPTR       		0xa4
-
-#define	SCB_RESID_SGCNT 		0xa8
-
-#define	SCB_RESID_DCNT  		0xa9
-
-#define	SCB_DATAPTR     		0xac
-
-#define	SCB_DATACNT     		0xb0
-
-#define	SCB_CMDPTR      		0xb4
-
-#define	SCB_CMDLEN      		0xb8
-
-#define	SCB_TAG         		0xb9
-
-#define	SCB_NEXT        		0xba
-
-#define	SCB_PREV        		0xbb
-
-#define	SCB_BUSYTARGETS 		0xbc
-
-#define	SEECTL_2840     		0xc0
-#define		CS_2840         	0x04
-#define		CK_2840         	0x02
-#define		DO_2840         	0x01
-
-#define	STATUS_2840     		0xc1
-#define		EEPROM_TF       	0x80
-#define		BIOS_SEL        	0x60
-#define		ADSEL           	0x1e
-#define		DI_2840         	0x01
-
-#define	CCHADDR         		0xe0
-
-#define	CCHCNT          		0xe8
-
-#define	CCSGRAM         		0xe9
-
-#define	CCSGADDR        		0xea
-
-#define	CCSGCTL         		0xeb
-#define		CCSGDONE        	0x80
-#define		CCSGEN          	0x08
-#define		FLAG            	0x02
-#define		CCSGRESET       	0x01
-
-#define	CCSCBRAM        		0xec
-
-#define	CCSCBADDR       		0xed
-
-#define	CCSCBCTL        		0xee
-#define		CCSCBDONE       	0x80
-#define		ARRDONE         	0x40
-#define		CCARREN         	0x10
-#define		CCSCBEN         	0x08
-#define		CCSCBDIR        	0x04
-#define		CCSCBRESET      	0x01
-
-#define	CCSCBCNT        		0xef
-
-#define	CCSCBPTR        		0xf1
-
-#define	HNSCB_QOFF      		0xf4
-
-#define	HESCB_QOFF      		0xf5
-
-#define	SNSCB_QOFF      		0xf6
-
-#define	SESCB_QOFF      		0xf7
-
-#define	SDSCB_QOFF      		0xf8
-
-#define	QOFF_CTLSTA     		0xfa
-#define		ESTABLISH_SCB_AVAIL	0x80
-#define		SCB_AVAIL       	0x40
-#define		SNSCB_ROLLOVER  	0x20
-#define		SDSCB_ROLLOVER  	0x10
-#define		SESCB_ROLLOVER  	0x08
-#define		SCB_QSIZE       	0x07
-#define		SCB_QSIZE_256   	0x06
-
-#define	DFF_THRSH       		0xfb
-#define		WR_DFTHRSH      	0x70
-#define		WR_DFTHRSH_MAX  	0x70
-#define		WR_DFTHRSH_90   	0x60
-#define		WR_DFTHRSH_85   	0x50
-#define		WR_DFTHRSH_75   	0x40
-#define		WR_DFTHRSH_63   	0x30
-#define		WR_DFTHRSH_50   	0x20
-#define		WR_DFTHRSH_25   	0x10
-#define		RD_DFTHRSH_MAX  	0x07
-#define		RD_DFTHRSH      	0x07
-#define		RD_DFTHRSH_90   	0x06
-#define		RD_DFTHRSH_85   	0x05
-#define		RD_DFTHRSH_75   	0x04
-#define		RD_DFTHRSH_63   	0x03
-#define		RD_DFTHRSH_50   	0x02
-#define		RD_DFTHRSH_25   	0x01
-#define		RD_DFTHRSH_MIN  	0x00
-#define		WR_DFTHRSH_MIN  	0x00
-
-#define	SG_CACHEPTR     		0xfc
-#define		SG_USER_DATA    	0xfc
-#define		LAST_SEG        	0x02
-#define		LAST_SEG_DONE   	0x01
-
-
-#define	CMD_GROUP_CODE_SHIFT	0x05
-#define	BUS_8_BIT	0x00
-#define	QOUTFIFO_OFFSET	0x01
-#define	CCSGRAM_MAXSEGS	0x10
-#define	CMD_GROUP2_BYTE_DELTA	0xfa
-#define	MAX_OFFSET_8BIT	0x0f
-#define	BUS_16_BIT	0x01
-#define	QINFIFO_OFFSET	0x02
-#define	CMD_GROUP5_BYTE_DELTA	0x0b
-#define	MAX_OFFSET_ULTRA2	0x7f
-#define	MAX_OFFSET_16BIT	0x08
-#define	UNTAGGEDSCB_OFFSET	0x00
-#define	SCB_LIST_NULL	0xff
-#define	SG_SIZEOF	0x08
-#define	CMD_GROUP4_BYTE_DELTA	0x04
-#define	CMD_GROUP0_BYTE_DELTA	0xfc
-#define	HOST_MSG	0xff
-#define	BUS_32_BIT	0x02
-#define	CCSGADDR_MAX	0x80
-
-
-/* Downloaded Constant Definitions */
-#define	TMODE_NUMCMDS	0x00
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c
--- v2.4.2/linux/drivers/scsi/aic7xxx_seq.c	Wed Jun 21 17:25:03 2000
+++ linux/drivers/scsi/aic7xxx_seq.c	Wed Dec 31 16:00:00 1969
@@ -1,745 +0,0 @@
-/*
-  * DO NOT EDIT - This file is automatically generated.
-  */
-static unsigned char seqprog[] = {
-	0xff, 0x6a, 0x06, 0x08,
-	0x7f, 0x02, 0x04, 0x08,
-	0x12, 0x6a, 0x00, 0x00,
-	0xff, 0x6a, 0xd6, 0x09,
-	0xff, 0x6a, 0xdc, 0x09,
-	0x00, 0x65, 0xca, 0x58,
-	0xf7, 0x01, 0x02, 0x08,
-	0xff, 0x4e, 0xc8, 0x08,
-	0xbf, 0x60, 0xc0, 0x08,
-	0x60, 0x0b, 0x86, 0x68,
-	0x40, 0x00, 0x0c, 0x68,
-	0x08, 0x1f, 0x3e, 0x10,
-	0x60, 0x0b, 0x86, 0x68,
-	0x40, 0x00, 0x0c, 0x68,
-	0x08, 0x1f, 0x3e, 0x10,
-	0xff, 0x3e, 0x48, 0x60,
-	0x40, 0xfa, 0x10, 0x78,
-	0xff, 0xf6, 0xd4, 0x08,
-	0x01, 0x4e, 0x9c, 0x18,
-	0x40, 0x60, 0xc0, 0x00,
-	0x00, 0x4d, 0x10, 0x70,
-	0x01, 0x4e, 0x9c, 0x18,
-	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0x3e, 0x5c,
-	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0x54, 0x5b,
-	0xff, 0x52, 0x20, 0x09,
-	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0xca, 0x5b,
-	0x03, 0xb0, 0x52, 0x31,
-	0xff, 0xb0, 0x52, 0x09,
-	0xff, 0xb1, 0x54, 0x09,
-	0xff, 0xb2, 0x56, 0x09,
-	0xff, 0xa3, 0x50, 0x09,
-	0xff, 0x3e, 0x74, 0x09,
-	0xff, 0x90, 0x7c, 0x08,
-	0xff, 0x3e, 0x20, 0x09,
-	0x00, 0x65, 0x4e, 0x58,
-	0x00, 0x65, 0x0c, 0x40,
-	0xf7, 0x1f, 0xca, 0x08,
-	0x08, 0xa1, 0xc8, 0x08,
-	0x00, 0x65, 0xca, 0x00,
-	0xff, 0x65, 0x3e, 0x08,
-	0xf0, 0xa1, 0xc8, 0x08,
-	0x0f, 0x0f, 0x1e, 0x08,
-	0x00, 0x0f, 0x1e, 0x00,
-	0xf0, 0xa1, 0xc8, 0x08,
-	0x0f, 0x05, 0x0a, 0x08,
-	0x00, 0x05, 0x0a, 0x00,
-	0xff, 0x6a, 0x0c, 0x08,
-	0x5a, 0x6a, 0x00, 0x04,
-	0x12, 0x65, 0x02, 0x00,
-	0x31, 0x6a, 0xca, 0x00,
-	0x80, 0x37, 0x6e, 0x68,
-	0xff, 0x65, 0xca, 0x18,
-	0xff, 0x37, 0xdc, 0x08,
-	0xff, 0x6e, 0xc8, 0x08,
-	0x00, 0x6c, 0x76, 0x78,
-	0x20, 0x01, 0x02, 0x00,
-	0x4c, 0x37, 0xc8, 0x28,
-	0x08, 0x1f, 0x7e, 0x78,
-	0x08, 0x37, 0x6e, 0x00,
-	0x08, 0x64, 0xc8, 0x00,
-	0x70, 0x64, 0xca, 0x18,
-	0xff, 0x6c, 0x0a, 0x08,
-	0x20, 0x64, 0xca, 0x18,
-	0xff, 0x6c, 0x08, 0x0c,
-	0x40, 0x0b, 0x96, 0x68,
-	0x20, 0x6a, 0x16, 0x00,
-	0xf0, 0x19, 0x6e, 0x08,
-	0x08, 0x6a, 0x18, 0x00,
-	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x66, 0x58,
-	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x12, 0x6a, 0x00, 0x00,
-	0x40, 0x6a, 0x16, 0x00,
-	0xff, 0x3e, 0x20, 0x09,
-	0xff, 0xba, 0x7c, 0x08,
-	0xff, 0xa1, 0x6e, 0x08,
-	0x08, 0x6a, 0x18, 0x00,
-	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x66, 0x58,
-	0x80, 0x6a, 0x68, 0x00,
-	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xff, 0x3d, 0xc8, 0x08,
-	0xbf, 0x64, 0xe2, 0x78,
-	0x80, 0x64, 0xac, 0x71,
-	0xa0, 0x64, 0xdc, 0x71,
-	0xc0, 0x64, 0xd4, 0x71,
-	0xe0, 0x64, 0x1c, 0x72,
-	0x01, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0xca, 0x58,
-	0xff, 0x06, 0xd4, 0x08,
-	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0xc4, 0x78,
-	0x08, 0x0c, 0x0c, 0x68,
-	0x01, 0x6a, 0x22, 0x01,
-	0xff, 0x6a, 0x26, 0x09,
-	0x02, 0x6a, 0x08, 0x30,
-	0xff, 0x6a, 0x08, 0x08,
-	0xdf, 0x01, 0x02, 0x08,
-	0x01, 0x6a, 0x7a, 0x00,
-	0xff, 0x6a, 0x6c, 0x0c,
-	0x04, 0x14, 0x10, 0x31,
-	0x03, 0xa9, 0x18, 0x31,
-	0x03, 0xa9, 0x10, 0x30,
-	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0xb4, 0x5b,
-	0x00, 0x65, 0x02, 0x41,
-	0xa8, 0x6a, 0x6a, 0x00,
-	0x79, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0xea, 0x68,
-	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x0e, 0x5b,
-	0x80, 0x6a, 0xd4, 0x01,
-	0x10, 0x36, 0xd6, 0x68,
-	0x10, 0x36, 0x6c, 0x00,
-	0x07, 0xac, 0x10, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
-	0x05, 0xa3, 0x70, 0x30,
-	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0xac, 0x5b,
-	0x00, 0x65, 0xa6, 0x5b,
-	0x38, 0x6a, 0xcc, 0x00,
-	0xa3, 0x6a, 0xb0, 0x5b,
-	0xff, 0x38, 0x12, 0x69,
-	0x80, 0x02, 0x04, 0x00,
-	0xe7, 0x35, 0x6a, 0x08,
-	0x03, 0x69, 0x18, 0x31,
-	0x03, 0x69, 0x10, 0x30,
-	0xff, 0x6a, 0x10, 0x00,
-	0xff, 0x6a, 0x12, 0x00,
-	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0x18, 0x61,
-	0xbf, 0x35, 0x6a, 0x08,
-	0x02, 0x6a, 0xf8, 0x01,
-	0xff, 0x69, 0xca, 0x08,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x1c, 0x69,
-	0x04, 0x0b, 0x28, 0x69,
-	0x10, 0x0c, 0x1e, 0x79,
-	0x04, 0x0b, 0x28, 0x69,
-	0xff, 0x6a, 0xca, 0x08,
-	0x00, 0x35, 0xee, 0x5a,
-	0x80, 0x02, 0x7c, 0x69,
-	0xff, 0x65, 0x6c, 0x79,
-	0xff, 0x38, 0x70, 0x18,
-	0xff, 0x38, 0x6c, 0x79,
-	0x80, 0xea, 0x48, 0x61,
-	0xef, 0x38, 0xc8, 0x18,
-	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0x3a, 0x49,
-	0x33, 0x38, 0xc8, 0x28,
-	0xff, 0x64, 0xd0, 0x09,
-	0x04, 0x39, 0xc0, 0x31,
-	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x40, 0x79,
-	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0x44, 0x69,
-	0x01, 0x6a, 0xd6, 0x01,
-	0x08, 0xe9, 0x10, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0xb2, 0x5b,
-	0x08, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0x88, 0x6a, 0x20, 0x5c,
-	0x00, 0x65, 0xa6, 0x5b,
-	0xff, 0x6a, 0xc8, 0x08,
-	0x08, 0x39, 0x72, 0x18,
-	0x00, 0x3a, 0x74, 0x20,
-	0x01, 0x0c, 0x64, 0x79,
-	0x10, 0x0c, 0x02, 0x79,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x6a, 0x69,
-	0x00, 0x65, 0x84, 0x59,
-	0x03, 0x08, 0x52, 0x31,
-	0xff, 0x38, 0x50, 0x09,
-	0xff, 0x08, 0x52, 0x09,
-	0xff, 0x09, 0x54, 0x09,
-	0xff, 0x0a, 0x56, 0x09,
-	0xff, 0x38, 0x50, 0x09,
-	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x84, 0x59,
-	0x7f, 0x02, 0x04, 0x08,
-	0xe1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0x04, 0x93, 0x9a, 0x69,
-	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x88, 0x69,
-	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x10, 0x94, 0x98, 0x69,
-	0x7f, 0x05, 0xa0, 0x69,
-	0x02, 0x03, 0xa0, 0x79,
-	0x11, 0x0c, 0x9c, 0x79,
-	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xa2, 0x69,
-	0x03, 0x08, 0x52, 0x31,
-	0xff, 0x38, 0x50, 0x09,
-	0x12, 0x01, 0x02, 0x00,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0x0e, 0x5b,
-	0x05, 0xb4, 0x10, 0x31,
-	0x02, 0x6a, 0x1a, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
-	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0xb0, 0x5b,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0xa6, 0x5b,
-	0x3d, 0x6a, 0xee, 0x5a,
-	0xac, 0x6a, 0x26, 0x01,
-	0x04, 0x0b, 0xc2, 0x69,
-	0x04, 0x0b, 0xc8, 0x69,
-	0x10, 0x0c, 0xc4, 0x79,
-	0x02, 0x03, 0xcc, 0x79,
-	0x11, 0x0c, 0xc8, 0x79,
-	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xce, 0x69,
-	0x12, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x0e, 0x5b,
-	0xff, 0x06, 0x44, 0x09,
-	0x00, 0x65, 0xaa, 0x40,
-	0x10, 0x3d, 0x06, 0x00,
-	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x00, 0x62,
-	0x0f, 0xa1, 0xca, 0x08,
-	0x07, 0xa1, 0xca, 0x08,
-	0x40, 0xa0, 0xc8, 0x08,
-	0x00, 0x65, 0xca, 0x00,
-	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0xf0, 0x79,
-	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x02, 0x42,
-	0x20, 0xa0, 0x08, 0x7a,
-	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0x10, 0x62,
-	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0x10, 0x62,
-	0x00, 0xb9, 0x08, 0x42,
-	0xff, 0x65, 0x08, 0x62,
-	0xa1, 0x6a, 0x22, 0x01,
-	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x10, 0x72,
-	0x40, 0x6a, 0x18, 0x00,
-	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0xda, 0x71,
-	0x40, 0x6a, 0x18, 0x00,
-	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x18, 0x62,
-	0x7f, 0xa0, 0x40, 0x09,
-	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x64, 0x6a, 0xe4, 0x5a,
-	0x80, 0x64, 0x8e, 0x6a,
-	0x04, 0x64, 0x70, 0x72,
-	0x02, 0x64, 0x76, 0x72,
-	0x00, 0x6a, 0x38, 0x72,
-	0x03, 0x64, 0x8a, 0x72,
-	0x01, 0x64, 0x6c, 0x72,
-	0x07, 0x64, 0xcc, 0x72,
-	0x08, 0x64, 0x34, 0x72,
-	0x23, 0x64, 0xd0, 0x72,
-	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0xd6, 0x5a,
-	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0xaa, 0x40,
-	0xff, 0xa8, 0x3c, 0x6a,
-	0xff, 0xa2, 0x54, 0x7a,
-	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0xa2, 0x54, 0x7a,
-	0x71, 0x6a, 0x22, 0x01,
-	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0x54, 0x62,
-	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0x3e, 0x74, 0x09,
-	0xff, 0x90, 0x7c, 0x08,
-	0x00, 0x65, 0x4e, 0x58,
-	0x00, 0x65, 0xbc, 0x40,
-	0x20, 0xa0, 0x5c, 0x6a,
-	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0x74, 0x5b,
-	0xff, 0x6a, 0x8a, 0x5b,
-	0xff, 0xf8, 0xc8, 0x08,
-	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0x74, 0x5b,
-	0x00, 0xb9, 0x8a, 0x5b,
-	0x01, 0x4f, 0x9e, 0x18,
-	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x38, 0x5c,
-	0x00, 0x65, 0xbc, 0x40,
-	0x41, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0x50, 0x5c,
-	0x00, 0x65, 0xbc, 0x40,
-	0x10, 0x36, 0x34, 0x7a,
-	0x05, 0x38, 0x46, 0x31,
-	0x04, 0x14, 0x58, 0x31,
-	0x03, 0xa9, 0x60, 0x31,
-	0xa3, 0x6a, 0xcc, 0x00,
-	0x38, 0x6a, 0xb0, 0x5b,
-	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xb2, 0x5b,
-	0xa9, 0x6a, 0xb4, 0x5b,
-	0x00, 0x65, 0x34, 0x42,
-	0xef, 0x36, 0x6c, 0x08,
-	0x00, 0x65, 0x34, 0x42,
-	0x0f, 0x64, 0xc8, 0x08,
-	0x07, 0x64, 0xc8, 0x08,
-	0x00, 0x37, 0x6e, 0x00,
-	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0x44, 0x5b,
-	0xff, 0x51, 0xa0, 0x72,
-	0x20, 0x36, 0xaa, 0x7a,
-	0x00, 0x90, 0x32, 0x5b,
-	0x00, 0x65, 0xac, 0x42,
-	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xe0, 0x3d, 0xc6, 0x62,
-	0x20, 0x12, 0xc6, 0x62,
-	0x51, 0x6a, 0xda, 0x5a,
-	0x00, 0x65, 0x2c, 0x5b,
-	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0xa1, 0xbe, 0x62,
-	0x04, 0xa0, 0xbe, 0x7a,
-	0xfb, 0xa0, 0x40, 0x09,
-	0x80, 0x36, 0x6c, 0x00,
-	0x80, 0xa0, 0x34, 0x7a,
-	0x7f, 0xa0, 0x40, 0x09,
-	0xff, 0x6a, 0xd6, 0x5a,
-	0x00, 0x65, 0x34, 0x42,
-	0x04, 0xa0, 0xc4, 0x7a,
-	0x00, 0x65, 0x50, 0x5c,
-	0x00, 0x65, 0xc6, 0x42,
-	0x00, 0x65, 0x38, 0x5c,
-	0x31, 0x6a, 0x22, 0x01,
-	0x0c, 0x6a, 0xd6, 0x5a,
-	0x00, 0x65, 0x34, 0x42,
-	0x61, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x34, 0x42,
-	0x51, 0x6a, 0xda, 0x5a,
-	0x51, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x34, 0x42,
-	0x10, 0x3d, 0x06, 0x00,
-	0xff, 0x65, 0x68, 0x0c,
-	0xff, 0x06, 0xd4, 0x08,
-	0x01, 0x0c, 0xdc, 0x7a,
-	0x04, 0x0c, 0xde, 0x6a,
-	0xe0, 0x03, 0x7a, 0x08,
-	0xe0, 0x3d, 0xea, 0x62,
-	0xff, 0x65, 0xcc, 0x08,
-	0xff, 0x12, 0xda, 0x0c,
-	0xff, 0x06, 0xd4, 0x0c,
-	0xd1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0xff, 0x65, 0x26, 0x09,
-	0x01, 0x0b, 0xfe, 0x6a,
-	0x10, 0x0c, 0xf0, 0x7a,
-	0x04, 0x0b, 0xf8, 0x6a,
-	0xff, 0x6a, 0xca, 0x08,
-	0x04, 0x93, 0xfc, 0x6a,
-	0x01, 0x94, 0xfa, 0x7a,
-	0x10, 0x94, 0xfc, 0x6a,
-	0x80, 0x3d, 0x02, 0x73,
-	0x0f, 0x04, 0x06, 0x6b,
-	0x02, 0x03, 0x06, 0x7b,
-	0x11, 0x0c, 0x02, 0x7b,
-	0xc7, 0x93, 0x26, 0x09,
-	0xff, 0x99, 0xd4, 0x08,
-	0x38, 0x93, 0x08, 0x6b,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0x36, 0x0c, 0x6b,
-	0x21, 0x6a, 0x22, 0x05,
-	0xff, 0x65, 0x20, 0x09,
-	0xff, 0x51, 0x1a, 0x63,
-	0xff, 0x37, 0xc8, 0x08,
-	0xa1, 0x6a, 0x26, 0x43,
-	0xff, 0x51, 0xc8, 0x08,
-	0xb9, 0x6a, 0x26, 0x43,
-	0xff, 0x90, 0xa4, 0x08,
-	0xff, 0xba, 0x2a, 0x73,
-	0xff, 0xba, 0x20, 0x09,
-	0xff, 0x65, 0xca, 0x18,
-	0x00, 0x6c, 0x1e, 0x63,
-	0xff, 0x90, 0xca, 0x0c,
-	0xff, 0x6a, 0xca, 0x04,
-	0x20, 0x36, 0x3e, 0x7b,
-	0x00, 0x90, 0x12, 0x5b,
-	0xff, 0x65, 0x3e, 0x73,
-	0xff, 0x52, 0x3c, 0x73,
-	0xff, 0xba, 0xcc, 0x08,
-	0xff, 0x52, 0x20, 0x09,
-	0xff, 0x66, 0x74, 0x09,
-	0xff, 0x65, 0x20, 0x0d,
-	0xff, 0xba, 0x7e, 0x0c,
-	0x00, 0x6a, 0x3e, 0x5c,
-	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x51, 0xca, 0x43,
-	0xff, 0x3f, 0x98, 0x73,
-	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3f, 0x12, 0x5b,
-	0xff, 0x65, 0x98, 0x73,
-	0x20, 0x36, 0x6c, 0x00,
-	0x20, 0xa0, 0x52, 0x6b,
-	0xff, 0xb9, 0xa2, 0x0c,
-	0xff, 0x6a, 0xa2, 0x04,
-	0xff, 0x65, 0xa4, 0x08,
-	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0xd0, 0x01,
-	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x5e, 0x7b,
-	0x01, 0x6a, 0xd6, 0x01,
-	0x01, 0xe9, 0xa4, 0x34,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x0d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0xff, 0x99, 0xa4, 0x0c,
-	0xff, 0x65, 0xa4, 0x08,
-	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0xd0, 0x01,
-	0x01, 0x6a, 0xdc, 0x05,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x01, 0x6a, 0x26, 0x05,
-	0x01, 0x65, 0xd8, 0x31,
-	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x8e, 0x7b,
-	0xff, 0x6a, 0xdc, 0x0d,
-	0xff, 0x65, 0x32, 0x09,
-	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x44,
-	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0x54, 0x5b,
-	0xff, 0x52, 0xa2, 0x0c,
-	0x01, 0x0c, 0x9e, 0x7b,
-	0x04, 0x0c, 0x9e, 0x6b,
-	0xe0, 0x03, 0x06, 0x08,
-	0xe0, 0x03, 0x7a, 0x0c,
-	0xff, 0x8c, 0x10, 0x08,
-	0xff, 0x8d, 0x12, 0x08,
-	0xff, 0x8e, 0x14, 0x0c,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x0c,
-	0x3d, 0x64, 0xa4, 0x28,
-	0x55, 0x64, 0xc8, 0x28,
-	0x00, 0x6c, 0xda, 0x18,
-	0xff, 0x52, 0xc8, 0x08,
-	0x00, 0x6c, 0xda, 0x20,
-	0xff, 0x6a, 0xc8, 0x08,
-	0x00, 0x6c, 0xda, 0x20,
-	0x00, 0x6c, 0xda, 0x24,
-	0xff, 0x65, 0xc8, 0x08,
-	0xe0, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0xba, 0x5b,
-	0xff, 0x90, 0xe2, 0x09,
-	0x20, 0x6a, 0xd0, 0x01,
-	0x04, 0x35, 0xdc, 0x7b,
-	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0xd8, 0x63,
-	0x00, 0x65, 0xe8, 0x43,
-	0x01, 0x6a, 0xdc, 0x01,
-	0x20, 0xa0, 0xd8, 0x31,
-	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xe2, 0x7b,
-	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0xe6, 0x63,
-	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0xea, 0x6b,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0xba, 0x5b,
-	0x20, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x35, 0x14, 0x6c,
-	0xa0, 0x6a, 0xca, 0x00,
-	0x20, 0x65, 0xc8, 0x18,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0x00, 0x65, 0x00, 0x64,
-	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0x04, 0x35, 0x0c, 0x7b,
-	0xa0, 0x6a, 0x20, 0x5c,
-	0x00, 0x65, 0x22, 0x5c,
-	0x00, 0x65, 0x22, 0x5c,
-	0x00, 0x65, 0x22, 0x44,
-	0xff, 0x65, 0xcc, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x0c,
-	0x08, 0x94, 0x30, 0x7c,
-	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x34, 0x6c,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0xff, 0x40, 0x74, 0x09,
-	0xff, 0x90, 0x80, 0x08,
-	0xff, 0x6a, 0x72, 0x05,
-	0xff, 0x40, 0x4c, 0x64,
-	0xff, 0x3f, 0x44, 0x64,
-	0xff, 0x6a, 0xca, 0x04,
-	0xff, 0x3f, 0x20, 0x09,
-	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0xba, 0x7e, 0x0c,
-	0xff, 0x40, 0x20, 0x09,
-	0xff, 0xba, 0x80, 0x0c,
-	0xff, 0x3f, 0x74, 0x09,
-	0xff, 0x90, 0x7e, 0x0c,
-};
-
-static int aic7xxx_patch12_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch12_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_WIDE) != 0);
-}
-
-static int aic7xxx_patch11_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch11_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_ULTRA2) == 0);
-}
-
-static int aic7xxx_patch10_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch10_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_CMD_CHAN) == 0);
-}
-
-static int aic7xxx_patch9_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch9_func(struct aic7xxx_host *p)
-{
-	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
-}
-
-static int aic7xxx_patch8_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch8_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_ULTRA) != 0);
-}
-
-static int aic7xxx_patch7_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch7_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_ULTRA2) != 0);
-}
-
-static int aic7xxx_patch6_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch6_func(struct aic7xxx_host *p)
-{
-	return ((p->flags & AHC_PAGESCBS) == 0);
-}
-
-static int aic7xxx_patch5_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch5_func(struct aic7xxx_host *p)
-{
-	return ((p->flags & AHC_PAGESCBS) != 0);
-}
-
-static int aic7xxx_patch4_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch4_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_QUEUE_REGS) != 0);
-}
-
-static int aic7xxx_patch3_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch3_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_TWIN) != 0);
-}
-
-static int aic7xxx_patch2_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch2_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_QUEUE_REGS) == 0);
-}
-
-static int aic7xxx_patch1_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch1_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_CMD_CHAN) != 0);
-}
-
-static int aic7xxx_patch0_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch0_func(struct aic7xxx_host *p)
-{
-	return (0);
-}
-
-struct sequencer_patch {
-	int		(*patch_func)(struct aic7xxx_host *);
-	unsigned int	begin	   :10,
-			skip_instr :10,
-			skip_patch :12;
-} sequencer_patches[] = {
-	{ aic7xxx_patch1_func, 3, 2, 1 },
-	{ aic7xxx_patch2_func, 7, 1, 1 },
-	{ aic7xxx_patch2_func, 8, 1, 1 },
-	{ aic7xxx_patch3_func, 11, 4, 1 },
-	{ aic7xxx_patch4_func, 16, 3, 2 },
-	{ aic7xxx_patch0_func, 19, 4, 1 },
-	{ aic7xxx_patch5_func, 23, 1, 1 },
-	{ aic7xxx_patch6_func, 26, 1, 1 },
-	{ aic7xxx_patch1_func, 29, 1, 2 },
-	{ aic7xxx_patch0_func, 30, 3, 1 },
-	{ aic7xxx_patch3_func, 39, 4, 1 },
-	{ aic7xxx_patch7_func, 43, 3, 2 },
-	{ aic7xxx_patch0_func, 46, 3, 1 },
-	{ aic7xxx_patch8_func, 52, 7, 1 },
-	{ aic7xxx_patch3_func, 60, 3, 1 },
-	{ aic7xxx_patch7_func, 63, 2, 1 },
-	{ aic7xxx_patch7_func, 102, 1, 2 },
-	{ aic7xxx_patch0_func, 103, 2, 1 },
-	{ aic7xxx_patch7_func, 107, 2, 1 },
-	{ aic7xxx_patch9_func, 109, 1, 1 },
-	{ aic7xxx_patch10_func, 110, 2, 1 },
-	{ aic7xxx_patch7_func, 113, 1, 2 },
-	{ aic7xxx_patch0_func, 114, 1, 1 },
-	{ aic7xxx_patch1_func, 118, 1, 1 },
-	{ aic7xxx_patch1_func, 121, 3, 2 },
-	{ aic7xxx_patch0_func, 124, 5, 1 },
-	{ aic7xxx_patch1_func, 132, 2, 3 },
-	{ aic7xxx_patch7_func, 132, 1, 1 },
-	{ aic7xxx_patch0_func, 134, 3, 1 },
-	{ aic7xxx_patch11_func, 138, 1, 2 },
-	{ aic7xxx_patch0_func, 139, 1, 1 },
-	{ aic7xxx_patch7_func, 140, 7, 2 },
-	{ aic7xxx_patch0_func, 147, 1, 1 },
-	{ aic7xxx_patch1_func, 152, 14, 3 },
-	{ aic7xxx_patch11_func, 165, 1, 1 },
-	{ aic7xxx_patch0_func, 166, 9, 1 },
-	{ aic7xxx_patch7_func, 180, 2, 1 },
-	{ aic7xxx_patch7_func, 182, 1, 1 },
-	{ aic7xxx_patch11_func, 183, 6, 3 },
-	{ aic7xxx_patch1_func, 183, 2, 2 },
-	{ aic7xxx_patch0_func, 185, 4, 1 },
-	{ aic7xxx_patch7_func, 190, 1, 1 },
-	{ aic7xxx_patch7_func, 194, 20, 1 },
-	{ aic7xxx_patch1_func, 215, 3, 3 },
-	{ aic7xxx_patch11_func, 217, 1, 1 },
-	{ aic7xxx_patch0_func, 218, 5, 1 },
-	{ aic7xxx_patch11_func, 223, 1, 2 },
-	{ aic7xxx_patch0_func, 224, 9, 1 },
-	{ aic7xxx_patch12_func, 240, 1, 2 },
-	{ aic7xxx_patch0_func, 241, 1, 1 },
-	{ aic7xxx_patch4_func, 302, 1, 2 },
-	{ aic7xxx_patch0_func, 303, 1, 1 },
-	{ aic7xxx_patch2_func, 306, 1, 1 },
-	{ aic7xxx_patch1_func, 316, 3, 2 },
-	{ aic7xxx_patch0_func, 319, 5, 1 },
-	{ aic7xxx_patch12_func, 327, 1, 2 },
-	{ aic7xxx_patch0_func, 328, 1, 1 },
-	{ aic7xxx_patch5_func, 333, 1, 1 },
-	{ aic7xxx_patch11_func, 375, 15, 1 },
-	{ aic7xxx_patch1_func, 427, 7, 2 },
-	{ aic7xxx_patch0_func, 434, 8, 1 },
-	{ aic7xxx_patch1_func, 443, 4, 2 },
-	{ aic7xxx_patch0_func, 447, 6, 1 },
-	{ aic7xxx_patch1_func, 453, 4, 2 },
-	{ aic7xxx_patch0_func, 457, 3, 1 },
-	{ aic7xxx_patch10_func, 467, 10, 1 },
-	{ aic7xxx_patch1_func, 486, 17, 4 },
-	{ aic7xxx_patch9_func, 494, 4, 2 },
-	{ aic7xxx_patch0_func, 498, 2, 1 },
-	{ aic7xxx_patch0_func, 503, 33, 1 },
-	{ aic7xxx_patch10_func, 536, 4, 1 },
-	{ aic7xxx_patch5_func, 540, 2, 1 },
-	{ aic7xxx_patch5_func, 543, 9, 1 },
-
-};
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/atari_dma_emul.c linux/drivers/scsi/atari_dma_emul.c
--- v2.4.2/linux/drivers/scsi/atari_dma_emul.c	Sat Jan  9 19:16:43 1999
+++ linux/drivers/scsi/atari_dma_emul.c	Tue Mar  6 19:44:37 2001
@@ -131,7 +131,7 @@
  * 
  * 4. When this function is left, the address pointer (start_addr) is
  *    converted to a physical address. Because it points one byte
- *    further than the last transfered byte, it can point outside the
+ *    further than the last transferred byte, it can point outside the
  *    current page. If virt_to_phys() is called with this address we
  *    might get an access error. Therefore virt_to_phys() is called with
  *    start_addr - 1 if the count has reached zero. The result is
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- v2.4.2/linux/drivers/scsi/atari_scsi.c	Mon Nov 27 17:57:34 2000
+++ linux/drivers/scsi/atari_scsi.c	Tue Mar  6 19:44:37 2001
@@ -690,19 +690,30 @@
 		/* This int is actually "pseudo-slow", i.e. it acts like a slow
 		 * interrupt after having cleared the pending flag for the DMA
 		 * interrupt. */
-		request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,
-		            "SCSI NCR5380", scsi_tt_intr);
+		if (request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,
+				 "SCSI NCR5380", scsi_tt_intr)) {
+			printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting",IRQ_TT_MFP_SCSI);
+			scsi_unregister(atari_scsi_host);
+			atari_stram_free(atari_dma_buffer);
+			atari_dma_buffer = 0;
+			return 0;
+		}
 		tt_mfp.active_edge |= 0x80;		/* SCSI int on L->H */
 #ifdef REAL_DMA
 		tt_scsi_dma.dma_ctrl = 0;
 		atari_dma_residual = 0;
-#endif /* REAL_DMA */
-#ifdef REAL_DMA
 #ifdef CONFIG_TT_DMA_EMUL
 		if (MACH_IS_HADES) {
-			request_irq(IRQ_AUTO_2, hades_dma_emulator,
-				    IRQ_TYPE_PRIO, "Hades DMA emulator",
-				    hades_dma_emulator);
+			if (request_irq(IRQ_AUTO_2, hades_dma_emulator,
+					 IRQ_TYPE_PRIO, "Hades DMA emulator",
+					 hades_dma_emulator)) {
+				printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2);
+				free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
+				scsi_unregister(atari_scsi_host);
+				atari_stram_free(atari_dma_buffer);
+				atari_dma_buffer = 0;
+				return 0;
+			}
 		}
 #endif
 		if (MACH_IS_MEDUSA || MACH_IS_HADES) {
@@ -719,9 +730,8 @@
 			 * the rest data bug is fixed, this can be lowered to 1.
 			 */
 			atari_read_overruns = 4;
-		}
-#endif
-		
+		}		
+#endif /*REAL_DMA*/
 	}
 	else { /* ! IS_A_TT */
 		
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/blz1230.c linux/drivers/scsi/blz1230.c
--- v2.4.2/linux/drivers/scsi/blz1230.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/blz1230.c	Tue Mar  6 19:44:37 2001
@@ -53,7 +53,7 @@
 
 volatile unsigned char cmd_buffer[16];
 				/* This is where all commands are put
-				 * before they are transfered to the ESP chip
+				 * before they are transferred to the ESP chip
 				 * via PIO.
 				 */
 
@@ -88,13 +88,8 @@
 
 		esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
 		udelay(5);
-		if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)){
-			esp_deallocate(esp);
-			scsi_unregister(esp->ehost);
-			release_mem_region(board+REAL_BLZ1230_ESP_ADDR,
-					   sizeof(struct ESP_regs));
-			return 0; /* Bail out if address did not hold data */
-		}
+		if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
+			goto err_out;
 
 		/* Do command transfer with programmed I/O */
 		esp->do_pio_cmds = 1;
@@ -140,8 +135,9 @@
 
 		esp->irq = IRQ_AMIGA_PORTS;
 		esp->slot = board+REAL_BLZ1230_ESP_ADDR;
-		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
-			    "Blizzard 1230 SCSI IV", esp_intr);
+		if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+				 "Blizzard 1230 SCSI IV", esp_intr))
+			goto err_out;
 
 		/* Figure out our scsi ID on the bus */
 		esp->scsi_id = 7;
@@ -156,6 +152,13 @@
 		return esps_in_use;
 	    }
 	}
+	return 0;
+ 
+ err_out:
+	scsi_unregister(esp->ehost);
+	esp_deallocate(esp);
+	release_mem_region(board+REAL_BLZ1230_ESP_ADDR,
+			   sizeof(struct ESP_regs));
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/blz2060.c linux/drivers/scsi/blz2060.c
--- v2.4.2/linux/drivers/scsi/blz2060.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/blz2060.c	Fri Mar  2 18:38:38 2001
@@ -53,7 +53,7 @@
 
 volatile unsigned char cmd_buffer[16];
 				/* This is where all commands are put
-				 * before they are transfered to the ESP chip
+				 * before they are transferred to the ESP chip
 				 * via PIO.
 				 */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cpqfcTScontrol.c linux/drivers/scsi/cpqfcTScontrol.c
--- v2.4.2/linux/drivers/scsi/cpqfcTScontrol.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/cpqfcTScontrol.c	Fri Mar  2 18:38:38 2001
@@ -1204,7 +1204,7 @@
           // 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 occured.  Any accepted Login exhanges are
+          // 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,
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c
--- v2.4.2/linux/drivers/scsi/cpqfcTSinit.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/cpqfcTSinit.c	Fri Mar  2 18:38:38 2001
@@ -1701,7 +1701,7 @@
 // removal time (load and unload times)
 // ALGORITHM notes:
 // Memory allocation varies by compiler and platform.  In the worst case,
-// we are only assured BYTE allignment, but in the best case, we can
+// we are only assured BYTE alignment, but in the best case, we can
 // request allocation on any desired boundary.  Our strategy: pad the
 // allocation request size (i.e. waste memory) so that we are assured
 // of passing desired boundary near beginning of contiguous space, then
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c
--- v2.4.2/linux/drivers/scsi/cpqfcTSworker.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/cpqfcTSworker.c	Fri Mar  2 18:38:38 2001
@@ -422,7 +422,7 @@
     
 //      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
       // if PortDiscDone is not set, it means the SendLogins routine
-      // failed to complete -- assume that LDn occured, so login frames
+      // failed to complete -- assume that LDn occurred, so login frames
       // are invalid
       if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
       {
@@ -4143,7 +4143,7 @@
   TachLiteIRE* pIRE;
   TachLiteTWE* pTWE;
   TachLiteTRE* pTRE;
-  ULONG fcp_dl;           // total byte length of DATA transfered
+  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;
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cyberstorm.c linux/drivers/scsi/cyberstorm.c
--- v2.4.2/linux/drivers/scsi/cyberstorm.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/cyberstorm.c	Fri Mar  2 18:38:38 2001
@@ -62,7 +62,7 @@
 
 volatile unsigned char cmd_buffer[16];
 				/* This is where all commands are put
-				 * before they are transfered to the ESP chip
+				 * before they are transferred to the ESP chip
 				 * via PIO.
 				 */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/cyberstormII.c linux/drivers/scsi/cyberstormII.c
--- v2.4.2/linux/drivers/scsi/cyberstormII.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/cyberstormII.c	Fri Mar  2 18:38:38 2001
@@ -52,7 +52,7 @@
 
 volatile unsigned char cmd_buffer[16];
 				/* This is where all commands are put
-				 * before they are transfered to the ESP chip
+				 * before they are transferred to the ESP chip
 				 * via PIO.
 				 */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/dmx3191d.c linux/drivers/scsi/dmx3191d.c
--- v2.4.2/linux/drivers/scsi/dmx3191d.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/dmx3191d.c	Fri Mar  2 11:12:11 2001
@@ -68,18 +68,17 @@
 	while ((pdev = pci_find_device(PCI_VENDOR_ID_DOMEX,
 			PCI_DEVICE_ID_DOMEX_DMX3191D, pdev))) {
 
-		unsigned long port = pci_resource_start (pdev, 0);
-
+		unsigned long port;
 		if (pci_enable_device(pdev))
 			continue;
 
-		if (check_region(port, DMX3191D_REGION)) {
+		port = pci_resource_start (pdev, 0);
+		
+		if (!request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME)) {
 			dmx3191d_printk("region 0x%lx-0x%lx already reserved\n",
 				port, port + DMX3191D_REGION);
 			continue;
 		}
-
-		request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME);
 
 		instance = scsi_register(tmpl, sizeof(struct NCR5380_hostdata));
 		if(instance == NULL)
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.4.2/linux/drivers/scsi/g_NCR5380.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/g_NCR5380.c	Tue Mar  6 19:44:37 2001
@@ -139,7 +139,7 @@
     int board;	/* Use NCR53c400, Ricoh, etc. extensions ? */
 } overrides 
 #ifdef GENERIC_NCR5380_OVERRIDE 
-    [] __initdata = GENERIC_NCR5380_OVERRIDE
+    [] __initdata = GENERIC_NCR5380_OVERRIDE;
 #else
     [1] __initdata = {{0,},};
 #endif
@@ -911,6 +911,64 @@
 MODULE_PARM(ncr_53c400, "i");
 MODULE_PARM(ncr_53c400a, "i");
 MODULE_PARM(dtc_3181e, "i");
+
+#else
+
+static int __init do_NCR5380_setup(char *str)
+{
+        int ints[10];
+
+        get_options(str, sizeof(ints)/sizeof(int), ints);
+        generic_NCR5380_setup(str,ints);
+
+        return 1;
+}
+
+static int __init do_NCR53C400_setup(char *str)
+{
+        int ints[10];
+
+        get_options(str, sizeof(ints)/sizeof(int), ints);
+        generic_NCR53C400_setup(str,ints);
+
+        return 1;
+}
+
+static int __init do_NCR53C400A_setup(char *str)
+{
+        int ints[10];
+
+        get_options(str, sizeof(ints)/sizeof(int), ints);
+        generic_NCR53C400A_setup(str,ints);
+
+        return 1;
+}
+
+static int __init do_DTC3181E_setup(char *str)
+{
+        int ints[10];
+
+        get_options(str, sizeof(ints)/sizeof(int), ints);
+        generic_DTC3181E_setup(str,ints);
+
+        return 1;
+}
+
+__setup("ncr5380=", do_NCR5380_setup);
+__setup("ncr53c400=", do_NCR53C400_setup);
+__setup("ncr53c400a=", do_NCR53C400A_setup);
+__setup("dtc3181e=", do_DTC3181E_setup);
+
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{
+		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('D','T','C'), ISAPNP_FUNCTION(0x436e), 
+		0
+	},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
 
 #endif
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c
--- v2.4.2/linux/drivers/scsi/i60uscsi.c	Thu Sep  2 10:03:26 1999
+++ linux/drivers/scsi/i60uscsi.c	Fri Mar  2 18:38:38 2001
@@ -33,7 +33,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h
--- v2.4.2/linux/drivers/scsi/i60uscsi.h	Fri Nov 12 04:29:47 1999
+++ linux/drivers/scsi/i60uscsi.h	Fri Mar  2 18:38:38 2001
@@ -33,7 +33,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i91uscsi.c linux/drivers/scsi/i91uscsi.c
--- v2.4.2/linux/drivers/scsi/i91uscsi.c	Mon Aug 23 10:23:23 1999
+++ linux/drivers/scsi/i91uscsi.c	Fri Mar  2 18:38:38 2001
@@ -34,7 +34,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/i91uscsi.h linux/drivers/scsi/i91uscsi.h
--- v2.4.2/linux/drivers/scsi/i91uscsi.h	Fri Dec 18 10:12:25 1998
+++ linux/drivers/scsi/i91uscsi.h	Fri Mar  2 18:38:38 2001
@@ -33,7 +33,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.4.2/linux/drivers/scsi/ibmmca.c	Sat Feb  3 19:51:29 2001
+++ linux/drivers/scsi/ibmmca.c	Fri Mar  2 18:38:38 2001
@@ -1594,7 +1594,7 @@
       if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
 	port = IM_IO_PORT;
       else { /* if disabled, no IRQs will be generated, as the chip won't
-	      * listen to the incomming commands and will do really nothing,
+	      * listen to the incoming commands and will do really nothing,
 	      * except for listening to the pos-register settings. If this
 	      * happens, I need to hugely think about it, as one has to
 	      * write something to the MCA-Bus pos register in order to
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ibmmca.h linux/drivers/scsi/ibmmca.h
--- v2.4.2/linux/drivers/scsi/ibmmca.h	Sun Dec 31 09:36:15 2000
+++ linux/drivers/scsi/ibmmca.h	Fri Mar  2 18:38:38 2001
@@ -1,7 +1,7 @@
 /* 
  * Low Level Driver for the IBM Microchannel SCSI Subsystem
  * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver
- * For use under the GNU public license within the Linux-kernel project.
+ * For use under the GNU General Public License within the Linux-kernel project.
  * This include file works only correctly with kernel 2.4.0 or higher!!! */
 
 #ifndef _IBMMCA_H
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c
--- v2.4.2/linux/drivers/scsi/imm.c	Mon Dec 11 13:43:20 2000
+++ linux/drivers/scsi/imm.c	Fri Mar  2 18:38:38 2001
@@ -36,7 +36,7 @@
     int mode;			/* Transfer mode                */
     int host;			/* Host number (for proc)       */
     Scsi_Cmnd *cur_cmd;		/* Current queued command       */
-    struct tq_struct imm_tq;	/* Polling interupt stuff       */
+    struct tq_struct imm_tq;	/* Polling interrupt stuff       */
     unsigned long jstart;	/* Jiffies at start             */
     unsigned failed:1;		/* Failure flag                 */
     unsigned dp:1;		/* Data phase present           */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/imm.h linux/drivers/scsi/imm.h
--- v2.4.2/linux/drivers/scsi/imm.h	Mon Dec 11 13:43:20 2000
+++ linux/drivers/scsi/imm.h	Fri Mar  2 18:38:38 2001
@@ -118,7 +118,7 @@
 #define IMM_BURST_SIZE	512	/* data burst size */
 #define IMM_SELECT_TMO  500	/* 500 how long to wait for target ? */
 #define IMM_SPIN_TMO    5000	/* 50000 imm_wait loop limiter */
-#define IMM_DEBUG	0	/* debuging option */
+#define IMM_DEBUG	0	/* debugging option */
 #define IN_EPP_MODE(x) (x == IMM_EPP_8 || x == IMM_EPP_16 || x == IMM_EPP_32)
 
 /* args to imm_connect */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v2.4.2/linux/drivers/scsi/in2000.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/in2000.c	Fri Mar  2 18:38:38 2001
@@ -681,7 +681,7 @@
          else {
             write1_io(0, IO_FIFO_READ);   /* put fifo in read mode */
             hostdata->fifo = FI_FIFO_READING;
-            cmd->SCp.have_data_in = 0;    /* nothing transfered yet */
+            cmd->SCp.have_data_in = 0;    /* nothing transferred yet */
             }
 
          }
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.4.2/linux/drivers/scsi/ini9100u.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/ini9100u.c	Fri Mar  2 18:38:38 2001
@@ -34,7 +34,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ini9100u.h linux/drivers/scsi/ini9100u.h
--- v2.4.2/linux/drivers/scsi/ini9100u.h	Mon Dec 11 13:19:45 2000
+++ linux/drivers/scsi/ini9100u.h	Fri Mar  2 18:38:38 2001
@@ -33,7 +33,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.4.2/linux/drivers/scsi/inia100.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/inia100.c	Fri Mar  2 18:38:38 2001
@@ -33,7 +33,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h
--- v2.4.2/linux/drivers/scsi/inia100.h	Mon Dec 11 13:19:47 2000
+++ linux/drivers/scsi/inia100.h	Fri Mar  2 18:38:38 2001
@@ -33,7 +33,7 @@
  *    derived from this software without specific prior written permission.
  *
  * Where this Software is combined with software released under the terms of 
- * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
  * combined work to also be released under the terms of the GPL, the terms
  * and conditions of this License will apply in addition to those of the
  * GPL with the exception of any terms or conditions of this License that
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- v2.4.2/linux/drivers/scsi/ips.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/ips.c	Fri Mar  2 18:38:38 2001
@@ -4831,7 +4831,7 @@
       }
 
       if (j >= 45)
-         /* error occured */
+         /* error occurred */
          return (0);
 
       PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
@@ -4855,7 +4855,7 @@
       }
 
       if (j >= 240)
-         /* error occured */
+         /* error occurred */
          return (0);
 
       ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
@@ -4920,7 +4920,7 @@
       }
 
       if (j >= 45)
-         /* error occured */
+         /* error occurred */
          return (0);
 
       PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
@@ -4944,7 +4944,7 @@
       }
 
       if (j >= 240)
-         /* error occured */
+         /* error occurred */
          return (0);
 
       ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
@@ -4961,7 +4961,7 @@
    }
 
    if (i >= 240)
-      /* error occured */
+      /* error occurred */
       return (0);
 
    /* setup CCCR */
@@ -5011,7 +5011,7 @@
    }
 
    if (i >= 45) {
-      /* error occured */
+      /* error occurred */
       printk(KERN_WARNING "(%s%d) timeout waiting for post.\n",
              ips_name, ha->host_num);
 
@@ -5042,7 +5042,7 @@
    }
 
    if (i >= 240) {
-      /* error occured */
+      /* error occurred */
       printk(KERN_WARNING "(%s%d) timeout waiting for config.\n",
              ips_name, ha->host_num);
 
@@ -5657,7 +5657,7 @@
       } else if (intr == IPS_INTR_IORL) {
          if (ha->waitflag == FALSE) {
             /*
-             * controller generated an interupt to
+             * controller generated an interrupt to
              * acknowledge completion of the command
              * and ips_intr() has serviced the interrupt.
              */
@@ -5681,7 +5681,7 @@
       } else if (intr == IPS_INTR_HAL) {
          if (ha->waitflag == FALSE) {
             /*
-             * controller generated an interupt to
+             * controller generated an interrupt to
              * acknowledge completion of the command
              * and ips_intr() has serviced the interrupt.
              */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/mac_esp.c linux/drivers/scsi/mac_esp.c
--- v2.4.2/linux/drivers/scsi/mac_esp.c	Wed Feb 21 18:20:32 2001
+++ linux/drivers/scsi/mac_esp.c	Fri Mar  2 18:38:38 2001
@@ -67,7 +67,7 @@
 
 volatile unsigned char cmd_buffer[16];
 				/* This is where all commands are put
-				 * before they are transfered to the ESP chip
+				 * before they are transferred to the ESP chip
 				 * via PIO.
 				 */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.4.2/linux/drivers/scsi/megaraid.c	Sat Feb  3 19:51:29 2001
+++ linux/drivers/scsi/megaraid.c	Tue Mar  6 19:44:37 2001
@@ -2,25 +2,24 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 1999 American Megatrends Inc.
+ * Copyright 2001  American Megatrends Inc.
  *
  *              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 : 1.07b
- * 
+ * Version : v1.14g (Feb 5, 2001)
+ *
  * Description: Linux device driver for AMI MegaRAID controller
  *
- * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490
- * 
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490
+ *                                      493.
  * History:
  *
  * Version 0.90:
  *     Original source contributed by Dell; integrated it into the kernel and
  *     cleaned up some things.  Added support for 438/466 controllers.
- *
  * Version 0.91:
  *     Aligned mailbox area on 16-byte boundry.
  *     Added schedule() at the end to properly clean up.
@@ -42,10 +41,10 @@
  *     8 Oct 98        Alan Cox <alan.cox@linux.org>
  *
  *     Merged with 2.1.131 source tree.
- *     12 Dec 98       K. Baranowski <kgb@knm.org.pl>                          
+ *     12 Dec 98       K. Baranowski <kgb@knm.org.pl>
  *
  * Version 0.93:
- *     Added support for vendor specific ioctl commands (0x80+xxh)
+ *     Added support for vendor specific ioctl commands (M_RD_IOCTL_CMD+xxh)
  *     Changed some fields in MEGARAID struct to better values.
  *     Added signature check for Rp controllers under 2.0 kernels
  *     Changed busy-wait loop to be time-based
@@ -74,9 +73,7 @@
  *
  * Version 0.97:
  *     Changed megaraid_command to use wait_queue.
- *     Fixed bug of undesirably detecting HP onboard controllers which
- *       are disabled.
- *     
+ *
  * Version 1.00:
  *     Checks to see if an irq ocurred while in isr, and runs through
  *       routine again.
@@ -89,13 +86,13 @@
  *
  * Version 1.01:
  *     Fixed bug in mega_cmd_done() for megamgr control commands,
- *       the host_byte in the result code from the scsi request to 
- *       scsi midlayer is set to DID_BAD_TARGET when adapter's 
- *       returned codes are 0xF0 and 0xF4.  
+ *       the host_byte in the result code from the scsi request to
+ *       scsi midlayer is set to DID_BAD_TARGET when adapter's
+ *       returned codes are 0xF0 and 0xF4.
  *
  * Version 1.02:
  *     Fixed the tape drive bug by extending the adapter timeout value
- *       for passthrough command to 60 seconds in mega_build_cmd(). 
+ *       for passthrough command to 60 seconds in mega_build_cmd().
  *
  * Version 1.03:
  *    Fixed Madrona support.
@@ -104,7 +101,7 @@
  *    Added driver version printout at driver loadup time
  *
  * Version 1.04
- *    Added code for 40 ld FW support. 
+ *    Added code for 40 ld FW support.
  *    Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
  *      data area greater than 4 KB, which is the upper bound for data
  *      tranfer through scsi_ioctl interface.
@@ -119,15 +116,182 @@
  *    Fixed the problem of unnecessary aborts in the abort entry point, which
  *      also enables the driver to handle large amount of I/O requests for
  *      long duration of time.
- *
+ * Version 1.06
+ *              Intel Release
  * Version 1.07
  *    Removed the usage of uaccess.h file for kernel versions less than
  *    2.0.36, as this file is not present in those versions.
  *
- * Version 1.07b
- *    The MegaRAID 466 cards with 3.00 firmware lockup and seem to very
- *    occasionally hang. We check such cards and report them. You can
- *    get firmware upgrades to flash the board to 3.10 for free.
+ * Version 108
+ *    Modified mega_ioctl so that 40LD megamanager would run
+ *    Made some changes for 2.3.XX compilation , esp wait structures
+ *    Code merge between 1.05 and 1.06 .
+ *    Bug fixed problem with ioctl interface for concurrency between
+ *    8ld and 40ld firwmare
+ *    Removed the flawed semaphore logic for handling new config command
+ *    Added support for building own scatter / gather list for big user
+ *    mode buffers
+ *    Added /proc file system support ,so that information is available in
+ *    human readable format
+ *
+ * Version 1a08
+ *    Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag
+ *
+ * Version 1b08
+ *    Include file changes.
+ * Version 1b08b
+ *    Change PCI ID value for the 471 card, use #defines when searching
+ *    for megaraid cards.
+ *
+ * Version 1.10
+ *
+ *      I) Changes made to make following ioctl commands work in 0x81 interface
+ *              a)DCMD_DELETE_LOGDRV
+ *              b)DCMD_GET_DISK_CONFIG
+ *              c)DCMD_DELETE_DRIVEGROUP
+ *              d)NC_SUBOP_ENQUIRY3
+ *              e)DCMD_CHANGE_LDNO
+ *              f)DCMD_CHANGE_LOOPID
+ *              g)DCMD_FC_READ_NVRAM_CONFIG
+ *      h)DCMD_WRITE_CONFIG
+ *      II) Added mega_build_kernel_sg function
+ *  III)Firmware flashing option added
+ *
+ * Version 1.10a
+ *
+ *      I)Dell updates included in the source code.
+ *              Note:   This change is not tested due to the unavailability of IA64 kernel
+ *      and it is in the #ifdef DELL_MODIFICATION macro which is not defined
+ *
+ * Version 1.10b
+ *
+ *      I)In M_RD_IOCTL_CMD_NEW command the wrong way of copying the data
+ *    to the user address corrected
+ *
+ * Version 1.10c
+ *
+ *      I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes.
+ *
+ * Version 1.11
+ *      I)  Version number changed from 1.10c to 1.11
+ *  II) DCMD_WRITE_CONFIG(0x0D) command in the driver changed from
+ *      scatter/gather list mode to direct pointer mode..
+ *     Fixed bug of undesirably detecting HP onboard controllers which
+ *       are disabled.
+ *
+ *      Version 1.12 (Sep 21, 2000)
+ *
+ *     I. Changes have been made for Dynamic DMA mapping in IA64 platform.
+ *                To enable all these changes define M_RD_DYNAMIC_DMA_SUPPORT in megaraid.h
+ *        II. Got rid of windows mode comments
+ *       III. Removed unwanted code segments
+ *    IV. Fixed bug of HP onboard controller information (commented with
+ *                 MEGA_HP_FIX)
+ *
+ *      Version 1a12
+ *      I.      reboot notifer and new ioctl changes ported from 1c09
+ *
+ *      Veriosn 1b12
+ *      I.      Changes in new ioctl interface routines ( Nov 06, 2000 )
+ *
+ *      Veriosn 1c12
+ *      I.      Changes in new ioctl interface routines ( Nov 07, 2000 )
+ *
+ *      Veriosn 1d12
+ *      I.      Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
+ *
+ *      Veriosn 1e12, 1f12
+ *      1.  Fixes for pci_map_single, pci_alloc_consistent along with mailbox
+ *          alignment
+ *
+ *	Version 1.13beta
+ *	Added Support for Full 64bit address space support. If firmware
+ *	supports 64bit, it goes to 64 bit mode even on x86 32bit 
+ *	systems. Data Corruption Issues while running on test9 kernel
+ *	on IA64 systems. This issue not seen on test11 on x86 system
+ *
+ *	Version 1.13c
+ *	1. Resolved Memory Leak when using M_RD_IOCTL_CMD interface
+ *	2. Resolved Queuing problem when MailBox Blocks
+ *	3. Added unregister_reboot_notifier support
+ * 
+ *	Version 1.13d
+ *	Experimental changes in interfacing with the controller in ISR
+ *
+ *	Version 1.13e
+ *	Fixed Broken 2.2.XX compilation changes + misc changes
+ *
+ *	Version 1.13f to 1.13i
+ *	misc changes + code clean up
+ *	Cleaned up the ioctl code and added set_mbox_xfer_addr()
+ *	Support for START_DEV (6)
+ * 	
+ *	Version 1.13j
+ *	Moved some code to megaraid.h file, replaced some hard coded values 
+ *      with respective macros. Chaged some funtions to static
+ *
+ *	Version 1.13k
+ *	Only some idendation correction to 1.13j 
+ *
+ *	Version 1.13l , 1.13m, 1.13n, 1.13o
+ *	Minor Identation changes + misc changes
+ *
+ *	Version 1.13q
+ *	Paded the new uioctl_t MIMD structure for maintaining alignment 
+ *	and size across 32 / 64 bit platforms
+ *	Changed the way MIMD IOCTL interface used virt_to_bus() to use pci
+ *	memory location
+ *
+ *	Version 1.13r
+ *	2.4.xx SCSI Changes.
+ *
+ *	Version 1.13s
+ *	Stats counter fixes
+ *	Temporary fix for some 64 bit firmwares in 2.4.XX kernels
+ *
+ *	Version	1.13t
+ *	Support for 64bit version of READ/WRITE/VIEW DISK CONFIG
+ *
+ *	Version 1.14
+ *	Did away with MEGADEV_IOCTL flag. It is now standard part of driver
+ *	without need for a special #define flag
+ *	Disabled old scsi ioctl path for kernel versions > 2.3.xx. This is due
+ *	to the nature in which the new scsi code queues a new scsi command to 
+ *	controller during SCSI IO Completion
+ *	Driver now checks for sub-system vendor id before taking ownership of
+ *	the controller
+ *
+ *	Version 1.14a
+ *	Added Host re-ordering
+ *
+ *	Version 1.14b
+ *	Corrected some issue which caused the older cards not to work
+ *	
+ *	Version 1.14c
+ *	IOCTL changes for not handling the non-64bit firmwares under 2.4.XX
+ *	kernel
+ *
+ *	Version 1.14d
+ *	Fixed Various MIMD Synchronization Issues
+ *	
+ *	Version 1.14e
+ *	Fixed the error handling during card initialization
+ *
+ *	Version 1.14f
+ *	Multiple invocations of mimd phase I ioctl stalls the cpu. Replaced
+ *	spinlock with semaphore(mutex)
+ *
+ *	Version 1.14g
+ *	Fixed running out of scbs issues while running MIMD apps under heavy IO
+ *
+ *	Version 1.14g-ac - 02/03/01
+ *	Reformatted to Linux format so I could compare to old one and cross
+ *	check bug fixes
+ *	Re fixed the assorted missing 'static' cases
+ *	Removed some unneeded version checks
+ *	Cleaned up some of the VERSION checks in the code
+ *	Left 2.0 support but removed 2.1.x support.
+ *	Collected much of the compat glue into one spot
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -135,31 +299,23 @@
  *
  *     Timeout period for upper scsi layer, i.e. SD_TIMEOUT in
  *     /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT
- *     value must be increased to (30 * HZ) otherwise false timeouts 
+ *     value must be increased to (30 * HZ) otherwise false timeouts
  *     will occur in the upper layer.
  *
+ *     Never set skip_id. The existing PCI code the megaraid uses fails
+ *     to properly check the vendor subid in some cases. Setting this then
+ *     makes it steal other i960's and crashes some boxes
+ *
+ *     Far too many ifdefs for versions.
+ *
  *===================================================================*/
 
-#define CRLFSTR "\n"
-#define IOCTL_CMD_NEW  0x81
-
-#define MEGARAID_VERSION "v107 (December 22, 1999)"
-
-
+#include <linux/config.h>
 #include <linux/version.h>
-
-#ifdef MODULE
 #include <linux/module.h>
-
-char kernel_version[] = UTS_RELEASE;
-
-MODULE_AUTHOR ("American Megatrends Inc.");
-MODULE_DESCRIPTION ("AMI MegaRAID driver");
-#endif
-
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
@@ -170,83 +326,117 @@
 #include <linux/wait.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
 
+#include <linux/sched.h>
 #include <linux/stat.h>
+#include <linux/malloc.h>	/* for kmalloc() */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+#include <linux/bios32.h>
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/* 0x20300 */
+#include <asm/spinlock.h>
+#else
 #include <linux/spinlock.h>
+#endif
+#endif
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#if LINUX_VERSION_CODE > 0x020024
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24)	/* 0x020024 */
 #include <asm/uaccess.h>
 #endif
 
+/*
+ * These header files are required for Shutdown Notification routines
+ */
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
 
 #include "megaraid.h"
 
-/*================================================================
- *
- *                          #Defines
- *
+/*
+ *================================================================
+ *  #Defines
  *================================================================
  */
 
 #define MAX_SERBUF 160
 #define COM_BASE 0x2f8
 
-
-u32 RDINDOOR (mega_host_config * megaCfg)
+static ulong RDINDOOR (mega_host_config * megaCfg)
 {
-  return readl (megaCfg->base + 0x20);
+	return readl (megaCfg->base + 0x20);
 }
 
-void WRINDOOR (mega_host_config * megaCfg, u32 value)
+static void WRINDOOR (mega_host_config * megaCfg, ulong value)
 {
-  writel (value, megaCfg->base + 0x20);
+	writel (value, megaCfg->base + 0x20);
 }
 
-u32 RDOUTDOOR (mega_host_config * megaCfg)
+static ulong RDOUTDOOR (mega_host_config * megaCfg)
 {
-  return readl (megaCfg->base + 0x2C);
+	return readl (megaCfg->base + 0x2C);
 }
 
-void WROUTDOOR (mega_host_config * megaCfg, u32 value)
+static void WROUTDOOR (mega_host_config * megaCfg, ulong value)
 {
-  writel (value, megaCfg->base + 0x2C);
+	writel (value, megaCfg->base + 0x2C);
 }
 
-/*================================================================
- *
- *                    Function prototypes
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
+
+/*
+ *	Linux 2.4 and higher
  *
- *================================================================
+ *	No driver private lock
+ *	Use the io_request_lock not cli/sti
+ *	queue task is a simple api without irq forms
  */
-static int __init megaraid_setup(char *);
 
-static int megaIssueCmd (mega_host_config * megaCfg,
-			 u_char * mboxData,
-			 mega_scb * scb,
-			 int intr);
-static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
-			 u32 * buffer, u32 * length);
-
-static int mega_busyWaitMbox(mega_host_config *);
-static void mega_runpendq (mega_host_config *);
-static void mega_rundoneq (mega_host_config *);
-static void mega_cmd_done (mega_host_config *, mega_scb *, int);
-static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
-static inline void mega_freeSgList(mega_host_config *megaCfg);
-static void mega_Convert8ldTo40ld(  mega_RAIDINQ  *inquiry,
-                                    mega_Enquiry3 *enquiry3,
-                                    megaRaidProductInfo *productInfo );
+#include <linux/smp.h>
+#define cpuid smp_processor_id()
+
+char kernel_version[] = UTS_RELEASE;
+MODULE_AUTHOR ("American Megatrends Inc.");
+MODULE_DESCRIPTION ("AMI MegaRAID driver");
 
+#define DRIVER_LOCK_T
+#define DRIVER_LOCK_INIT(p)
+#define DRIVER_LOCK(p)
+#define DRIVER_UNLOCK(p)
+#define IO_LOCK_T unsigned long io_flags = 0;
+#define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
+#define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
 
-#include <linux/smp.h>
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)	/* 0x020200 */
 
+/*
+ *	Linux 2.2 and higher
+ *
+ *	No driver private lock
+ *	Use the io_request_lock not cli/sti
+ *	No pci region api
+ *	queue_task is now a single simple API
+ */
+ 
+#include <linux/smp.h>
 #define cpuid smp_processor_id()
+
+char kernel_version[] = UTS_RELEASE;
+MODULE_AUTHOR ("American Megatrends Inc.");
+MODULE_DESCRIPTION ("AMI MegaRAID driver");
+
 #define DRIVER_LOCK_T
 #define DRIVER_LOCK_INIT(p)
 #define DRIVER_LOCK(p)
@@ -255,95 +445,220 @@
 #define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
 #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
 
+#define pci_free_consistent(a,b,c,d)
+#define pci_unmap_single(a,b,c,d,e)
+
+#define init_MUTEX_LOCKED(x)	((x)=MUTEX_LOCKED)
+#define init_MUTEX(x)		((x)=MUTEX)
+
+#define queue_task_irq(a,b)     queue_task(a,b)
+#define queue_task_irq_off(a,b) queue_task(a,b)
+
+#define DECLARE_WAIT_QUEUE_HEAD(x)	struct wait_queue *x = NULL
+#else
+
+/*
+ *	Linux 2.0 macros. Here we have to provide some of our own
+ *	functionality. We also only work little endian 32bit.
+ *	Again no pci_alloc/free api
+ *	IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty 
+ */
+ 
+#define cpuid 0
+#define DRIVER_LOCK_T long cpu_flags;
+#define DRIVER_LOCK_INIT(p)
+#define DRIVER_LOCK(p) \
+       		save_flags(cpu_flags); \
+       		cli();
+#define DRIVER_UNLOCK(p) \
+       		restore_flags(cpu_flags);
+#define IO_LOCK_T
+#define IO_LOCK(p)
+#define IO_UNLOCK(p)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+
+#define pci_free_consistent(a,b,c,d)
+#define pci_unmap_single(a,b,c,d,e)
+
+#define init_MUTEX_LOCKED(x)	((x)=MUTEX_LOCKED)
+#define init_MUTEX(x)		((x)=MUTEX)
+
+/*
+ *	2.0 lacks spinlocks, iounmap/ioremap
+ */
+
+#define ioremap vremap
+#define iounmap vfree
+
+ /* simulate spin locks */
+typedef struct {
+	volatile char lock;
+} spinlock_t;
+
+#define spin_lock_init(x) { (x)->lock = 0;}
+#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\
+                                        (x)->lock=1; save_flags(flags);\
+                                        cli();}
+#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
+
+#define DECLARE_WAIT_QUEUE_HEAD(x)	struct wait_queue *x = NULL
+
+#endif
+
+
+
 /* set SERDEBUG to 1 to enable serial debugging */
 #define SERDEBUG 0
 #if SERDEBUG
 static void ser_init (void);
 static void ser_puts (char *str);
 static void ser_putc (char c);
-static int ser_printk (const char *fmt,...);
+static int ser_printk (const char *fmt, ...);
 #endif
 
-/*================================================================
- *
+#ifdef CONFIG_PROC_FS
+#define COPY_BACK if (offset > megaCfg->procidx) { \
+		*eof = TRUE; \
+        megaCfg->procidx = 0; \
+        megaCfg->procbuf[0] = 0; \
+        return 0;} \
+ if ((count + offset) > megaCfg->procidx) { \
+      count = megaCfg->procidx - offset; \
+      *eof = TRUE; } \
+      memcpy(page, &megaCfg->procbuf[offset], count); \
+      megaCfg->procidx = 0; \
+      megaCfg->procbuf[0] = 0;
+#endif
+
+/*
+ * ================================================================
  *                    Global variables
- *
  *================================================================
  */
 
 /*  Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
     XX scsi id on each channel.  Used for Madrona motherboard, where SAF_TE
     processor id cannot be scanned */
+
+static char *megaraid;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)	/* 0x20100 */
 #ifdef MODULE
-static char *megaraid = NULL;
-MODULE_PARM(megaraid, "s");
+MODULE_PARM (megaraid, "s");
 #endif
-static int skip_id;
-
+#endif
+static int skip_id = -1;
 static int numCtlrs = 0;
-static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0};
+static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 };
+static struct proc_dir_entry *mega_proc_dir_entry;
 
 #if DEBUG
 static u32 maxCmdTime = 0;
 #endif
 
 static mega_scb *pLastScb = NULL;
+static struct notifier_block mega_notifier = {
+	megaraid_reboot_notify,
+	NULL,
+	0
+};
+
+/* For controller re-ordering */
+struct mega_hbas mega_hbas[MAX_CONTROLLERS];
+
+/*
+ * The File Operations structure for the serial/ioctl interface of the driver
+ */
+/* For controller re-ordering */ 
+
+static struct file_operations megadev_fops = {
+	ioctl:megadev_ioctl_entry,
+	open:megadev_open,
+	release:megadev_close,
+};
+
+/*
+ * Array to structures for storing the information about the controllers. This
+ * information is sent to the user level applications, when they do an ioctl
+ * for this information.
+ */
+static struct mcontroller mcontroller[MAX_CONTROLLERS];
+
+/* The current driver version */
+static u32 driver_ver = 114;
 
+/* major number used by the device for character interface */
+static int major;
+
+static struct semaphore mimd_ioctl_sem;
+static struct semaphore mimd_entry_mtx;
 
 #if SERDEBUG
-static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED;
+volatile static spinlock_t serial_lock;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)	/* 0x20300 */
+static struct proc_dir_entry proc_scsi_megaraid = {
+	PROC_SCSI_MEGARAID, 8, "megaraid",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry proc_root;
 #endif
 
+
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
 
-static void ser_init ()
+static void ser_init (void)
 {
-  unsigned port = COM_BASE;
+	unsigned port = COM_BASE;
 
-  outb (0x80, port + 3);
-  outb (0, port + 1);
-  /* 9600 Baud, if 19200: outb(6,port) */
-  outb (12, port);
-  outb (3, port + 3);
-  outb (0, port + 1);
+	outb (0x80, port + 3);
+	outb (0, port + 1);
+	/* 9600 Baud, if 19200: outb(6,port) */
+	outb (12, port);
+	outb (3, port + 3);
+	outb (0, port + 1);
 }
 
 static void ser_puts (char *str)
 {
-  char *ptr;
+	char *ptr;
 
-  ser_init ();
-  for (ptr = str; *ptr; ++ptr)
-    ser_putc (*ptr);
+	ser_init ();
+	for (ptr = str; *ptr; ++ptr)
+		ser_putc (*ptr);
 }
 
 static void ser_putc (char c)
 {
-  unsigned port = COM_BASE;
+	unsigned port = COM_BASE;
 
-  while ((inb (port + 5) & 0x20) == 0);
-  outb (c, port);
-  if (c == 0x0a) {
-    while ((inb (port + 5) & 0x20) == 0);
-    outb (0x0d, port);
-  }
-}
-
-static int ser_printk (const char *fmt,...)
-{
-  va_list args;
-  int i;
-  long flags;
-
-  spin_lock_irqsave(&serial_lock,flags);
-  va_start (args, fmt);
-  i = vsprintf (strbuf, fmt, args);
-  ser_puts (strbuf);
-  va_end (args);
-  spin_unlock_irqrestore(&serial_lock,flags);
+	while ((inb (port + 5) & 0x20) == 0) ;
+	outb (c, port);
+	if (c == 0x0a) {
+		while ((inb (port + 5) & 0x20) == 0) ;
+		outb (0x0d, port);
+	}
+}
+
+static int ser_printk (const char *fmt, ...)
+{
+	va_list args;
+	int i;
+	long flags;
+
+	spin_lock_irqsave (&serial_lock, flags);
+	va_start (args, fmt);
+	i = vsprintf (strbuf, fmt, args);
+	ser_puts (strbuf);
+	va_end (args);
+	spin_unlock_irqrestore (&serial_lock, flags);
 
-  return i;
+	return i;
 }
 
 #define TRACE(a)    { ser_printk a;}
@@ -352,14 +667,16 @@
 #define TRACE(A)
 #endif
 
+#define TRACE1(a)
+
 static void callDone (Scsi_Cmnd * SCpnt)
 {
-  if (SCpnt->result) {
-    TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number,
-	    SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun,
-	    SCpnt->result));
-  }
-  SCpnt->scsi_done (SCpnt);
+	if (SCpnt->result) {
+		TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n",
+			SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
+			SCpnt->target, SCpnt->lun, SCpnt->result));
+	}
+	SCpnt->scsi_done (SCpnt);
 }
 
 /*-------------------------------------------------------------------------
@@ -372,51 +689,92 @@
  * Free a SCB structure
  *=======================
  */
-static void mega_freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
+static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb)
 {
 
-  mega_scb *pScbtmp;
+	mega_scb *pScbtmp;
+
+	if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
+		return;
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	switch (pScb->dma_type) {
+	case M_RD_DMA_TYPE_NONE:
+		break;
+	case M_RD_PTHRU_WITH_BULK_DATA:
+		pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+				  pScb->pthru->dataxferlen,
+				  pScb->dma_direction);
+		break;
+	case M_RD_PTHRU_WITH_SGLIST:
+	{
+		int count;
+		for (count = 0; count < pScb->sglist_count; count++) {
+			pci_unmap_single (megaCfg->dev,
+					  pScb->dma_h_sglist[count],
+					  pScb->sgList[count].length,
+					  pScb->dma_direction);
+
+		}
+		break;
+	}
+	case M_RD_BULK_DATA_ONLY:
+		pci_unmap_single (megaCfg->dev,
+				  pScb->dma_h_bulkdata,
+				  pScb->iDataSize, pScb->dma_direction);
+
+		break;
+	case M_RD_SGLIST_ONLY:
+		pci_unmap_sg (megaCfg->dev,
+			      pScb->SCpnt->request_buffer,
+			      pScb->SCpnt->use_sg, pScb->dma_direction);
+		break;
+	default:
+		break;
+	}
+#endif
+
+	/* Unlink from pending queue */
+	if (pScb == megaCfg->qPendingH) {
+
+		if (megaCfg->qPendingH == megaCfg->qPendingT)
+			megaCfg->qPendingH = megaCfg->qPendingT = NULL;
+		else
+			megaCfg->qPendingH = megaCfg->qPendingH->next;
+
+		megaCfg->qPcnt--;
+
+	} else {
+		for (pScbtmp = megaCfg->qPendingH; pScbtmp;
+		     pScbtmp = pScbtmp->next) {
+
+			if (pScbtmp->next == pScb) {
+
+				pScbtmp->next = pScb->next;
+
+				if (pScb == megaCfg->qPendingT) {
+					megaCfg->qPendingT = pScbtmp;
+				}
+
+				megaCfg->qPcnt--;
+				break;
+			}
+		}
+	}
+
+	/* Link back into free list */
+	pScb->state = SCB_FREE;
+	pScb->SCpnt = NULL;
+
+	if (megaCfg->qFreeH == (mega_scb *) NULL) {
+		megaCfg->qFreeH = megaCfg->qFreeT = pScb;
+	} else {
+		megaCfg->qFreeT->next = pScb;
+		megaCfg->qFreeT = pScb;
+	}
 
-  if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
-    return ;
-  }
-
-  /* Unlink from pending queue */
-
-  if(pScb == megaCfg->qPendingH) {
-    if(megaCfg->qPendingH == megaCfg->qPendingT ) 
-      megaCfg->qPendingH = megaCfg->qPendingT = NULL;
-    else {
-      megaCfg->qPendingH = megaCfg->qPendingH->next;
-    }
-    megaCfg->qPcnt--;
-  }
-  else {
-    for(pScbtmp=megaCfg->qPendingH; pScbtmp; pScbtmp=pScbtmp->next) {
-      if (pScbtmp->next == pScb) {
-        pScbtmp->next = pScb->next;
-        if(pScb == megaCfg->qPendingT) {
-          megaCfg->qPendingT = pScbtmp;
-        }
-        megaCfg->qPcnt--;
-	break;
-    }
-  }
-  }
-
-  /* Link back into free list */
-  pScb->state = SCB_FREE;
-  pScb->SCpnt = NULL;
-
-  if(megaCfg->qFreeH == (mega_scb *) NULL ) {
-    megaCfg->qFreeH = megaCfg->qFreeT = pScb;
-  }
-  else {
-    megaCfg->qFreeT->next  = pScb;
-    megaCfg->qFreeT = pScb;
-  }
-  megaCfg->qFreeT->next = NULL;
-  megaCfg->qFcnt++;
+	megaCfg->qFreeT->next = NULL;
+	megaCfg->qFcnt++;
 
 }
 
@@ -424,186 +782,173 @@
  * Allocate a SCB structure
  *===========================
  */
-static mega_scb * mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb *mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
 {
-  mega_scb *pScb;
+	mega_scb *pScb;
+
+	/* Unlink command from Free List */
+	if ((pScb = megaCfg->qFreeH) != NULL) {
+		megaCfg->qFreeH = pScb->next;
+		megaCfg->qFcnt--;
+
+		pScb->isrcount = jiffies;
+		pScb->next = NULL;
+		pScb->state = SCB_ACTIVE;
+		pScb->SCpnt = SCpnt;
 
-  /* Unlink command from Free List */
-  if ((pScb = megaCfg->qFreeH) != NULL) {
-    megaCfg->qFreeH = pScb->next;
-    megaCfg->qFcnt--;
-    
-    pScb->isrcount = jiffies;
-    pScb->next  = NULL;
-    pScb->state = SCB_ACTIVE;
-    pScb->SCpnt = SCpnt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pScb->dma_type = M_RD_DMA_TYPE_NONE;
+#endif
 
-    return pScb;
-  }
+		return pScb;
+	}
 
-  printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
+	printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
 
-  return NULL;
+	return NULL;
 }
 
-/*================================================
- * Initialize SCB structures
- *================================================
- */
-static int mega_initSCB (mega_host_config * megaCfg)
+/* Run through the list of completed requests  and finish it */
+static void mega_rundoneq (mega_host_config * megaCfg)
 {
-  int idx;
+	Scsi_Cmnd *SCpnt;
 
-  megaCfg->qFreeH = NULL;
-  megaCfg->qFcnt = 0;
-#if DEBUG
-if(megaCfg->max_cmds >= MAX_COMMANDS) {
-printk("megaraid:ctlr max cmds = %x : MAX_CMDS = %x", megaCfg->max_cmds, MAX_COMMANDS);
-}
-#endif
+	while ((SCpnt = megaCfg->qCompletedH) != NULL) {
+		megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble;
+		megaCfg->qCcnt--;
+
+		SCpnt->host_scribble = (unsigned char *) NULL;	/* XC : sep 14 */
+		/* Callback */
+		callDone (SCpnt);
+	}
 
-  for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) {
-    megaCfg->scbList[idx].idx    = idx;
-    megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
-					   GFP_ATOMIC | GFP_DMA);
-    if (megaCfg->scbList[idx].sgList == NULL) {
-      printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
-      mega_freeSgList(megaCfg);
-      return -1;
-    }
-    
-    if (idx < MAX_COMMANDS) {
-      /* Link to free list */
-      mega_freeSCB(megaCfg, &megaCfg->scbList[idx]);
-    }
-  }
-  return 0;
-}
-
-/* Run through the list of completed requests */
-static void mega_rundoneq (mega_host_config *megaCfg)
-{
-  Scsi_Cmnd *SCpnt;
-
-  while ((SCpnt = megaCfg->qCompletedH) != NULL) {
-    megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
-    megaCfg->qCcnt--;
-
-    SCpnt->host_scribble = (unsigned char *) NULL ; // XC : sep 14
-    /* Callback */
-    callDone (SCpnt);
-  }
-  megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
+	megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
 }
 
 /*
  * Runs through the list of pending requests
  * Assumes that mega_lock spin_lock has been acquired.
  */
-static void mega_runpendq(mega_host_config *megaCfg)
+static int mega_runpendq (mega_host_config * megaCfg)
 {
-  mega_scb *pScb;
+	mega_scb *pScb;
+	int rc;
 
-  /* Issue any pending commands to the card */
-  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
-    if (pScb->state == SCB_ACTIVE) {
-      if(megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1))
-	return;
-    }
-  }
+	/* Issue any pending commands to the card */
+	for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
+		if (pScb->state == SCB_ACTIVE) {
+			if ((rc =
+			     megaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) == -1)
+				return rc;
+		}
+	}
+	return 0;
 }
 
 /* Add command to the list of completed requests */
-static void
-mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
-			   int status)
+
+static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
 {
-  int islogical;
-  Scsi_Cmnd *SCpnt;
-  mega_passthru *pthru;
-  mega_mailbox *mbox;
-
-  if (pScb == NULL) {
-	TRACE(("NULL pScb in mega_cmd_done!"));
-	printk("NULL pScb in mega_cmd_done!");
-  }
-
-  SCpnt = pScb->SCpnt;
-  pthru = &pScb->pthru;
-  mbox = (mega_mailbox *) &pScb->mboxData;
-
-  if (SCpnt == NULL) {
-	TRACE(("NULL SCpnt in mega_cmd_done!"));
-	TRACE(("pScb->idx = ",pScb->idx));
-	TRACE(("pScb->state = ",pScb->state));
-	TRACE(("pScb->state = ",pScb->state));
-	printk("megaraid:Problem...!\n");
-	while(1);
-  }
-
-  islogical = (SCpnt->channel == megaCfg->host->max_channel);
-
-  if (SCpnt->cmnd[0] == INQUIRY &&
-      ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
-      !islogical) {
-    status = 0xF0;
-  }
-
-/* clear result; otherwise, success returns corrupt value */ 
- SCpnt->result = 0;  
-
-if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/
-    switch (status) {
-      case 0xF0:
-      case 0xF4:
-	SCpnt->result=(DID_BAD_TARGET<<16)|status;
-        break;
-      default:
-	SCpnt->result|=status;
-   }/*end of switch*/
-}
-else{
-  /* Convert MegaRAID status to Linux error code */
-  switch (status) {
-  case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD*/
-    SCpnt->result |= (DID_OK << 16);
-    break;
-  case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
-	/*set sense_buffer and result fields*/
-       if( mbox->cmd==MEGA_MBOXCMD_PASSTHRU ){
-	  memcpy( SCpnt->sense_buffer , pthru->reqsensearea, 14);
-          SCpnt->result = (DRIVER_SENSE<<24)|(DID_ERROR << 16)|status; 
-       }
-       else{
- 	  SCpnt->sense_buffer[0]=0x70;
-	  SCpnt->sense_buffer[2]=ABORTED_COMMAND;
-          SCpnt->result |= (CHECK_CONDITION << 1);
-       }
-    break;
-  case 0x08:  /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
-    SCpnt->result |= (DID_BUS_BUSY << 16)|status;
-    break;
-  default: 
-    SCpnt->result |= (DID_BAD_TARGET << 16)|status;
-    break;
-  }
- }
-  if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW ) 
-  /* not IOCTL_CMD_NEW SCB, freeSCB()*/
-  /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
-   * after copy data back to user space*/
-     mega_freeSCB(megaCfg, pScb);
-
-  /* Add Scsi_Command to end of completed queue */
-    if( megaCfg->qCompletedH == NULL ) {
-      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
-    }
-    else {
-      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
-      megaCfg->qCompletedT = SCpnt;
-   }
-   megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
-   megaCfg->qCcnt++;
+	int islogical;
+	Scsi_Cmnd *SCpnt;
+	mega_passthru *pthru;
+	mega_mailbox *mbox;
+
+	if (pScb == NULL) {
+		TRACE (("NULL pScb in mega_cmd_done!"));
+		printk(KERN_CRIT "NULL pScb in mega_cmd_done!");
+	}
+
+	SCpnt = pScb->SCpnt;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pthru = pScb->pthru;
+#else
+	pthru = &pScb->pthru;
+#endif
+
+	mbox = (mega_mailbox *) & pScb->mboxData;
+
+	if (SCpnt == NULL) {
+		TRACE (("NULL SCpnt in mega_cmd_done!"));
+		TRACE (("pScb->idx = ", pScb->idx));
+		TRACE (("pScb->state = ", pScb->state));
+		TRACE (("pScb->state = ", pScb->state));
+		panic(KERN_ERR "megaraid:Problem...!\n");
+	}
+
+	islogical = (SCpnt->channel == megaCfg->host->max_channel);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* Special Case to handle PassThrough->XferAddrress > 4GB */
+	switch (SCpnt->cmnd[0]) {
+	case INQUIRY:
+	case READ_CAPACITY:
+		memcpy (SCpnt->request_buffer,
+			pScb->bounce_buffer, SCpnt->request_bufflen);
+		break;
+	}
+#endif
+
+	mega_freeSCB (megaCfg, pScb);
+
+	if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
+		status = 0xF0;
+	}
+
+	/* 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 */
+		switch (status) {
+		case 2:
+		case 0xF0:
+		case 0xF4:
+			SCpnt->result = (DID_BAD_TARGET << 16) | status;
+			break;
+		default:
+			SCpnt->result |= status;
+		}		/*end of switch */
+	} else {
+		/* Convert MegaRAID status to Linux error code */
+		switch (status) {
+		case 0x00:	/* SUCCESS , i.e. SCSI_STATUS_GOOD */
+			SCpnt->result |= (DID_OK << 16);
+			break;
+
+		case 0x02:	/* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
+
+			/*set sense_buffer and result fields */
+			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
+				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;
+			} else {
+				SCpnt->sense_buffer[0] = 0x70;
+				SCpnt->sense_buffer[2] = ABORTED_COMMAND;
+				SCpnt->result |= (CHECK_CONDITION << 1);
+			}
+			break;
+
+		case 0x08:	/* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
+			SCpnt->result |= (DID_BUS_BUSY << 16) | status;
+			break;
+
+		default:
+			SCpnt->result |= (DID_BAD_TARGET << 16) | status;
+			break;
+		}
+	}
+
+	/* Add Scsi_Command to end of completed queue */
+	if (megaCfg->qCompletedH == NULL) {
+		megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+	} else {
+		megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
+		megaCfg->qCompletedT = SCpnt;
+	}
+
+	megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+	megaCfg->qCcnt++;
 }
 
 /*-------------------------------------------------------------------
@@ -614,491 +959,859 @@
  * If NULL is returned, the scsi_done function MUST have been called
  *
  *-------------------------------------------------------------------*/
-static mega_scb * mega_build_cmd (mega_host_config * megaCfg, 
-				  Scsi_Cmnd * SCpnt)
-{
-  mega_scb *pScb;
-  mega_mailbox *mbox;
-  mega_passthru *pthru;
-  long seg;
-  char islogical;
-  char lun = SCpnt->lun;
 
-  if ((SCpnt->cmnd[0] == 0x80)  || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) )  /* ioctl */
-    return mega_ioctl (megaCfg, SCpnt);
- 
-  islogical = (SCpnt->channel == megaCfg->host->max_channel);
+static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+	mega_scb *pScb;
+	mega_mailbox *mbox;
+	mega_passthru *pthru;
+	long seg;
+	char islogical;
+	char lun = SCpnt->lun;
+
+	if ((SCpnt->cmnd[0] == MEGADEVIOC))
+		return megadev_doioctl (megaCfg, SCpnt);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+	if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD)
+	    || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW))
+		return mega_ioctl (megaCfg, SCpnt);	/* Handle IOCTL command */
+#endif
 
-  if (!islogical && lun != 0) {
-    SCpnt->result = (DID_BAD_TARGET << 16);
-    callDone (SCpnt);
-    return NULL;
-  }
+	islogical = (SCpnt->channel == megaCfg->host->max_channel);
 
-  if (!islogical && SCpnt->target == skip_id) {
-	SCpnt->result = (DID_BAD_TARGET << 16);
-	callDone (SCpnt);
-	return NULL;
-  }
+	if (!islogical && lun != 0) {
+		SCpnt->result = (DID_BAD_TARGET << 16);
+		callDone (SCpnt);
+		return NULL;
+	}
 
-  if ( islogical ) {
-	lun = (SCpnt->target * 8) + lun;
-        if ( lun > FC_MAX_LOGICAL_DRIVES ){
-            SCpnt->result = (DID_BAD_TARGET << 16);
-            callDone (SCpnt);
-            return NULL;
-        }
-  }
-  /*-----------------------------------------------------
-   *
-   *               Logical drive commands
-   *
-   *-----------------------------------------------------*/
-  if (islogical) {
-    switch (SCpnt->cmnd[0]) {
-    case TEST_UNIT_READY:
-      memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen);
-      SCpnt->result = (DID_OK << 16);
-      callDone (SCpnt);
-      return NULL;
-
-    case MODE_SENSE:
-      memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
-      SCpnt->result = (DID_OK << 16);
-      callDone (SCpnt);
-      return NULL;
-
-    case READ_CAPACITY:
-    case INQUIRY:
-      /* Allocate a SCB and initialize passthru */
-      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
-	SCpnt->result = (DID_ERROR << 16);
-	callDone (SCpnt);
-	return NULL;
-      }
-      pthru = &pScb->pthru;
-      mbox = (mega_mailbox *) & pScb->mboxData;
-
-      memset (mbox, 0, sizeof (pScb->mboxData));
-      memset (pthru, 0, sizeof (mega_passthru));
-      pthru->timeout = 0;
-      pthru->ars = 1;
-      pthru->reqsenselen = 14;
-      pthru->islogical = 1;
-      pthru->logdrv = lun;
-      pthru->cdblen = SCpnt->cmd_len;
-      pthru->dataxferaddr = virt_to_bus (SCpnt->request_buffer);
-      pthru->dataxferlen = SCpnt->request_bufflen;
-      memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
-      /* Initialize mailbox area */
-      mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
-      mbox->xferaddr = virt_to_bus (pthru);
-
-      return pScb;
-
-    case READ_6:
-    case WRITE_6:
-    case READ_10:
-    case WRITE_10:
-      /* Allocate a SCB and initialize mailbox */
-      if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
-	SCpnt->result = (DID_ERROR << 16);
-	callDone (SCpnt);
-	return NULL;
-      }
-      mbox = (mega_mailbox *) & pScb->mboxData;
+	if (!islogical && SCpnt->target == skip_id) {
+		SCpnt->result = (DID_BAD_TARGET << 16);
+		callDone (SCpnt);
+		return NULL;
+	}
 
-      memset (mbox, 0, sizeof (pScb->mboxData));
-      mbox->logdrv = lun;
-      mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ?
-	MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE;
-
-      /* 6-byte */
-      if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
-	mbox->numsectors =
-	  (u32) SCpnt->cmnd[4];
-	mbox->lba =
-	  ((u32) SCpnt->cmnd[1] << 16) |
-	  ((u32) SCpnt->cmnd[2] << 8) |
-	  (u32) SCpnt->cmnd[3];
-	mbox->lba &= 0x1FFFFF;
-      }
-
-      /* 10-byte */
-      if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
-	mbox->numsectors =
-	  (u32) SCpnt->cmnd[8] |
-	  ((u32) SCpnt->cmnd[7] << 8);
-	mbox->lba =
-	  ((u32) SCpnt->cmnd[2] << 24) |
-	  ((u32) SCpnt->cmnd[3] << 16) |
-	  ((u32) SCpnt->cmnd[4] << 8) |
-	  (u32) SCpnt->cmnd[5];
-      }
-
-      /* Calculate Scatter-Gather info */
-      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
-					  (u32 *) & mbox->xferaddr,
-					  (u32 *) & seg);
-
-      return pScb;
-
-    default:
-      SCpnt->result = (DID_BAD_TARGET << 16);
-      callDone (SCpnt);
-      return NULL;
-    }
-  }
-  /*-----------------------------------------------------
-   *
-   *               Passthru drive commands
-   *
-   *-----------------------------------------------------*/
-  else {
-    /* Allocate a SCB and initialize passthru */
-    if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
-      SCpnt->result = (DID_ERROR << 16);
-      callDone (SCpnt);
-      return NULL;
-    }
-    pthru = &pScb->pthru;
-    mbox = (mega_mailbox *) pScb->mboxData;
-
-    memset (mbox, 0, sizeof (pScb->mboxData));
-    memset (pthru, 0, sizeof (mega_passthru));
-    pthru->timeout = 2; /*set adapter timeout value to 10 min. for tape drive*/
-     		        /* 0=6sec/1=60sec/2=10min/3=3hrs */
-    pthru->ars = 1;
-    pthru->reqsenselen = 14;
-    pthru->islogical = 0;
-    pthru->channel = (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
-    pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD*/
-                     (SCpnt->channel<<4)|SCpnt->target : SCpnt->target;
-    pthru->cdblen = SCpnt->cmd_len;
-    memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
-
-    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-					 (u32 *) & pthru->dataxferaddr,
-					 (u32 *) & pthru->dataxferlen);
-
-    /* Initialize mailbox */
-    mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
-    mbox->xferaddr = virt_to_bus (pthru);
-
-    return pScb;
-  }
-  return NULL;
-}
+	if (islogical) {
+		lun = (SCpnt->target * 8) + lun;
+		if (lun > FC_MAX_LOGICAL_DRIVES) {
+			SCpnt->result = (DID_BAD_TARGET << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+	}
+	/*-----------------------------------------------------
+	 *
+	 *               Logical drive commands
+	 *
+	 *-----------------------------------------------------*/
+	if (islogical) {
+		switch (SCpnt->cmnd[0]) {
+		case TEST_UNIT_READY:
+			memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen);
+			SCpnt->result = (DID_OK << 16);
+			callDone (SCpnt);
+			return NULL;
+
+		case MODE_SENSE:
+			memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]);
+			SCpnt->result = (DID_OK << 16);
+			callDone (SCpnt);
+			return NULL;
+
+		case READ_CAPACITY:
+		case INQUIRY:
+			/* Allocate a SCB and initialize passthru */
+			if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+				SCpnt->result = (DID_ERROR << 16);
+				callDone (SCpnt);
+				return NULL;
+			}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pthru = pScb->pthru;
+#else
+			pthru = &pScb->pthru;
+#endif
 
-/*--------------------------------------------------------------------
- * build RAID commands for controller, passed down through ioctl()
- *--------------------------------------------------------------------*/
-static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
-{
-  mega_scb *pScb;
-  mega_ioctl_mbox *mbox;
-  mega_mailbox *mailbox;
-  mega_passthru *pthru;
-  u8 *mboxdata;
-  long seg;
-  unsigned char *data = (unsigned char *)SCpnt->request_buffer;
-  int i;
-
-  if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
-    SCpnt->result = (DID_ERROR << 16);
-    callDone (SCpnt);
-    return NULL;
-  }
-
-  mboxdata = (u8 *) & pScb->mboxData;
-  mbox = (mega_ioctl_mbox *) & pScb->mboxData;
-  mailbox = (mega_mailbox *) & pScb->mboxData;
-  memset (mailbox, 0, sizeof (pScb->mboxData));
-
-  if (data[0] == 0x03) {	/* passthrough command */
-    unsigned char cdblen = data[2];
-    pthru = &pScb->pthru;
-    memset (pthru, 0, sizeof (mega_passthru));
-    pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0;
-    pthru->timeout = data[cdblen+3] & 0x07;
-    pthru->reqsenselen = 14;
-    pthru->ars = (data[cdblen+3] & 0x08) ? 1:0;
-    pthru->logdrv = data[cdblen+4];
-    pthru->channel = data[cdblen+5];
-    pthru->target = data[cdblen+6];
-    pthru->cdblen = cdblen;
-    memcpy (pthru->cdb, &data[3], cdblen);
-
-    mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
-    mailbox->xferaddr = virt_to_bus (pthru);
-
-    pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-					 (u32 *) & pthru->dataxferaddr,
-					 (u32 *) & pthru->dataxferlen);
-
-    for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) {
-       data[i] = data[i+cdblen+7];
-    }
-
-    return pScb;
-  }
-  /* else normal (nonpassthru) command */
+			mbox = (mega_mailbox *) & pScb->mboxData;
+			memset (mbox, 0, sizeof (pScb->mboxData));
+			memset (pthru, 0, sizeof (mega_passthru));
+			pthru->timeout = 0;
+			pthru->ars = 1;
+			pthru->reqsenselen = 14;
+			pthru->islogical = 1;
+			pthru->logdrv = lun;
+			pthru->cdblen = SCpnt->cmd_len;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			/*Not sure about the direction */
+			pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+			pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+
+#if 0
+/* Normal Code w/o the need for bounce buffer */
+			pScb->dma_h_bulkdata
+			    = pci_map_single (megaCfg->dev,
+					      SCpnt->request_buffer,
+					      SCpnt->request_bufflen,
+					      pScb->dma_direction);
 
-#if LINUX_VERSION_CODE > 0x020024
-/*
- * usage of the function copy from user is used in case of data more than
- * 4KB.  This is used only with adapters which supports more than 8 logical
- * drives.  This feature is disabled on kernels earlier or same as 2.0.36
- * as the uaccess.h file is not available with those kernels.
- */
+			pthru->dataxferaddr = pScb->dma_h_bulkdata;
+#else
+/* Special Code to use bounce buffer for READ_CAPA/INQ */
+			pthru->dataxferaddr = pScb->dma_bounce_buffer;
+			pScb->dma_type = M_RD_DMA_TYPE_NONE;
+#endif
 
-  if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { 
-            /* use external data area for large xfers  */
-     /* If cmnd[0] is set to IOCTL_CMD_NEW then *
-      *   cmnd[4..7] = external user buffer     *
-      *   cmnd[8..11] = length of buffer        *
-      *                                         */
-      char *kern_area;
-      char *user_area = *((char **)&SCpnt->cmnd[4]);
-      u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]);
-      if (verify_area(VERIFY_READ, user_area, xfer_size)) {
-          printk("megaraid: Got bad user address.\n");
-          SCpnt->result = (DID_ERROR << 16);
-          callDone (SCpnt);
-          return NULL;
-      }
-      kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA);
-      if (kern_area == NULL) {
-          printk("megaraid: Couldn't allocate kernel mem.\n");
-	  SCpnt->result = (DID_ERROR << 16);
-	  callDone (SCpnt);
-	  return NULL;
-      }
-      copy_from_user(kern_area,user_area,xfer_size);
-      pScb->kern_area = kern_area;
-  }
-#endif
-
-  mbox->cmd = data[0];
-  mbox->channel = data[1];
-  mbox->param = data[2];
-  mbox->pad[0] = data[3];
-  mbox->logdrv = data[4];
-
-  if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
-      if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */
-          *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/
-          *(mboxdata+2) = data[2]; /*sub command*/
-          *(mboxdata+3) = 0;       /*number of elements in SG list*/
-          mbox->xferaddr           /*i.e. mboxdata byte 0x8 to 0xb*/
-                        = virt_to_bus(pScb->kern_area);
-      }
-      else{
-         mbox->xferaddr = virt_to_bus(pScb->kern_area);
-         mbox->numsgelements = 0;
-      }
-  } 
-  else {
-
-      mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
-				      (u32 *) & mbox->xferaddr,
-				      (u32 *) & seg);
-
-      for (i=0;i<(SCpnt->request_bufflen-6);i++) {
-          data[i] = data[i+6];
-      }
-  }
+#else
+			pthru->dataxferaddr =
+			    virt_to_bus (SCpnt->request_buffer);
+#endif
 
-  return (pScb);
-}
+			pthru->dataxferlen = SCpnt->request_bufflen;
+			memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
 
-#if DEBUG
-static void showMbox(mega_scb *pScb)
-{
-  mega_mailbox *mbox;
+			/* Initialize mailbox area */
+			mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
 
-  if (pScb == NULL) return;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			mbox->xferaddr = pScb->dma_passthruhandle64;
+			TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
+#else
+			mbox->xferaddr = virt_to_bus (pthru);
+#endif
+			return pScb;
 
-  mbox = (mega_mailbox *)pScb->mboxData;
-  printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
-	 pScb->SCpnt->pid, 
-	 mbox->cmd, mbox->cmdid, mbox->numsectors,
-	 mbox->lba, mbox->xferaddr, mbox->logdrv,
-	 mbox->numsgelements);
-}
+		case READ_6:
+		case WRITE_6:
+		case READ_10:
+		case WRITE_10:
+			/* Allocate a SCB and initialize mailbox */
+			if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+				SCpnt->result = (DID_ERROR << 16);
+				callDone (SCpnt);
+				return NULL;
+			}
+			mbox = (mega_mailbox *) & pScb->mboxData;
+
+			memset (mbox, 0, sizeof (pScb->mboxData));
+			mbox->logdrv = lun;
+
+			if (megaCfg->flag & BOARD_64BIT) {
+				mbox->cmd = (*SCpnt->cmnd == READ_6
+					     || *SCpnt->cmnd ==
+					     READ_10) ? MEGA_MBOXCMD_LREAD64 :
+				    MEGA_MBOXCMD_LWRITE64;
+			} else {
+				mbox->cmd = (*SCpnt->cmnd == READ_6
+					     || *SCpnt->cmnd ==
+					     READ_10) ? MEGA_MBOXCMD_LREAD :
+				    MEGA_MBOXCMD_LWRITE;
+			}
+
+			/* 6-byte */
+			if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) {
+				mbox->numsectors = (u32) SCpnt->cmnd[4];
+				mbox->lba =
+				    ((u32) SCpnt->cmnd[1] << 16) |
+				    ((u32) SCpnt->cmnd[2] << 8) |
+				    (u32) SCpnt->cmnd[3];
+				mbox->lba &= 0x1FFFFF;
+
+				if (*SCpnt->cmnd == READ_6) {
+					megaCfg->nReads[(int) lun]++;
+					megaCfg->nReadBlocks[(int) lun] +=
+					    mbox->numsectors;
+				} else {
+					megaCfg->nWrites[(int) lun]++;
+					megaCfg->nWriteBlocks[(int) lun] +=
+					    mbox->numsectors;
+				}
+			}
+
+			/* 10-byte */
+			if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
+				mbox->numsectors =
+				    (u32) SCpnt->cmnd[8] |
+				    ((u32) SCpnt->cmnd[7] << 8);
+				mbox->lba =
+				    ((u32) SCpnt->cmnd[2] << 24) |
+				    ((u32) SCpnt->cmnd[3] << 16) |
+				    ((u32) SCpnt->cmnd[4] << 8) |
+				    (u32) SCpnt->cmnd[5];
+
+				if (*SCpnt->cmnd == READ_10) {
+					megaCfg->nReads[(int) lun]++;
+					megaCfg->nReadBlocks[(int) lun] +=
+					    mbox->numsectors;
+				} else {
+					megaCfg->nWrites[(int) lun]++;
+					megaCfg->nWriteBlocks[(int) lun] +=
+					    mbox->numsectors;
+				}
+			}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) {
+				pScb->dma_direction = PCI_DMA_FROMDEVICE;
+			} else {	/*WRITE_6 or WRITE_10 */
+				pScb->dma_direction = PCI_DMA_TODEVICE;
+			}
 #endif
 
-#if DEBUG
-static unsigned int cum_time = 0;
-static unsigned int cum_time_cnt = 0;
+			/* Calculate Scatter-Gather info */
+			mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
+								 (u32 *) &
+								 mbox->xferaddr,
+								 (u32 *) & seg);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pScb->iDataSize = seg;
+
+			if (mbox->numsgelements) {
+				pScb->dma_type = M_RD_SGLIST_ONLY;
+				TRACE1 (("M_RD_SGLIST_ONLY Enabled \n"));
+			} else {
+				pScb->dma_type = M_RD_BULK_DATA_ONLY;
+				TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));
+			}
 #endif
 
-/*--------------------------------------------------------------------
- * Interrupt service routine
- *--------------------------------------------------------------------*/
-static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
-{
-#if LINUX_VERSION_CODE >= 0x20100
-  IO_LOCK_T
+			return pScb;
+		default:
+			SCpnt->result = (DID_BAD_TARGET << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+	}
+	/*-----------------------------------------------------
+	 *
+	 *               Passthru drive commands
+	 *
+	 *-----------------------------------------------------*/
+	else {
+		/* Allocate a SCB and initialize passthru */
+		if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+			SCpnt->result = (DID_ERROR << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pthru = pScb->pthru;
+#else
+		pthru = &pScb->pthru;
 #endif
-  mega_host_config    *megaCfg;
-  u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
-  u32 dword=0;
-  mega_mailbox *mbox;
-  mega_scb *pScb;
-  u_char qCnt, qStatus;
-  u_char            completed[MAX_FIRMWARE_STATUS];
-  Scsi_Cmnd *SCpnt;
-
-  megaCfg = (mega_host_config *) devp;
-  mbox = (mega_mailbox *)tmpBox;
-
-  if (megaCfg->host->irq == irq) {
-    if (megaCfg->flag & IN_ISR) {
-      printk(KERN_ERR "ISR called reentrantly!!\n");
-    }
-
-    megaCfg->flag |= IN_ISR;
-
-    if (mega_busyWaitMbox(megaCfg)) {
-	printk(KERN_WARNING "Error: mailbox busy in isr!\n");
-    }
-
-    /* Check if a valid interrupt is pending */
-    if (megaCfg->flag & BOARD_QUARTZ) {
-      dword = RDOUTDOOR (megaCfg);
-      if (dword != 0x10001234) {
-	/* Spurious interrupt */
-	megaCfg->flag &= ~IN_ISR;
-	return;
-      }
-    }
-    else {
-      byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
-      if ((byte & VALID_INTR_BYTE) == 0) {
-	/* Spurious interrupt */
-	megaCfg->flag &= ~IN_ISR;
-	return;
-      }
-      WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
-    }
-
-    for(idx=0;idx<MAX_FIRMWARE_STATUS;idx++ ) completed[idx] = 0;
-
-    IO_LOCK;
-
-    qCnt = 0xff;
-    while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) 
-      ;
-
-    qStatus = 0xff;
-    while ((qStatus = megaCfg->mbox->status) == 0xFF)
-      ;
-
-    /* Get list of completed requests */
-    for (idx = 0; idx<qCnt; idx++) {
-      while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
-	printk("p");
-      }
-      completed[idx] = sIdx;
-      sIdx = 0xFF;
-    }
-
-    if (megaCfg->flag & BOARD_QUARTZ) {
-      WROUTDOOR (megaCfg, dword);
-      /* Acknowledge interrupt */
-      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
-      while (RDINDOOR (megaCfg) & 0x02);
-    }
-    else {
-      CLEAR_INTR (megaCfg->host->io_port);
-    }
+		mbox = (mega_mailbox *) pScb->mboxData;
 
-#if DEBUG
-    if(qCnt >= MAX_FIRMWARE_STATUS) {
-      printk("megaraid_isr: cmplt=%d ", qCnt);
-    }
+		memset (mbox, 0, sizeof (pScb->mboxData));
+		memset (pthru, 0, sizeof (mega_passthru));
+
+		/* set adapter timeout value to 10 min. for tape drive	*/
+		/* 0=6sec/1=60sec/2=10min/3=3hrs 			*/
+		pthru->timeout = 2;
+		pthru->ars = 1;
+		pthru->reqsenselen = 14;
+		pthru->islogical = 0;
+		pthru->channel =
+		    (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
+		pthru->target = (megaCfg->flag & BOARD_40LD) ?	/*BOARD_40LD */
+		    (SCpnt->channel << 4) | SCpnt->target : SCpnt->target;
+		pthru->cdblen = SCpnt->cmd_len;
+
+		memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		/* Not sure about the direction */
+		pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+		/* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+		switch (SCpnt->cmnd[0]) {
+		case INQUIRY:
+		case READ_CAPACITY:
+			pthru->numsgelements = 0;
+			pthru->dataxferaddr = pScb->dma_bounce_buffer;
+			pthru->dataxferlen = SCpnt->request_bufflen;
+			break;
+		default:
+			pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+								  (u32 *) &
+								  pthru->
+								  dataxferaddr,
+								  (u32 *) &
+								  pthru->
+								  dataxferlen);
+			break;
+		}
+#else
+		pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+							  (u32 *) & pthru->
+							  dataxferaddr,
+							  (u32 *) & pthru->
+							  dataxferlen);
 #endif
 
-    for (idx = 0; idx < qCnt; idx++) {
-      sIdx = completed[idx];
-      if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
-	pScb = &megaCfg->scbList[sIdx - 1];
+		/* Initialize mailbox */
+		mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
 
-	/* ASSERT(pScb->state == SCB_ISSUED); */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		mbox->xferaddr = pScb->dma_passthruhandle64;
 
-#if DEBUG
-	if (((jiffies) - pScb->isrcount) > maxCmdTime) {
-	  maxCmdTime = (jiffies) - pScb->isrcount;
-	  printk("megaraid_isr : cmd time = %u\n", maxCmdTime);
-	}
+		if (pthru->numsgelements) {
+			pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+			TRACE1 (("M_RD_PTHRU_WITH_SGLIST Enabled \n"));
+		} else {
+			pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA
+			    TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
+		}
+#else
+		mbox->xferaddr = virt_to_bus (pthru);
 #endif
-/*
- * Assuming that the scsi command, for which an abort request was received
- * earlier has completed.
- */
-	if (pScb->state == SCB_ABORTED) {
-          SCpnt = pScb->SCpnt;
+
+		return pScb;
+	}
+	return NULL;
+}
+
+/* Handle Driver Level IOCTLs
+ * Return value of 0 indicates this function could not handle , so continue
+ * processing
+*/
+
+static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+	unsigned char *data = (unsigned char *) SCpnt->request_buffer;
+	mega_driver_info driver_info;
+
+	/* If this is not our command dont do anything */
+	if (SCpnt->cmnd[0] != M_RD_DRIVER_IOCTL_INTERFACE)
+		return 0;
+
+	switch (SCpnt->cmnd[1]) {
+	case GET_DRIVER_INFO:
+		if (SCpnt->request_bufflen < sizeof (driver_info)) {
+			SCpnt->result = DID_BAD_TARGET << 16;
+			callDone (SCpnt);
+			return 1;
+		}
+
+		driver_info.size = sizeof (driver_info) - sizeof (int);
+		driver_info.version = MEGARAID_IOCTL_VERSION;
+		memcpy (data, &driver_info, sizeof (driver_info));
+		break;
+	default:
+		SCpnt->result = DID_BAD_TARGET << 16;
+	}
+
+	callDone (SCpnt);
+	return 1;
+}
+
+static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb,
+		    mega_ioctl_mbox * mbox, u32 direction)
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	switch (direction) {
+	case TO_DEVICE:
+		pScb->dma_direction = PCI_DMA_TODEVICE;
+		break;
+	case FROM_DEVICE:
+		pScb->dma_direction = PCI_DMA_FROMDEVICE;
+		break;
+	case FROMTO_DEVICE:
+		pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+		break;
+	}
+
+	pScb->dma_h_bulkdata
+	    = pci_map_single (megaCfg->dev,
+			      pScb->buff_ptr,
+			      pScb->iDataSize, pScb->dma_direction);
+	mbox->xferaddr = pScb->dma_h_bulkdata;
+	pScb->dma_type = M_RD_BULK_DATA_ONLY;
+	TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n"));
+#else
+	mbox->xferaddr = virt_to_bus (pScb->buff_ptr);
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+
+/*--------------------------------------------------------------------
+ * build RAID commands for controller, passed down through ioctl()
+ *--------------------------------------------------------------------*/
+static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+	mega_scb *pScb;
+	mega_ioctl_mbox *mbox;
+	mega_mailbox *mailbox;
+	mega_passthru *pthru;
+	u8 *mboxdata;
+	long seg, i = 0;
+	unsigned char *data = (unsigned char *) SCpnt->request_buffer;
+
+	if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
+		SCpnt->result = (DID_ERROR << 16);
+		callDone (SCpnt);
+		return NULL;
 	}
-	if (pScb->state == SCB_RESET) {
-          SCpnt = pScb->SCpnt;
-	  mega_freeSCB (megaCfg, pScb);
-	  SCpnt->result = (DID_RESET << 16) ;
-          if( megaCfg->qCompletedH == NULL ) {
-            megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
-          }
-          else {
-            megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
-            megaCfg->qCompletedT = SCpnt;
-          }
-          megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
-          megaCfg->qCcnt++;
-          continue;
-	}
-
-        if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) 
-        {    /* external user buffer */
-           up(&pScb->sem);
-        }
-	/* Mark command as completed */
-	mega_cmd_done(megaCfg, pScb, qStatus);
-
-      }
-      else {
-        printk(KERN_ERR "megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
-      }
-    }
-
-    mega_rundoneq(megaCfg);
-
-    megaCfg->flag &= ~IN_ISR;
-
-    /* Loop through any pending requests */
-    mega_runpendq(megaCfg);
-#if LINUX_VERSION_CODE >= 0x20100
-    IO_UNLOCK;
+	pthru = &pScb->pthru;
+
+	mboxdata = (u8 *) & pScb->mboxData;
+	mbox = (mega_ioctl_mbox *) & pScb->mboxData;
+	mailbox = (mega_mailbox *) & pScb->mboxData;
+	memset (mailbox, 0, sizeof (pScb->mboxData));
+
+	if (data[0] == 0x03) {	/* passthrough command */
+		unsigned char cdblen = data[2];
+		memset (pthru, 0, sizeof (mega_passthru));
+		pthru->islogical = (data[cdblen + 3] & 0x80) ? 1 : 0;
+		pthru->timeout = data[cdblen + 3] & 0x07;
+		pthru->reqsenselen = 14;
+		pthru->ars = (data[cdblen + 3] & 0x08) ? 1 : 0;
+		pthru->logdrv = data[cdblen + 4];
+		pthru->channel = data[cdblen + 5];
+		pthru->target = data[cdblen + 6];
+		pthru->cdblen = cdblen;
+		memcpy (pthru->cdb, &data[3], cdblen);
+
+		mailbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+
+
+		pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
+							  (u32 *) & pthru->
+							  dataxferaddr,
+							  (u32 *) & pthru->
+							  dataxferlen);
+
+		mailbox->xferaddr = virt_to_bus (pthru);
+
+		for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) {
+			data[i] = data[i + cdblen + 7];
+		}
+		return pScb;
+	}
+	/* else normal (nonpassthru) command */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24)	/*0x020024 */
+	/*
+	 *usage of the function copy from user is used in case of data more than
+	 *4KB.This is used only with adapters which supports more than 8 logical
+	 * drives.This feature is disabled on kernels earlier or same as 2.0.36
+	 * as the uaccess.h file is not available with those kernels.
+	 */
+
+	if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+		/* use external data area for large xfers  */
+		/* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then *
+		 *   cmnd[4..7] = external user buffer     *
+		 *   cmnd[8..11] = length of buffer        *
+		 *                                         */
+		char *user_area = *((char **) &SCpnt->cmnd[4]);
+		u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]);
+		switch (data[0]) {
+		case FW_FIRE_WRITE:
+		case FW_FIRE_FLASH:
+			if ((ulong) user_area & (PAGE_SIZE - 1)) {
+				printk
+				    ("megaraid:user address not aligned on 4K boundary.Error.\n");
+				SCpnt->result = (DID_ERROR << 16);
+				callDone (SCpnt);
+				return NULL;
+			}
+			break;
+		default:
+			break;
+		}
+
+		if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) {
+			printk
+			    ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.\n");
+			SCpnt->result = (DID_ERROR << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+
+		copy_from_user (pScb->buff_ptr, user_area, xfer_size);
+		pScb->iDataSize = xfer_size;
+
+		switch (data[0]) {
+		case DCMD_FC_CMD:
+			switch (data[1]) {
+			case DCMD_FC_READ_NVRAM_CONFIG:
+			case DCMD_GET_DISK_CONFIG:
+				{
+					if ((ulong) pScb->
+					    buff_ptr & (PAGE_SIZE - 1)) {
+						printk
+						    ("megaraid:user address not sufficient Error.\n");
+						SCpnt->result =
+						    (DID_ERROR << 16);
+						callDone (SCpnt);
+						return NULL;
+					}
+
+					/*building SG list */
+					mega_build_kernel_sg (pScb->buff_ptr,
+							      xfer_size,
+							      pScb, mbox);
+					break;
+				}
+			default:
+				break;
+			}	/*switch (data[1]) */
+			break;
+		}
+
+	}
+#endif
+
+	mbox->cmd = data[0];
+	mbox->channel = data[1];
+	mbox->param = data[2];
+	mbox->pad[0] = data[3];
+	mbox->logdrv = data[4];
+
+	if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+		switch (data[0]) {
+		case FW_FIRE_WRITE:
+			mbox->cmd = FW_FIRE_WRITE;
+			mbox->channel = data[1];	/* Current Block Number */
+			set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
+			mbox->numsgelements = 0;
+			break;
+		case FW_FIRE_FLASH:
+			mbox->cmd = FW_FIRE_FLASH;
+			mbox->channel = data[1] | 0x80;	/* Origin */
+			set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
+			mbox->numsgelements = 0;
+			break;
+		case DCMD_FC_CMD:
+			*(mboxdata + 0) = data[0];	/*mailbox byte 0: DCMD_FC_CMD */
+			*(mboxdata + 2) = data[1];	/*sub command */
+			switch (data[1]) {
+			case DCMD_FC_READ_NVRAM_CONFIG:
+			case DCMD_FC_READ_NVRAM_CONFIG_64:
+				/* number of elements in SG list */
+				*(mboxdata + 3) = mbox->numsgelements;
+				if (megaCfg->flag & BOARD_64BIT)
+					*(mboxdata + 2) =
+					    DCMD_FC_READ_NVRAM_CONFIG_64;
+				break;
+			case DCMD_WRITE_CONFIG:
+			case DCMD_WRITE_CONFIG_64:
+				if (megaCfg->flag & BOARD_64BIT)
+					*(mboxdata + 2) = DCMD_WRITE_CONFIG_64;
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    TO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			case DCMD_GET_DISK_CONFIG:
+			case DCMD_GET_DISK_CONFIG_64:
+				if (megaCfg->flag & BOARD_64BIT)
+					*(mboxdata + 2) =
+					    DCMD_GET_DISK_CONFIG_64;
+				*(mboxdata + 3) = data[2];	/*number of elements in SG list */
+				/*nr of elements in SG list */
+				*(mboxdata + 4) = mbox->numsgelements;
+				break;
+			case DCMD_DELETE_LOGDRV:
+			case DCMD_DELETE_DRIVEGROUP:
+			case NC_SUBOP_ENQUIRY3:
+				*(mboxdata + 3) = data[2];
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    FROMTO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			case DCMD_CHANGE_LDNO:
+			case DCMD_CHANGE_LOOPID:
+				*(mboxdata + 3) = data[2];
+				*(mboxdata + 4) = data[3];
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    TO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			default:
+				set_mbox_xfer_addr (megaCfg, pScb, mbox,
+						    FROMTO_DEVICE);
+				mbox->numsgelements = 0;
+				break;
+			}	/*switch */
+			break;
+		default:
+			set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE);
+			mbox->numsgelements = 0;
+			break;
+		}
+	} else {
+
+		mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
+							 (u32 *) & mbox->
+							 xferaddr,
+							 (u32 *) & seg);
+
+		/* Handling some of the fw special commands */
+		switch (data[0]) {
+		case 6:	/* START_DEV */
+			mbox->xferaddr = *((u32 *) & data[i + 6]);
+			break;
+		default:
+			break;
+		}
+
+		for (i = 0; i < (SCpnt->request_bufflen - 6); i++) {
+			data[i] = data[i + 6];
+		}
+	}
+
+	return (pScb);
+}
+
+
+static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox)
+{
+	ulong i, buffer_area, len, end, end_page, x, idx = 0;
+
+	buffer_area = (ulong) barea;
+	i = buffer_area;
+	end = buffer_area + xfersize;
+	end_page = (end) & ~(PAGE_SIZE - 1);
+
+	do {
+		len = PAGE_SIZE - (i % PAGE_SIZE);
+		x = pScb->sgList[idx].address =
+		    virt_to_bus ((volatile void *) i);
+		pScb->sgList[idx].length = len;
+		i += len;
+		idx++;
+	} while (i < end_page);
+
+	if ((end - i) < 0) {
+		printk ("megaraid:Error in user address\n");
+	}
+
+	if (end - i) {
+		pScb->sgList[idx].address = virt_to_bus ((volatile void *) i);
+		pScb->sgList[idx].length = end - i;
+		idx++;
+	}
+	mbox->xferaddr = virt_to_bus (pScb->sgList);
+	mbox->numsgelements = idx;
+}
+
+#endif				/* KERNEL_VERSION(2,3,0) */
+
+#if DEBUG
+static unsigned int cum_time = 0;
+static unsigned int cum_time_cnt = 0;
+
+static void showMbox (mega_scb * pScb)
+{
+	mega_mailbox *mbox;
+
+	if (pScb == NULL)
+		return;
+
+	mbox = (mega_mailbox *) pScb->mboxData;
+	printk ("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
+		pScb->SCpnt->pid,
+		mbox->cmd, mbox->cmdid, mbox->numsectors,
+		mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements);
+}
+
+#endif
+
+/*--------------------------------------------------------------------
+ * Interrupt service routine
+ *--------------------------------------------------------------------*/
+static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
+{
+	IO_LOCK_T
+	mega_host_config * megaCfg;
+	u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
+	u32 dword = 0;
+	mega_mailbox *mbox;
+	mega_scb *pScb;
+	u_char qCnt, qStatus;
+	u_char completed[MAX_FIRMWARE_STATUS];
+	Scsi_Cmnd *SCpnt;
+
+	megaCfg = (mega_host_config *) devp;
+	mbox = (mega_mailbox *) tmpBox;
+
+	if (megaCfg->host->irq == irq) {
+		if (megaCfg->flag & IN_ISR) {
+			TRACE (("ISR called reentrantly!!\n"));
+			printk ("ISR called reentrantly!!\n");
+		}
+		megaCfg->flag |= IN_ISR;
+
+		if (mega_busyWaitMbox (megaCfg)) {
+			printk (KERN_WARNING "Error: mailbox busy in isr!\n");
+		}
+
+		/* Check if a valid interrupt is pending */
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			dword = RDOUTDOOR (megaCfg);
+			if (dword != 0x10001234) {
+				/* Spurious interrupt */
+				megaCfg->flag &= ~IN_ISR;
+				return;
+			}
+		} else {
+			byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
+			if ((byte & VALID_INTR_BYTE) == 0) {
+				/* Spurious interrupt */
+				megaCfg->flag &= ~IN_ISR;
+				return;
+			}
+			WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+		}
+
+		for (idx = 0; idx < MAX_FIRMWARE_STATUS; idx++)
+			completed[idx] = 0;
+
+		IO_LOCK;
+
+		megaCfg->nInterrupts++;
+		qCnt = 0xff;
+		while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ;
+
+		qStatus = 0xff;
+		while ((qStatus = megaCfg->mbox->status) == 0xFF) ;
+
+		/* Get list of completed requests */
+		for (idx = 0; idx < qCnt; idx++) {
+			while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
+				printk ("p");
+			}
+			completed[idx] = sIdx;
+			sIdx = 0xFF;
+		}
+
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			WROUTDOOR (megaCfg, dword);
+			/* Acknowledge interrupt */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			/* In this case mbox contains physical address */
+#if 0
+			WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2);
+#else
+			WRINDOOR (megaCfg, 0x2);
+#endif
+
+#else
+
+#if 0
+			WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+#else
+			WRINDOOR (megaCfg, 0x2);
 #endif
 
-  }
+#endif
+
+#if 0
+			while (RDINDOOR (megaCfg) & 0x02) ;
+#endif
+		} else {
+			CLEAR_INTR (megaCfg->host->io_port);
+		}
+
+#if DEBUG
+		if (qCnt >= MAX_FIRMWARE_STATUS) {
+			printk ("megaraid_isr: cmplt=%d ", qCnt);
+		}
+#endif
+
+		for (idx = 0; idx < qCnt; idx++) {
+			sIdx = completed[idx];
+			if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
+				pScb = &megaCfg->scbList[sIdx - 1];
+
+				/* ASSERT(pScb->state == SCB_ISSUED); */
+
+#if DEBUG
+				if (((jiffies) - pScb->isrcount) > maxCmdTime) {
+					maxCmdTime = (jiffies) - pScb->isrcount;
+					printk
+					    ("megaraid_isr : cmd time = %u\n",
+					     maxCmdTime);
+				}
+#endif
+				/*
+				 * Assuming that the scsi command, for which 
+				 * an abort request was received earlier, has 
+				 * completed.
+				 */
+				if (pScb->state == SCB_ABORTED) {
+					SCpnt = pScb->SCpnt;
+				}
+				if (pScb->state == SCB_RESET) {
+					SCpnt = pScb->SCpnt;
+					mega_freeSCB (megaCfg, pScb);
+					SCpnt->result = (DID_RESET << 16);
+					if (megaCfg->qCompletedH == NULL) {
+						megaCfg->qCompletedH =
+						    megaCfg->qCompletedT =
+						    SCpnt;
+					} else {
+						megaCfg->qCompletedT->
+						    host_scribble =
+						    (unsigned char *) SCpnt;
+						megaCfg->qCompletedT = SCpnt;
+					}
+					megaCfg->qCompletedT->host_scribble =
+					    (unsigned char *) NULL;
+					megaCfg->qCcnt++;
+					continue;
+				}
+
+				/* We don't want the ISR routine to touch M_RD_IOCTL_CMD_NEW commands, so
+				 * don't mark them as complete, instead we pop their semaphore so
+				 * that the queue routine can finish them off
+				 */
+				if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+					/* save the status byte for the queue routine to use */
+					pScb->SCpnt->result = qStatus;
+					up (&pScb->ioctl_sem);
+				} else {
+					/* Mark command as completed */
+					mega_cmd_done (megaCfg, pScb, qStatus);
+				}
+			} else {
+				printk
+				    ("megaraid: wrong cmd id completed from firmware:id=%x\n",
+				     sIdx);
+			}
+		}
+
+		mega_rundoneq (megaCfg);
+
+		megaCfg->flag &= ~IN_ISR;
+		/* Loop through any pending requests */
+		mega_runpendq (megaCfg);
+		IO_UNLOCK;
+
+	}
+
 }
 
 /*==================================================*/
 /* Wait until the controller's mailbox is available */
 /*==================================================*/
+
 static int mega_busyWaitMbox (mega_host_config * megaCfg)
 {
-  mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
-  long counter;
+	mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+	long counter;
 
-  for (counter = 0; counter < 10000; counter++) {
-    if (!mbox->busy) {
-      return 0;
-    }
-    udelay (100);
-    barrier();
-  }
-  return -1;			/* give up after 1 second */
+	for (counter = 0; counter < 10000; counter++) {
+		if (!mbox->busy) {
+			return 0;
+		}
+		udelay (100);
+		barrier ();
+	}
+	return -1;		/* give up after 1 second */
 }
 
 /*=====================================================
@@ -1113,153 +1826,278 @@
  *   -1: the command was not actually issued out
  *   othercases:
  *     intr==0, return ScsiStatus, i.e. mbox->status
- *     intr==1, return 0 
+ *     intr==1, return 0
  *=====================================================
  */
-static int megaIssueCmd (mega_host_config * megaCfg,
-	      u_char * mboxData,
-	      mega_scb * pScb,
-	      int intr)
-{
-  mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
-  u_char byte;
-  u32 cmdDone;
-  u32 phys_mbox;
-  u8 retval=-1;
+static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, 
+		mega_scb * pScb, int intr)
+{
+	volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64;
+#endif
+
+	u_char byte;
+
+#ifdef __LP64__
+	u64 phys_mbox;
+#else
+	u32 phys_mbox;
+#endif
+	u8 retval = -1;
 
-  mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0);   /* Set cmdid */
-  mboxData[0xF] = 1;		/* Set busy */
+	mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE);	/* Set cmdid */
+	mboxData[0xF] = 1;	/* Set busy */
 
-  phys_mbox = virt_to_bus (megaCfg->mbox);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* In this case mbox contains physical address */
+	phys_mbox = megaCfg->adjdmahandle64;
+#else
+	phys_mbox = virt_to_bus (megaCfg->mbox);
+#endif
 
 #if DEBUG
-  showMbox(pScb);
+	ShowMbox (pScb);
 #endif
 
-  /* Wait until mailbox is free */
-  if (mega_busyWaitMbox (megaCfg)) {
-    printk("Blocked mailbox......!!\n");
-    udelay(1000);
+	/* Wait until mailbox is free */
+	if (mega_busyWaitMbox (megaCfg)) {
+		printk ("Blocked mailbox......!!\n");
+		udelay (1000);
 
 #if DEBUG
-    showMbox(pLastScb);
+		showMbox (pLastScb);
+#endif
+
+		/* Abort command */
+		if (pScb == NULL) {
+			TRACE (("NULL pScb in megaIssue\n"));
+			printk ("NULL pScb in megaIssue\n");
+		}
+		mega_cmd_done (megaCfg, pScb, 0x08);
+		return -1;
+	}
+
+	pLastScb = pScb;
+
+	/* Copy mailbox data into host structure */
+	megaCfg->mbox64->xferSegment_lo = 0;
+	megaCfg->mbox64->xferSegment_hi = 0;
+
+	memcpy ((char *) mbox, mboxData, 16);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	switch (mboxData[0]) {
+	case MEGA_MBOXCMD_LREAD64:
+	case MEGA_MBOXCMD_LWRITE64:
+		mbox64->xferSegment_lo = mbox->xferaddr;
+		mbox64->xferSegment_hi = 0;
+		mbox->xferaddr = 0xFFFFFFFF;
+		break;
+	}
 #endif
-    
-    /* Abort command */
-    if (pScb == NULL) {
-	TRACE(("NULL pScb in megaIssue\n"));
-	printk("NULL pScb in megaIssue\n");
-    }
-    mega_cmd_done (megaCfg, pScb, 0x08);
-    return -1;
-  }
-
-  pLastScb = pScb;
-
-  /* Copy mailbox data into host structure */
-  megaCfg->mbox64->xferSegment = 0;
-  memcpy (mbox, mboxData, 16);
-
-  /* Kick IO */
-  if (intr) {
-
-    /* Issue interrupt (non-blocking) command */
-    if (megaCfg->flag & BOARD_QUARTZ) {
-       mbox->mraid_poll = 0;
-      mbox->mraid_ack = 0;
-      WRINDOOR (megaCfg, phys_mbox | 0x1);
-    }
-    else {
-      ENABLE_INTR (megaCfg->host->io_port);
-      ISSUE_COMMAND (megaCfg->host->io_port);
-    }
-    pScb->state = SCB_ISSUED;
-
-    retval=0;
-  }
-  else {			/* Issue non-ISR (blocking) command */
-    disable_irq(megaCfg->host->irq);
-    if (megaCfg->flag & BOARD_QUARTZ) {
-      mbox->mraid_poll = 0;
-      mbox->mraid_ack = 0;
-      WRINDOOR (megaCfg, phys_mbox | 0x1);
-
-      while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
-      WROUTDOOR (megaCfg, cmdDone);
-
-      if (pScb) {
-	mega_cmd_done (megaCfg, pScb, mbox->status);
-      }
-
-      WRINDOOR (megaCfg, phys_mbox | 0x2);
-      while (RDINDOOR (megaCfg) & 0x2);
-
-    }
-    else {
-      DISABLE_INTR (megaCfg->host->io_port);
-      ISSUE_COMMAND (megaCfg->host->io_port);
-
-      while (!((byte = READ_PORT (megaCfg->host->io_port, INTR_PORT)) & INTR_VALID));
-      WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
-
-      ENABLE_INTR (megaCfg->host->io_port);
-      CLEAR_INTR (megaCfg->host->io_port);
-
-      if (pScb) {
-	mega_cmd_done (megaCfg, pScb, mbox->status);
-      }
-      else {
-	TRACE (("Error: NULL pScb!\n"));
-      }
-    }
-    enable_irq(megaCfg->host->irq);
-    retval=mbox->status;
-  }
+
+	/* Kick IO */
+	if (intr) {
+		/* Issue interrupt (non-blocking) command */
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			mbox->mraid_poll = 0;
+			mbox->mraid_ack = 0;
+
+			WRINDOOR (megaCfg, phys_mbox | 0x1);
+		} else {
+			ENABLE_INTR (megaCfg->host->io_port);
+			ISSUE_COMMAND (megaCfg->host->io_port);
+		}
+		pScb->state = SCB_ISSUED;
+
+		retval = 0;
+	} else {		/* Issue non-ISR (blocking) command */
+		disable_irq (megaCfg->host->irq);
+		if (megaCfg->flag & BOARD_QUARTZ) {
+			mbox->mraid_poll = 0;
+			mbox->mraid_ack = 0;
+			mbox->numstatus = 0xFF;
+			mbox->status = 0xFF;
+			WRINDOOR (megaCfg, phys_mbox | 0x1);
+
+			while (mbox->numstatus == 0xFF) ;
+			while (mbox->status == 0xFF) ;
+			while (mbox->mraid_poll != 0x77) ;
+			mbox->mraid_poll = 0;
+			mbox->mraid_ack = 0x77;
+
+			/* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
+			   WROUTDOOR (megaCfg, cmdDone); */
+
+			if (pScb) {
+				mega_cmd_done (megaCfg, pScb, mbox->status);
+			}
+
+			WRINDOOR (megaCfg, phys_mbox | 0x2);
+			while (RDINDOOR (megaCfg) & 0x2) ;
+
+		} else {
+			DISABLE_INTR (megaCfg->host->io_port);
+			ISSUE_COMMAND (megaCfg->host->io_port);
+
+			while (!
+			       ((byte =
+				 READ_PORT (megaCfg->host->io_port,
+					    INTR_PORT)) & INTR_VALID)) ;
+			WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+
+			ENABLE_INTR (megaCfg->host->io_port);
+			CLEAR_INTR (megaCfg->host->io_port);
+
+			if (pScb) {
+				mega_cmd_done (megaCfg, pScb, mbox->status);
+			} else {
+				TRACE (("Error: NULL pScb!\n"));
+			}
+		}
+		enable_irq (megaCfg->host->irq);
+		retval = mbox->status;
+	}
 #if DEBUG
-  while (mega_busyWaitMbox (megaCfg)) {
-    printk("Blocked mailbox on exit......!\n");
-    udelay(1000);
-  }
+	while (mega_busyWaitMbox (megaCfg)) {
+		printk(KERN_ERR "Blocked mailbox on exit......!\n");
+		udelay (1000);
+	}
 #endif
 
-  return retval;
+	return retval;
 }
 
 /*-------------------------------------------------------------------
  * Copies data to SGLIST
  *-------------------------------------------------------------------*/
-static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
-	      u32 * buffer, u32 * length)
+/* Note:
+	For 64 bit cards, we need a minimum of one SG element for read/write
+*/
+
+static int
+mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+		   u32 * buffer, u32 * length)
 {
-  struct scatterlist *sgList;
-  int idx;
+	struct scatterlist *sgList;
+	int idx;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	int sgcnt;
+#endif
+
+	mega_mailbox *mbox = NULL;
+
+	mbox = (mega_mailbox *) scb->mboxData;
+	/* Scatter-gather not used */
+	if (scb->SCpnt->use_sg == 0) {
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
+				      scb->SCpnt->request_buffer,
+				      scb->SCpnt->request_bufflen,
+				      scb->dma_direction);
+		/* We need to handle special commands like READ64, WRITE64
+		   as they need a minimum of 1 SG irrespective of actaully SG
+		 */
+		if ((megaCfg->flag & BOARD_64BIT) &&
+		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+		     (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+			scb->sg64List[0].address = scb->dma_h_bulkdata;
+			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
+			*buffer = scb->dma_sghandle64;
+			*length = 0;
+			scb->sglist_count = 1;
+			return 1;
+		} else {
+			*buffer = scb->dma_h_bulkdata;
+			*length = (u32) scb->SCpnt->request_bufflen;
+		}
+#else
+		*buffer = virt_to_bus (scb->SCpnt->request_buffer);
+		*length = (u32) scb->SCpnt->request_bufflen;
+#endif
+		return 0;
+	}
+
+	sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
 
-  /* Scatter-gather not used */
-  if (scb->SCpnt->use_sg == 0) {
-    *buffer = virt_to_bus (scb->SCpnt->request_buffer);
-    *length = (u32) scb->SCpnt->request_bufflen;
-    return 0;
-  }
-
-  sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
-  if (scb->SCpnt->use_sg == 1) {
-    *buffer = virt_to_bus (sgList[0].address);
-    *length = (u32) sgList[0].length;
-    return 0;
-  }
-
-  /* Copy Scatter-Gather list info into controller structure */
-  for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
-    scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
-    scb->sgList[idx].length = (u32) sgList[idx].length;
-  }
-
-  /* Reset pointer and length fields */
-  *buffer = virt_to_bus (scb->sgList);
-  *length = 0;
+	if (scb->SCpnt->use_sg == 1) {
 
-  /* Return count of SG requests */
-  return scb->SCpnt->use_sg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
+				      sgList[0].address,
+				      sgList[0].length, scb->dma_direction);
+
+		if ((megaCfg->flag & BOARD_64BIT) &&
+		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+		     (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+			scb->sg64List[0].address = scb->dma_h_bulkdata;
+			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
+			*buffer = scb->dma_sghandle64;
+			*length = 0;
+			scb->sglist_count = 1;
+			return 1;
+		} else {
+			*buffer = scb->dma_h_bulkdata;
+			*length = (u32) sgList[0].length;
+		}
+#else
+		*buffer = virt_to_bus (sgList[0].address);
+		*length = (u32) sgList[0].length;
+#endif
+
+		return 0;
+	}
+
+	/* Copy Scatter-Gather list info into controller structure */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	sgcnt = pci_map_sg (megaCfg->dev,
+			    sgList, scb->SCpnt->use_sg, scb->dma_direction);
+
+	/* Determine the validity of the new count  */
+	if (sgcnt == 0)
+		printk ("pci_map_sg returned zero!!! ");
+
+	for (idx = 0; idx < sgcnt; idx++, sgList++) {
+
+		if ((megaCfg->flag & BOARD_64BIT) &&
+		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
+		     (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
+			scb->sg64List[idx].address = sg_dma_address (sgList);
+			scb->sg64List[idx].length = sg_dma_len (sgList);
+		} else {
+			scb->sgList[idx].address = sg_dma_address (sgList);
+			scb->sgList[idx].length = sg_dma_len (sgList);
+		}
+
+	}
+
+#else
+	for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
+		scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
+		scb->sgList[idx].length = (u32) sgList[idx].length;
+	}
+#endif
+
+	/* Reset pointer and length fields */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	*buffer = scb->dma_sghandle64;
+	scb->sglist_count = scb->SCpnt->use_sg;
+#else
+	*buffer = virt_to_bus (scb->sgList);
+#endif
+	*length = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* Return count of SG requests */
+	return sgcnt;
+#else
+	/* Return count of SG requests */
+	return scb->SCpnt->use_sg;
+#endif
 }
 
 /*--------------------------------------------------------------------
@@ -1278,169 +2116,243 @@
  *   10 01 numstatus byte
  *   11 01 status byte
  *--------------------------------------------------------------------*/
-static int mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
+static int
+mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
 {
-  /* align on 16-byte boundry */
-  megaCfg->mbox = &megaCfg->mailbox64.mailbox;
-  megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0);
-  megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
-  paddr = (paddr + 4 + 16) & 0xfffffff0;
-
-  /* Register mailbox area with the firmware */
-  if (!(megaCfg->flag & BOARD_QUARTZ)) {
-    WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
-    WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF);
-    WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF);
-    WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF);
-    WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE);
-
-    CLEAR_INTR (megaCfg->host->io_port);
-    ENABLE_INTR (megaCfg->host->io_port);
-  }
-  return 0;
-}
+	/* align on 16-byte boundry */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
+#else
+	megaCfg->mbox = &megaCfg->mailbox64.mailbox;
+#endif
+
+#ifdef __LP64__
+	megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F));
+	megaCfg->adjdmahandle64 = (megaCfg->dma_handle64 + 16) & ((u64) (-1) ^ 0x0F);
+	megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - sizeof (u64));
+	paddr = (paddr + 4 + 16) & ((u64) (-1) ^ 0x0F);
+#else
+	megaCfg->mbox
+	    = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0);
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	megaCfg->adjdmahandle64 = ((megaCfg->dma_handle64 + 16) & 0xFFFFFFF0);
+#endif
+
+	megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - 8);
+	paddr = (paddr + 4 + 16) & 0xFFFFFFF0;
+#endif
+
+	/* Register mailbox area with the firmware */
+	if (!(megaCfg->flag & BOARD_QUARTZ)) {
+		WRITE_PORT (megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF);
+		WRITE_PORT (megaCfg->host->io_port, MBOX_PORT1,
+			    (paddr >> 8) & 0xFF);
+		WRITE_PORT (megaCfg->host->io_port, MBOX_PORT2,
+			    (paddr >> 16) & 0xFF);
+		WRITE_PORT (megaCfg->host->io_port, MBOX_PORT3,
+			    (paddr >> 24) & 0xFF);
+		WRITE_PORT (megaCfg->host->io_port, ENABLE_MBOX_REGION,
+			    ENABLE_MBOX_BYTE);
+
+		CLEAR_INTR (megaCfg->host->io_port);
+		ENABLE_INTR (megaCfg->host->io_port);
+	}
+	return 0;
+}
 
 /*---------------------------------------------------------------------------
  * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and
  * puts it into ProductInfo and Enquiry3 structures for later use
  *---------------------------------------------------------------------------*/
-static void mega_Convert8ldTo40ld(  mega_RAIDINQ  *inquiry,
-                                    mega_Enquiry3 *enquiry3,
-                                    megaRaidProductInfo *productInfo )
-{
-        int i;
-
-        productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
-        enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
-        productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
-        for (i=0;i<4;i++) {
-                productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
-                productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
-        }
-        enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
-        productInfo->DramSize = inquiry->AdpInfo.DramSize;
-
-        enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
-        for (i=0;i<MAX_LOGICAL_DRIVES;i++) {
-                enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
-                enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
-                enquiry3->lDrvState[i] = inquiry->LogdrvInfo.LDrvState[i];
-        }
-
-        for (i=0;i<(MAX_PHYSICAL_DRIVES);i++) {
-                enquiry3->pDrvState[i] = inquiry->PhysdrvInfo.PDrvState[i];
-        }
-}
+static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry,
+		       mega_Enquiry3 * enquiry3,
+		       megaRaidProductInfo * productInfo)
+{
+	int i;
+
+	productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
+	enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
+	productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
+
+	for (i = 0; i < 4; i++) {
+		productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
+		productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
+	}
+	enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
+	productInfo->DramSize = inquiry->AdpInfo.DramSize;
+
+	enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
+
+	for (i = 0; i < MAX_LOGICAL_DRIVES; i++) {
+		enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
+		enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
+		enquiry3->lDrvState[i]
+		    = inquiry->LogdrvInfo.LDrvState[i];
+	}
 
+	for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) {
+		enquiry3->pDrvState[i]
+		    = inquiry->PhysdrvInfo.PDrvState[i];
+	}
+}
 
 /*-------------------------------------------------------------------
  * Issue an adapter info query to the controller
  *-------------------------------------------------------------------*/
 static int mega_i_query_adapter (mega_host_config * megaCfg)
 {
-  mega_Enquiry3 *enquiry3Pnt;
-  mega_mailbox *mbox;
-  u_char mboxData[16];
-  u32 paddr;
-  u8 retval;
-
-  /* Initialize adapter inquiry mailbox*/
-  paddr = virt_to_bus (megaCfg->mega_buffer);
-  mbox = (mega_mailbox *) mboxData;
+	mega_Enquiry3 *enquiry3Pnt;
+	mega_mailbox *mbox;
+	u_char mboxData[16];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_addr_t raid_inq_dma_handle = 0, prod_info_dma_handle = 0, enquiry3_dma_handle = 0;
+#endif
+	u8 retval;
+
+	/* Initialize adapter inquiry mailbox */
+
+	mbox = (mega_mailbox *) mboxData;
 
-  memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer));
-  memset (mbox, 0, 16);
+	memset ((void *) megaCfg->mega_buffer, 0,
+		sizeof (megaCfg->mega_buffer));
+	memset (mbox, 0, 16);
 
 /*
- * Try to issue Enquiry3 command 
- * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and 
+ * Try to issue Enquiry3 command
+ * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
  * update enquiry3 structure
  */
-  mbox->xferaddr = virt_to_bus ( (void*) megaCfg->mega_buffer); 
-             /* Initialize mailbox databuffer addr */
-  enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer; 
-             /* point mega_Enguiry3 to the data buf */
-
-  mboxData[0]=FC_NEW_CONFIG ;          /* i.e. mbox->cmd=0xA1 */
-  mboxData[2]=NC_SUBOP_ENQUIRY3;       /* i.e. 0x0F */
-  mboxData[3]=ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
-
-  /* Issue a blocking command to the card */
-  if ( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0 )
-  {  /* the adapter does not support 40ld*/
-
-     mega_RAIDINQ adapterInquiryData;
-     mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
-
-     mbox->xferaddr = virt_to_bus ( (void*) adapterInquiryPnt);
-
-     mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;  /*issue old 0x05 command to adapter*/
-     /* Issue a blocking command to the card */;
-     retval=megaIssueCmd (megaCfg, mboxData, NULL, 0);
-
-     /*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
-     mega_Convert8ldTo40ld(  adapterInquiryPnt, 
-                             enquiry3Pnt, 
-                             (megaRaidProductInfo * ) &megaCfg->productInfo );
-
-  }
-  else{ /* adapter supports 40ld */
-    megaCfg->flag |= BOARD_40LD;
-
-    /*get productInfo, which is static information and will be unchanged*/
-    mbox->xferaddr = virt_to_bus ( (void*) &megaCfg->productInfo );
-
-    mboxData[0]=FC_NEW_CONFIG ;         /* i.e. mbox->cmd=0xA1 */
-    mboxData[2]=NC_SUBOP_PRODUCT_INFO;  /* i.e. 0x0E */
-   
-    if( (retval=megaIssueCmd(megaCfg, mboxData, NULL, 0)) != 0  ) 
-        printk("ami:Product_info (0x0E) cmd failed with error: %d\n", retval);
-
-  }
-
-  megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent;
-  megaCfg->host->max_id = 16;              /* max targets per channel */
-    /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1;*/ 
-  megaCfg->host->max_lun =              /* max lun */
-    (megaCfg->flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; 
-  megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
-
-  megaCfg->numldrv = enquiry3Pnt->numLDrv;
-  megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
-  if(megaCfg->max_cmds > MAX_COMMANDS) megaCfg->max_cmds = MAX_COMMANDS - 1;
-
-  megaCfg->host->can_queue   = megaCfg->max_cmds;
-
-  if (megaCfg->host->can_queue >= MAX_COMMANDS) {
-    megaCfg->host->can_queue = MAX_COMMANDS-1;
-  }
-
-#ifdef HP			/* use HP firmware and bios version encoding */
-  sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
-	   megaCfg->productInfo.FwVer[2],
-	   megaCfg->productInfo.FwVer[1] >> 8,
-	   megaCfg->productInfo.FwVer[1] & 0x0f,
-	   megaCfg->productInfo.FwVer[2] >> 8,
-	   megaCfg->productInfo.FwVer[2] & 0x0f);
-  sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
-	   megaCfg->productInfo.BiosVer[2],
-	   megaCfg->productInfo.BiosVer[1] >> 8,
-	   megaCfg->productInfo.BiosVer[1] & 0x0f,
-	   megaCfg->productInfo.BiosVer[2] >> 8,
-	   megaCfg->productInfo.BiosVer[2] & 0x0f);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	enquiry3_dma_handle = pci_map_single (megaCfg->dev,
+			      (void *) megaCfg->mega_buffer,
+			      (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+	mbox->xferaddr = enquiry3_dma_handle;
+#else
+	/*Taken care */
+	mbox->xferaddr = virt_to_bus ((void *) megaCfg->mega_buffer);
+#endif
+
+	/* Initialize mailbox databuffer addr */
+	enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer;
+	/* point mega_Enguiry3 to the data buf */
+
+	mboxData[0] = FC_NEW_CONFIG;	/* i.e. mbox->cmd=0xA1 */
+	mboxData[2] = NC_SUBOP_ENQUIRY3;	/* i.e. 0x0F */
+	mboxData[3] = ENQ3_GET_SOLICITED_FULL;	/* i.e. 0x02 */
+
+	/* Issue a blocking command to the card */
+	if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0) {	/* the adapter does not support 40ld */
+		mega_RAIDINQ adapterInquiryData;
+		mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		raid_inq_dma_handle = pci_map_single (megaCfg->dev,
+				      (void *) adapterInquiryPnt,
+				      sizeof (mega_RAIDINQ),
+				      PCI_DMA_FROMDEVICE);
+		mbox->xferaddr = raid_inq_dma_handle;
+#else
+		/*taken care */
+		mbox->xferaddr = virt_to_bus ((void *) adapterInquiryPnt);
+#endif
+
+		mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ;	/*issue old 0x05 command to adapter */
+		/* Issue a blocking command to the card */ ;
+		retval = megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+		pci_unmap_single (megaCfg->dev,
+				  raid_inq_dma_handle,
+				  sizeof (mega_RAIDINQ), PCI_DMA_FROMDEVICE);
+
+		/*update Enquiry3 and ProductInfo structures with mega_RAIDINQ structure*/
+		mega_Convert8ldTo40ld (adapterInquiryPnt,
+				       enquiry3Pnt,
+				       (megaRaidProductInfo *) & megaCfg->
+				       productInfo);
+
+	} else {		/* adapter supports 40ld */
+		megaCfg->flag |= BOARD_40LD;
+
+		pci_unmap_single (megaCfg->dev,
+				  enquiry3_dma_handle,
+				  (2 * 1024L), PCI_DMA_FROMDEVICE);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+/*get productInfo, which is static information and will be unchanged*/
+		prod_info_dma_handle
+		    = pci_map_single (megaCfg->dev,
+				      (void *) &megaCfg->productInfo,
+				      sizeof (megaRaidProductInfo),
+				      PCI_DMA_FROMDEVICE);
+		mbox->xferaddr = prod_info_dma_handle;
+#else
+		/*taken care */
+		mbox->xferaddr = virt_to_bus ((void *) &megaCfg->productInfo);
+#endif
+
+		mboxData[0] = FC_NEW_CONFIG;	/* i.e. mbox->cmd=0xA1 */
+		mboxData[2] = NC_SUBOP_PRODUCT_INFO;	/* i.e. 0x0E */
+
+		if ((retval = megaIssueCmd (megaCfg, mboxData, NULL, 0)) != 0)
+			printk ("ami:Product_info cmd failed with error: %d\n",
+				retval);
+
+		pci_unmap_single (megaCfg->dev,
+				  prod_info_dma_handle,
+				  sizeof (megaRaidProductInfo),
+				  PCI_DMA_FROMDEVICE);
+	}
+
+	megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent;
+	megaCfg->host->max_id = 16;	/* max targets per channel */
+	/*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */
+	megaCfg->host->max_lun =	/* max lun */
+	    (megaCfg->
+	     flag & BOARD_40LD) ? FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
+	megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
+
+	megaCfg->numldrv = enquiry3Pnt->numLDrv;
+	megaCfg->max_cmds = megaCfg->productInfo.MaxConcCmds;
+	if (megaCfg->max_cmds > MAX_COMMANDS)
+		megaCfg->max_cmds = MAX_COMMANDS - 1;
+
+	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
+
+#ifdef MEGA_HP_FIX		/* use HP firmware and bios version encoding */
+	sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
+		 megaCfg->productInfo.FwVer[2],
+		 megaCfg->productInfo.FwVer[1] >> 8,
+		 megaCfg->productInfo.FwVer[1] & 0x0f,
+		 megaCfg->productInfo.FwVer[2] >> 8,
+		 megaCfg->productInfo.FwVer[2] & 0x0f);
+	sprintf (megaCfg->biosVer, "%c%d%d.%d%d",
+		 megaCfg->productInfo.BiosVer[2],
+		 megaCfg->productInfo.BiosVer[1] >> 8,
+		 megaCfg->productInfo.BiosVer[1] & 0x0f,
+		 megaCfg->productInfo.BiosVer[2] >> 8,
+		 megaCfg->productInfo.BiosVer[2] & 0x0f);
 #else
-	memcpy (megaCfg->fwVer, (void *)megaCfg->productInfo.FwVer, 4);
+	memcpy (megaCfg->fwVer, (char *) megaCfg->productInfo.FwVer, 4);
 	megaCfg->fwVer[4] = 0;
 
-	memcpy (megaCfg->biosVer, (void *)megaCfg->productInfo.BiosVer, 4);
+	memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
 	megaCfg->biosVer[4] = 0;
 #endif
 
-	printk ("megaraid: [%s:%s] detected %d logical drives" CRLFSTR,
-        	megaCfg->fwVer,
-		megaCfg->biosVer,
-		megaCfg->numldrv);
+	printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
+		megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
+	/*
+	 * I hope that I can unmap here, reason DMA transaction is not required any more
+	 * after this
+	 */
 
 	return 0;
 }
@@ -1454,227 +2366,665 @@
 /*----------------------------------------------------------
  * Returns data to be displayed in /proc/scsi/megaraid/X
  *----------------------------------------------------------*/
-int megaraid_proc_info (char *buffer, char **start, off_t offset,
+
+static int megaraid_proc_info (char *buffer, char **start, off_t offset,
 		    int length, int host_no, int inout)
 {
-  *start = buffer;
-  return 0;
+	*start = buffer;
+	return 0;
 }
 
-int mega_findCard (Scsi_Host_Template * pHostTmpl,
-	  u16 pciVendor, u16 pciDev,
-	  long flag)
-{
-  mega_host_config *megaCfg;
-  struct Scsi_Host *host;
-  u_char megaIrq;
-  u32 megaBase;
-  u16 numFound = 0;
-
-  struct pci_dev *pdev = NULL;
-  
-  while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
-    if (pci_enable_device(pdev))
-    	continue;
-    if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
-      u16 magic;
-      pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
-      if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471))
-	continue;		/* not an AMI board */
-    }
-    printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x: in %s\n",
-	    pciVendor,
-	    pciDev,
-	    pdev->slot_name);
-
-    /* Read the base port and IRQ from PCI */
-    megaBase = pci_resource_start (pdev, 0);
-    megaIrq  = pdev->irq;
-
-    if (flag & BOARD_QUARTZ)
-      megaBase = (long) ioremap (megaBase, 128);
-    else
-      megaBase += 0x10;
-
-    /* Initialize SCSI Host structure */
-    host = scsi_register (pHostTmpl, sizeof (mega_host_config));
-    if(host == NULL)
-    	continue;
-    megaCfg = (mega_host_config *) host->hostdata;
-    memset (megaCfg, 0, sizeof (mega_host_config));
-
-    printk ("scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
-	    host->host_no, (u_int) megaBase, megaIrq);
-
-    /* Copy resource info into structure */
-    megaCfg->qCompletedH = NULL;
-    megaCfg->qCompletedT = NULL;
-    megaCfg->qPendingH = NULL;
-    megaCfg->qPendingT = NULL;
-    megaCfg->qFreeH    = NULL;
-    megaCfg->qFreeT    = NULL;
-    megaCfg->qFcnt = 0;
-    megaCfg->qPcnt = 0;
-    megaCfg->qCcnt = 0;
-    megaCfg->flag = flag;
-    megaCfg->host = host;
-    megaCfg->base = megaBase;
-    megaCfg->host->irq = megaIrq;
-    megaCfg->host->io_port = megaBase;
-    megaCfg->host->n_io_port = 16;
-    megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn;
-    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!" CRLFSTR);
-	scsi_unregister (host);
-	continue;
-      }
-    }
-
-    /* Request our IRQ */
-    if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,
-		     "megaraid", megaCfg)) {
-      printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR,
-	      megaIrq);
-      scsi_unregister (host);
-      continue;
-    }
-
-    mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64));
-    mega_i_query_adapter (megaCfg);
-   
-    if (flag == BOARD_QUARTZ) {
-      /* Check to see if this is a Dell PERC RAID controller model 466 */
-      u16 subsysid, subsysvid;
-#if LINUX_VERSION_CODE < 0x20100
-      pcibios_read_config_word (pciBus, pciDevFun,
-				PCI_SUBSYSTEM_VENDOR_ID,
-				&subsysvid);
-      pcibios_read_config_word (pciBus, pciDevFun,
-				PCI_SUBSYSTEM_ID,
-				&subsysid);
-#else
-      pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
-      pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid);
-#endif
-      if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&
-           (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {
-	printk(KERN_WARNING
-"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
-"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
-"megaraid: with those firmware versions on this specific card.  In order\n"
-"megaraid: to protect your data, please upgrade your firmware to version\n"
-"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
-"megaraid: site at\n"
-"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
-	megaraid_release (host);
-#ifdef MODULE	
-	continue;
-#else
-	while(1) schedule_timeout(1 * HZ);
-#endif	
-      }
-    }
-
-    /* Initialize SCBs */
-    if (mega_initSCB (megaCfg)) {
-      megaraid_release (host);
-      continue;
-    }
-
-    numFound++;
-  }
-  return numFound;
+static int mega_findCard (Scsi_Host_Template * pHostTmpl,
+	       u16 pciVendor, u16 pciDev, long flag)
+{
+	mega_host_config *megaCfg = NULL;
+	struct Scsi_Host *host = NULL;
+	u_char pciBus, pciDevFun, megaIrq;
+
+	u16 magic;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	u32 magic64;
+#endif
+
+	int i;
+
+#ifdef __LP64__
+	u64 megaBase;
+#else
+	u32 megaBase;
+#endif
+
+	u16 pciIdx = 0;
+	u16 numFound = 0;
+	u16 subsysid, subsysvid;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+	while (!pcibios_find_device
+	       (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
+#else
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+	struct pci_dev *pdev = NULL;
+#else
+	struct pci_dev *pdev = pci_devices;
+#endif
+
+	while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
+		if (pci_enable_device (pdev))
+			continue;
+		pciBus = pdev->bus->number;
+		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 LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			pcibios_read_config_dword (pciBus, pciDevFun,
+						   PCI_CONF_AMISIG64, &magic64);
+
+			if (magic64 == AMI_64BIT_SIGNATURE)
+				flag |= BOARD_64BIT;
+#endif
+		}
+
+		/* Hmmm...Should we not make this more modularized so that in future we dont add
+		   for each firmware */
+
+		if (flag & BOARD_QUARTZ) {
+			/* Check to see if this is a Dell PERC RAID controller model 466 */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+			pcibios_read_config_word (pciBus, pciDevFun,
+						  PCI_SUBSYSTEM_VENDOR_ID,
+						  &subsysvid);
+			pcibios_read_config_word (pciBus, pciDevFun,
+						  PCI_SUBSYSTEM_ID, &subsysid);
+#else
+			pci_read_config_word (pdev,
+					      PCI_SUBSYSTEM_VENDOR_ID,
+					      &subsysvid);
+			pci_read_config_word (pdev,
+					      PCI_SUBSYSTEM_ID, &subsysid);
+#endif
+			if ((subsysid == 0x1111) && (subsysvid == 0x1111) &&
+			    (!strcmp (megaCfg->fwVer, "3.00")
+			     || !strcmp (megaCfg->fwVer, "3.01"))) {
+				printk (KERN_WARNING
+					"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
+					"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
+					"megaraid: with those firmware versions on this specific card.  In order\n"
+					"megaraid: to protect your data, please upgrade your firmware to version\n"
+					"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
+					"megaraid: site at\n"
+					"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
+				continue;
+			}
+
+			/* If we dont detect this valid subsystem vendor id's 
+			   we refuse to load the driver 
+			   PART of PC200X compliance
+			 */
+
+			if ((subsysvid != AMI_SUBSYS_ID)
+			    && (subsysvid != DELL_SUBSYS_ID)
+			    && (subsysvid != HP_SUBSYS_ID))
+				continue;
+		}
+
+		printk (KERN_INFO
+			"megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
+			pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun),
+			PCI_FUNC (pciDevFun));
+		/* Read the base port and IRQ from PCI */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+		pcibios_read_config_dword (pciBus, pciDevFun,
+					   PCI_BASE_ADDRESS_0,
+					   (u_int *) & megaBase);
+		pcibios_read_config_byte (pciBus, pciDevFun,
+					  PCI_INTERRUPT_LINE, &megaIrq);
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/*0x20300 */
+		megaBase = pdev->base_address[0];
+		megaIrq = pdev->irq;
+#else
+
+		megaBase = pci_resource_start (pdev, 0);
+		megaIrq = pdev->irq;
+#endif
+
+		pciIdx++;
+
+		if (flag & BOARD_QUARTZ) {
+			megaBase = (long) ioremap (megaBase, 128);
+			if (!megaBase)
+				continue;
+		} else
+			megaBase += 0x10;
+
+		/* Initialize SCSI Host structure */
+		host = scsi_register (pHostTmpl, sizeof (mega_host_config));
+		if (!host)
+			goto err_unmap;
+
+		megaCfg = (mega_host_config *) host->hostdata;
+		memset (megaCfg, 0, sizeof (mega_host_config));
+
+		printk (KERN_INFO "scsi%d : Found a MegaRAID controller at 0x%x, IRQ: %d"
+			M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq);
+
+		if (flag & BOARD_64BIT)
+			printk (KERN_INFO "scsi%d : Enabling 64 bit support\n",
+				host->host_no);
+
+		/* Copy resource info into structure */
+		megaCfg->qCompletedH = NULL;
+		megaCfg->qCompletedT = NULL;
+		megaCfg->qPendingH = NULL;
+		megaCfg->qPendingT = NULL;
+		megaCfg->qFreeH = NULL;
+		megaCfg->qFreeT = NULL;
+		megaCfg->qFcnt = 0;
+		megaCfg->qPcnt = 0;
+		megaCfg->qCcnt = 0;
+		megaCfg->lock_free = SPIN_LOCK_UNLOCKED;
+		megaCfg->lock_pend = SPIN_LOCK_UNLOCKED;
+		megaCfg->lock_scsicmd = SPIN_LOCK_UNLOCKED;
+		megaCfg->flag = flag;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		megaCfg->dev = pdev;
+#endif
+		megaCfg->host = host;
+		megaCfg->base = megaBase;
+		megaCfg->host->irq = megaIrq;
+		megaCfg->host->io_port = megaBase;
+		megaCfg->host->n_io_port = 16;
+		megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
+		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!" M_RD_CRLFSTR);
+				goto err_unregister;
+			}
+		}
+
+		/* Request our IRQ */
+		if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ,
+				 "megaraid", megaCfg)) {
+			printk (KERN_WARNING
+				"megaraid: Couldn't register IRQ %d!\n",
+				megaIrq);
+			goto err_release;
+		}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		/*
+		 * unmap while releasing the driver, Is it required to be 
+		 * PCI_DMA_BIDIRECTIONAL 
+		*/
+
+		megaCfg->mailbox64ptr
+		    = pci_alloc_consistent (megaCfg->dev,
+					    sizeof (mega_mailbox64),
+					    &(megaCfg->dma_handle64));
+
+		mega_register_mailbox (megaCfg,
+				       virt_to_bus ((void *) megaCfg->
+						    mailbox64ptr));
+#else
+		/*Taken care */
+		mega_register_mailbox (megaCfg,
+				       virt_to_bus ((void *) &megaCfg->
+						    mailbox64));
+#endif
+
+		mega_i_query_adapter (megaCfg);
+
+		if (mega_is_bios_enabled (megaCfg)) {
+			mega_hbas[numCtlrs].is_bios_enabled = 1;
+		}
+		mega_hbas[numCtlrs].hostdata_addr = megaCfg;
+
+		/* Initialize SCBs */
+		if (mega_init_scb (megaCfg)) {
+			pci_free_consistent (megaCfg->dev,
+					     sizeof (mega_mailbox64),
+					     (void *) megaCfg->mailbox64ptr,
+					     megaCfg->dma_handle64);
+			scsi_unregister (host);
+			continue;
+		}
+
+		/*
+		 * Fill in the structure which needs to be passed back to the
+		 * application when it does an ioctl() for controller related
+		 * information.
+		 */
+
+		i = numCtlrs;
+		numCtlrs++;
+
+		mcontroller[i].base = megaBase;
+		mcontroller[i].irq = megaIrq;
+		mcontroller[i].numldrv = megaCfg->numldrv;
+		mcontroller[i].pcibus = pciBus;
+		mcontroller[i].pcidev = pciDev;
+		mcontroller[i].pcifun = PCI_FUNC (pciDevFun);
+		mcontroller[i].pciid = pciIdx;
+		mcontroller[i].pcivendor = pciVendor;
+		mcontroller[i].pcislot = PCI_SLOT (pciDevFun);
+		mcontroller[i].uid = (pciBus << 8) | pciDevFun;
+
+		numFound++;
+
+		/* Set the Mode of addressing to 64 bit */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64)
+#ifdef __LP64__
+			pdev->dma_mask = 0xffffffffffffffff;
+#else
+			pdev->dma_mask = 0xffffffff;
+#endif
+#endif
+		continue;
+	      err_release:
+		if (flag & BOARD_QUARTZ)
+			release_region (megaBase, 16);
+	      err_unregister:
+		scsi_unregister (host);
+	      err_unmap:
+		if (flag & BOARD_QUARTZ)
+			iounmap ((void *) megaBase);
+	}
+	return numFound;
 }
 
 /*---------------------------------------------------------
  * Detects if a megaraid controller exists in this system
  *---------------------------------------------------------*/
+
 int megaraid_detect (Scsi_Host_Template * pHostTmpl)
 {
-  int count = 0;
+	int ctlridx = 0, count = 0;
 
-#ifdef MODULE
-  if (megaraid)
-      megaraid_setup(megaraid);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/*0x20300 */
+	pHostTmpl->proc_dir = &proc_scsi_megaraid;
+#else
+	pHostTmpl->proc_name = "megaraid";
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/* 0x20100 */
+	if (!pcibios_present ()) {
+		printk (KERN_WARNING "megaraid: PCI bios not present."
+			M_RD_CRLFSTR);
+		return 0;
+	}
 #endif
+	skip_id = -1;
+	if (megaraid && !strncmp (megaraid, "skip", strlen ("skip"))) {
+		if (megaraid[4] != '\0') {
+			skip_id = megaraid[4] - '0';
+			if (megaraid[5] != '\0') {
+				skip_id = (skip_id * 10) + (megaraid[5] - '0');
+			}
+		}
+		skip_id = (skip_id > 15) ? -1 : skip_id;
+	}
 
-  pHostTmpl->proc_name = "megaraid";
+	printk (KERN_INFO "megaraid: " MEGARAID_VERSION M_RD_CRLFSTR);
 
-  printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
+	memset (mega_hbas, 0, sizeof (mega_hbas));
+
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+				PCI_DEVICE_ID_AMI_MEGARAID, 0);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+				PCI_DEVICE_ID_AMI_MEGARAID2, 0);
+	count += mega_findCard (pHostTmpl, 0x8086,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+
+	mega_reorder_hosts ();
+
+#ifdef CONFIG_PROC_FS
+	if (count) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+		mega_proc_dir_entry = proc_mkdir ("megaraid", &proc_root);
+#else
+		mega_proc_dir_entry = create_proc_entry ("megaraid",
+							 S_IFDIR | S_IRUGO |
+							 S_IXUGO, &proc_root);
+#endif
+		if (!mega_proc_dir_entry)
+			printk ("megaraid: failed to create megaraid root\n");
+		else
+			for (ctlridx = 0; ctlridx < count; ctlridx++)
+				mega_create_proc_entry (ctlridx,
+							mega_proc_dir_entry);
+	}
+#endif
 
-  count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
-  count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
-  count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+	/*
+	 * Register the driver as a character device, for appliactions to access
+	 * it for ioctls.
+	 * Ideally, this should go in the init_module() routine, but since it is
+	 * hidden in the file "scsi_module.c" ( included in the end ), we define
+	 * it here
+	 * First argument (major) to register_chrdev implies a dynamic major
+	 * number allocation.
+	 */
+	major = register_chrdev (0, "megadev", &megadev_fops);
+
+	/*
+	 * Register the Shutdown Notification hook in kernel
+	 */
+	if (register_reboot_notifier (&mega_notifier)) {
+		printk ("MegaRAID Shutdown routine not registered!!\n");
+	}
+	init_MUTEX (&mimd_entry_mtx);
 
-  return count;
+	return count;
 }
 
 /*---------------------------------------------------------------------
  * Release the controller's resources
  *---------------------------------------------------------------------*/
-int megaraid_release (struct Scsi_Host *pSHost)
+static int megaraid_release (struct Scsi_Host *pSHost)
+{
+	mega_host_config *megaCfg;
+	mega_mailbox *mbox;
+	u_char mboxData[16];
+	int i;
+
+	megaCfg = (mega_host_config *) pSHost->hostdata;
+	mbox = (mega_mailbox *) mboxData;
+
+	/* Flush cache to disk */
+	memset (mbox, 0, 16);
+	mboxData[0] = 0xA;
+
+	free_irq (megaCfg->host->irq, megaCfg);	/* Must be freed first, otherwise
+						   extra interrupt is generated */
+
+	/* Issue a blocking (interrupts disabled) command to the card */
+	megaIssueCmd (megaCfg, mboxData, NULL, 0);
+
+	/* Free our resources */
+	if (megaCfg->flag & BOARD_QUARTZ) {
+		iounmap ((void *) megaCfg->base);
+	} else {
+		release_region (megaCfg->host->io_port, 16);
+	}
+
+	mega_freeSgList (megaCfg);
+	pci_free_consistent (megaCfg->dev,
+			     sizeof (mega_mailbox64),
+			     (void *) megaCfg->mailbox64ptr,
+			     megaCfg->dma_handle64);
+	scsi_unregister (pSHost);
+
+#ifdef CONFIG_PROC_FS
+	if (megaCfg->controller_proc_dir_entry) {
+		remove_proc_entry ("stat", megaCfg->controller_proc_dir_entry);
+		remove_proc_entry ("status",
+				   megaCfg->controller_proc_dir_entry);
+		remove_proc_entry ("config",
+				   megaCfg->controller_proc_dir_entry);
+		remove_proc_entry ("mailbox",
+				   megaCfg->controller_proc_dir_entry);
+		for (i = 0; i < numCtlrs; i++) {
+			char buf[12] = { 0 };
+			sprintf (buf, "%d", i);
+			remove_proc_entry (buf, mega_proc_dir_entry);
+		}
+		remove_proc_entry ("megaraid", &proc_root);
+	}
+#endif
+
+	/*
+	 * Unregister the character device interface to the driver. Ideally this
+	 * should have been done in cleanup_module routine. Since this is hidden
+	 * in file "scsi_module.c", we do it here.
+	 * major is the major number of the character device returned by call to
+	 * register_chrdev() routine.
+	 */
+	unregister_chrdev (major, "megadev");
+	unregister_reboot_notifier (&mega_notifier);
+
+	return 0;
+}
+
+static int mega_is_bios_enabled (mega_host_config * megacfg)
 {
-  mega_host_config *megaCfg;
-  mega_mailbox *mbox;
-  u_char mboxData[16];
+	mega_mailbox *mboxpnt;
+	unsigned char mbox[16];
+	int ret;
 
-  megaCfg = (mega_host_config *) pSHost->hostdata;
-  mbox = (mega_mailbox *) mboxData;
+	mboxpnt = (mega_mailbox *) mbox;
 
-  /* Flush cache to disk */
-  memset (mbox, 0, 16);
-  mboxData[0] = 0xA;
+	memset (mbox, 0, sizeof (mbox));
+	memset ((void *) megacfg->mega_buffer,
+		0, sizeof (megacfg->mega_buffer));
 
-  free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise
-					   extra interrupt is generated */
+	/*
+	 * issue command to find out if the BIOS is enbled for this controller
+	 */
+	mbox[0] = IS_BIOS_ENABLED;
+	mbox[2] = GET_BIOS;
 
-  /* Issue a blocking (interrupts disabled) command to the card */
-  megaIssueCmd (megaCfg, mboxData, NULL, 0);
+	mboxpnt->xferaddr = virt_to_bus ((void *) megacfg->mega_buffer);
 
-  /* Free our resources */
-  if (megaCfg->flag & BOARD_QUARTZ) {
-    iounmap ((void *) megaCfg->base);
-  }
-  else {
-    release_region (megaCfg->host->io_port, 16);
-  }
+	ret = megaIssueCmd (megacfg, mbox, NULL, 0);
 
-  mega_freeSgList(megaCfg);
-  scsi_unregister (pSHost);
+	return (*(char *) megacfg->mega_buffer);
+}
+
+static void mega_reorder_hosts (void)
+{
+	struct Scsi_Host *shpnt;
+	struct Scsi_Host *shone;
+	struct Scsi_Host *shtwo;
+	mega_host_config *boot_host;
+	int i;
+
+	/*
+	 * Find the (first) host which has it's BIOS enabled
+	 */
+	boot_host = NULL;
+	for (i = 0; i < MAX_CONTROLLERS; i++) {
+		if (mega_hbas[i].is_bios_enabled) {
+			boot_host = mega_hbas[i].hostdata_addr;
+			break;
+		}
+	}
 
-  return 0;
+	if (boot_host == NULL) {
+		printk (KERN_WARNING "megaraid: no BIOS enabled.\n");
+		return;
+	}
+
+	/*
+	 * Traverse through the list of SCSI hosts for our HBA locations
+	 */
+	shone = shtwo = NULL;
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		/* Is it one of ours? */
+		for (i = 0; i < MAX_CONTROLLERS; i++) {
+			if ((mega_host_config *) shpnt->hostdata ==
+			    mega_hbas[i].hostdata_addr) {
+				/* Does this one has BIOS enabled */
+				if (mega_hbas[i].hostdata_addr == boot_host) {
+
+					/* Are we first */
+					if (shtwo == NULL)	/* Yes! */
+						return;
+					else {	/* :-( */
+						shone = shpnt;
+					}
+				} else {
+					if (!shtwo) {
+						/* were we here before? xchng first */
+						shtwo = shpnt;
+					}
+				}
+				break;
+			}
+		}
+		/*
+		 * Have we got the boot host and one which does not have the bios
+		 * enabled.
+		 */
+		if (shone && shtwo)
+			break;
+	}
+	if (shone && shtwo) {
+		mega_swap_hosts (shone, shtwo);
+	}
+
+	return;
 }
 
-static inline void mega_freeSgList(mega_host_config *megaCfg)
+static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo)
 {
-  int i;
+	struct Scsi_Host *prevtoshtwo;
+	struct Scsi_Host *prevtoshone;
+	struct Scsi_Host *save = NULL;;
+
+	/* Are these two nodes adjacent */
+	if (shtwo->next == shone) {
+
+		if (shtwo == scsi_hostlist && shone->next == NULL) {
+
+			/* just two nodes */
+			scsi_hostlist = shone;
+			shone->next = shtwo;
+			shtwo->next = NULL;
+		} else if (shtwo == scsi_hostlist) {
+			/* first two nodes of the list */
+
+			scsi_hostlist = shone;
+			shtwo->next = shone->next;
+			scsi_hostlist->next = shtwo;
+		} else if (shone->next == NULL) {
+			/* last two nodes of the list */
+
+			prevtoshtwo = scsi_hostlist;
+
+			while (prevtoshtwo->next != shtwo)
+				prevtoshtwo = prevtoshtwo->next;
+
+			prevtoshtwo->next = shone;
+			shone->next = shtwo;
+			shtwo->next = NULL;
+		} else {
+			prevtoshtwo = scsi_hostlist;
+
+			while (prevtoshtwo->next != shtwo)
+				prevtoshtwo = prevtoshtwo->next;
+
+			prevtoshtwo->next = shone;
+			shtwo->next = shone->next;
+			shone->next = shtwo;
+		}
+
+	} else if (shtwo == scsi_hostlist && shone->next == NULL) {
+		/* shtwo at head, shone at tail, not adjacent */
+
+		prevtoshone = scsi_hostlist;
+
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		scsi_hostlist = shone;
+		shone->next = shtwo->next;
+		prevtoshone->next = shtwo;
+		shtwo->next = NULL;
+	} else if (shtwo == scsi_hostlist && shone->next != NULL) {
+		/* shtwo at head, shone is not at tail */
+
+		prevtoshone = scsi_hostlist;
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		scsi_hostlist = shone;
+		prevtoshone->next = shtwo;
+		save = shtwo->next;
+		shtwo->next = shone->next;
+		shone->next = save;
+	} else if (shone->next == NULL) {
+		/* shtwo not at head, shone at tail */
+
+		prevtoshtwo = scsi_hostlist;
+		prevtoshone = scsi_hostlist;
+
+		while (prevtoshtwo->next != shtwo)
+			prevtoshtwo = prevtoshtwo->next;
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		prevtoshtwo->next = shone;
+		shone->next = shtwo->next;
+		prevtoshone->next = shtwo;
+		shtwo->next = NULL;
+
+	} else {
+		prevtoshtwo = scsi_hostlist;
+		prevtoshone = scsi_hostlist;
+		save = NULL;;
+
+		while (prevtoshtwo->next != shtwo)
+			prevtoshtwo = prevtoshtwo->next;
+		while (prevtoshone->next != shone)
+			prevtoshone = prevtoshone->next;
+
+		prevtoshtwo->next = shone;
+		save = shone->next;
+		shone->next = shtwo->next;
+		prevtoshone->next = shtwo;
+		shtwo->next = save;
+	}
+	return;
+}
+
+static inline void mega_freeSgList (mega_host_config * megaCfg)
+{
+	int i;
 
-  for (i = 0; i < megaCfg->max_cmds; i++) {
-    if (megaCfg->scbList[i].sgList)
-      kfree (megaCfg->scbList[i].sgList);	/* free sgList */
-  }
+	for (i = 0; i < megaCfg->max_cmds; i++) {
+		if (megaCfg->scbList[i].sgList)
+			pci_free_consistent (megaCfg->dev,
+					     sizeof (mega_64sglist) *
+					     MAX_SGLIST,
+					     megaCfg->scbList[i].sgList,
+					     megaCfg->scbList[i].
+					     dma_sghandle64);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)	/* 0x020400 */
+			kfree (megaCfg->scbList[i].sgList);	/* free sgList */
+#endif
+	}
 }
 
 /*----------------------------------------------
- * Get information about the card/driver 
+ * Get information about the card/driver
  *----------------------------------------------*/
-const char * megaraid_info (struct Scsi_Host *pSHost)
+static const char *megaraid_info (struct Scsi_Host *pSHost)
 {
-  static char buffer[512];
-  mega_host_config *megaCfg;
+	static char buffer[512];
+	mega_host_config *megaCfg;
 
-  megaCfg = (mega_host_config *) pSHost->hostdata;
+	megaCfg = (mega_host_config *) pSHost->hostdata;
 
-  sprintf (buffer, "AMI 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_lun);
-  return buffer;
+	sprintf (buffer,
+		 "AMI 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_lun);
+	return buffer;
 }
 
 /*-----------------------------------------------------------------
@@ -1690,107 +3040,115 @@
  *   0E 01 reserved
  *   0F 01 mailbox busy
  *   10 01 numstatus byte
- *   11 01 status byte 
+ *   11 01 status byte
  *-----------------------------------------------------------------*/
-int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
+static int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *))
 {
-  DRIVER_LOCK_T
-  mega_host_config *megaCfg;
-  mega_scb *pScb;
-
-  megaCfg = (mega_host_config *) SCpnt->host->hostdata;
-  DRIVER_LOCK(megaCfg);
-
-  if (!(megaCfg->flag & (1L << SCpnt->channel))) {
-    if (SCpnt->channel < SCpnt->host->max_channel)
-       printk (/*KERN_INFO*/ "scsi%d: scanning channel %c for devices.\n",
-	    megaCfg->host->host_no,
-	    SCpnt->channel + '1');
-    else
-       printk(/*KERN_INFO*/ "scsi%d: scanning virtual channel for logical drives.\n", megaCfg->host->host_no);
-       
-    megaCfg->flag |= (1L << SCpnt->channel);
-  }
-
-  SCpnt->scsi_done = pktComp;
-
-  /* If driver in abort or reset.. cancel this command */
-  if (megaCfg->flag & IN_ABORT) {
-    SCpnt->result = (DID_ABORT << 16);
-    /* Add Scsi_Command to end of completed queue */
-    if( megaCfg->qCompletedH == NULL ) {
-      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
-    }
-    else {
-      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
-      megaCfg->qCompletedT = SCpnt;
-    }
-    megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
-    megaCfg->qCcnt++;
-
-    DRIVER_UNLOCK(megaCfg);
-    return 0;
-  }
-  else if (megaCfg->flag & IN_RESET) {
-    SCpnt->result = (DID_RESET << 16);
-    /* Add Scsi_Command to end of completed queue */
-    if( megaCfg->qCompletedH == NULL ) {
-      megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
-    }
-    else {
-      megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
-      megaCfg->qCompletedT = SCpnt;
-    }
-    megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
-    megaCfg->qCcnt++;
-
-    DRIVER_UNLOCK(megaCfg);
-    return 0;
-  }
-
-  megaCfg->flag |= IN_QUEUE;
-  /* Allocate and build a SCB request */
-  if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
-              /*build SCpnt for IOCTL_CMD_NEW cmd in mega_ioctl()*/
-    /* Add SCB to the head of the pending queue */
-    /* Add SCB to the head of the pending queue */
-    if( megaCfg->qPendingH == NULL ) {
-      megaCfg->qPendingH = megaCfg->qPendingT = pScb;
-    }
-    else {
-      megaCfg->qPendingT->next = pScb;
-      megaCfg->qPendingT = pScb;
-    }
-    megaCfg->qPendingT->next = NULL;
-    megaCfg->qPcnt++;
-
-      mega_runpendq(megaCfg);
-
-#if LINUX_VERSION_CODE > 0x020024
-    if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
-    {  /* user data from external user buffer */
-          char *user_area;
-          u32  xfer_size;
-
-          init_MUTEX_LOCKED(&pScb->sem);
-          down(&pScb->sem);
-
-          user_area = *((char **)&pScb->SCpnt->cmnd[4]);
-          xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]);
-
-          copy_to_user(user_area,pScb->kern_area,xfer_size);
-
-          kfree(pScb->kern_area);
-
-          mega_freeSCB(megaCfg, pScb);
-    }
-#endif
-  }
+	DRIVER_LOCK_T mega_host_config * megaCfg;
+	mega_scb *pScb;
+	char *user_area = NULL;
+
+	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+	DRIVER_LOCK (megaCfg);
+
+	if (!(megaCfg->flag & (1L << SCpnt->channel))) {
+		if (SCpnt->channel < SCpnt->host->max_channel)
+			printk ( /*KERN_INFO */
+				"scsi%d: scanning channel %c for devices.\n",
+				megaCfg->host->host_no, SCpnt->channel + '1');
+		else
+			printk ( /*KERN_INFO */
+				"scsi%d: scanning virtual channel for logical drives.\n",
+				megaCfg->host->host_no);
+
+		megaCfg->flag |= (1L << SCpnt->channel);
+	}
+
+	SCpnt->scsi_done = pktComp;
 
-  megaCfg->flag &= ~IN_QUEUE;
-  DRIVER_UNLOCK(megaCfg);
+	if (mega_driver_ioctl (megaCfg, SCpnt))
+		return 0;
+
+	/* If driver in abort or reset.. cancel this command */
+	if (megaCfg->flag & IN_ABORT) {
+		SCpnt->result = (DID_ABORT << 16);
+		/* Add Scsi_Command to end of completed queue */
+		if (megaCfg->qCompletedH == NULL) {
+			megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+		} else {
+			megaCfg->qCompletedT->host_scribble =
+			    (unsigned char *) SCpnt;
+			megaCfg->qCompletedT = SCpnt;
+		}
+		megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+		megaCfg->qCcnt++;
+
+		DRIVER_UNLOCK (megaCfg);
+		return 0;
+	} else if (megaCfg->flag & IN_RESET) {
+		SCpnt->result = (DID_RESET << 16);
+		/* Add Scsi_Command to end of completed queue */
+		if (megaCfg->qCompletedH == NULL) {
+			megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
+		} else {
+			megaCfg->qCompletedT->host_scribble =
+			    (unsigned char *) SCpnt;
+			megaCfg->qCompletedT = SCpnt;
+		}
+		megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
+		megaCfg->qCcnt++;
+
+		DRIVER_UNLOCK (megaCfg);
+		return 0;
+	}
 
-  return 0;
+	megaCfg->flag |= IN_QUEUE;
+	/* Allocate and build a SCB request */
+	if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
+		/*build SCpnt for M_RD_IOCTL_CMD_NEW cmd in mega_ioctl() */
+		/* Add SCB to the head of the pending queue */
+		/* Add SCB to the head of the pending queue */
+		if (megaCfg->qPendingH == NULL) {
+			megaCfg->qPendingH = megaCfg->qPendingT = pScb;
+		} else {
+			megaCfg->qPendingT->next = pScb;
+			megaCfg->qPendingT = pScb;
+		}
+		megaCfg->qPendingT->next = NULL;
+		megaCfg->qPcnt++;
+
+		if (mega_runpendq (megaCfg) == -1) {
+			DRIVER_UNLOCK (megaCfg);
+			return 0;
+		}
+
+		if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
+			init_MUTEX_LOCKED (&pScb->ioctl_sem);
+			spin_unlock_irq (&io_request_lock);
+			down (&pScb->ioctl_sem);
+			user_area = *((char **) &pScb->SCpnt->cmnd[4]);
+			if (copy_to_user
+			    (user_area, pScb->buff_ptr, pScb->iDataSize)) {
+				printk
+				    ("megaraid: Error copying ioctl return value to user buffer.\n");
+				pScb->SCpnt->result = (DID_ERROR << 16);
+			}
+			spin_lock_irq (&io_request_lock);
+			DRIVER_LOCK (megaCfg);
+			kfree (pScb->buff_ptr);
+			pScb->buff_ptr = NULL;
+			mega_cmd_done (megaCfg, pScb, pScb->SCpnt->result);
+			mega_rundoneq (megaCfg);
+			mega_runpendq (megaCfg);
+			DRIVER_UNLOCK (megaCfg);
+		}
+
+		megaCfg->flag &= ~IN_QUEUE;
+
+	}
+
+	DRIVER_UNLOCK (megaCfg);
+	return 0;
 }
 
 /*----------------------------------------------------------------------
@@ -1798,167 +3156,404 @@
  *----------------------------------------------------------------------*/
 volatile static int internal_done_flag = 0;
 volatile static int internal_done_errcode = 0;
-static DECLARE_WAIT_QUEUE_HEAD(internal_wait);
+
+static DECLARE_WAIT_QUEUE_HEAD (internal_wait);
 
 static void internal_done (Scsi_Cmnd * SCpnt)
 {
-  internal_done_errcode = SCpnt->result;
-  internal_done_flag++;
-  wake_up(&internal_wait);
+	internal_done_errcode = SCpnt->result;
+	internal_done_flag++;
+	wake_up (&internal_wait);
 }
 
 /* shouldn't be used, but included for completeness */
 
-int megaraid_command (Scsi_Cmnd * SCpnt)
+static int megaraid_command (Scsi_Cmnd * SCpnt)
 {
-  internal_done_flag = 0;
+	internal_done_flag = 0;
 
-  /* Queue command, and wait until it has completed */
-  megaraid_queue (SCpnt, internal_done);
+	/* Queue command, and wait until it has completed */
+	megaraid_queue (SCpnt, internal_done);
 
-  while (!internal_done_flag) {
-	interruptible_sleep_on(&internal_wait);
-  }
+	while (!internal_done_flag) {
+		interruptible_sleep_on (&internal_wait);
+	}
 
-  return internal_done_errcode;
+	return internal_done_errcode;
 }
 
 /*---------------------------------------------------------------------
  * Abort a previous SCSI request
  *---------------------------------------------------------------------*/
-int
-megaraid_abort (Scsi_Cmnd * SCpnt)
+static int megaraid_abort (Scsi_Cmnd * SCpnt)
 {
-  mega_host_config *megaCfg;
-  int   rc; //, idx;
-  mega_scb *pScb;
+	mega_host_config *megaCfg;
+	int rc;			/*, idx; */
+	mega_scb *pScb;
 
-  rc = SCSI_ABORT_NOT_RUNNING;
+	rc = SCSI_ABORT_NOT_RUNNING;
 
-  megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
-  megaCfg->flag |= IN_ABORT;
+	megaCfg->flag |= IN_ABORT;
 
-  for(pScb=megaCfg->qPendingH; pScb; pScb=pScb->next) {
-    if (pScb->SCpnt == SCpnt) {
-      /* Found an aborting command */
+	for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
+		if (pScb->SCpnt == SCpnt) {
+			/* Found an aborting command */
 #if DEBUG
-      showMbox(pScb);
+			showMbox (pScb);
 #endif
 
-/*
- * If the command is queued to be issued to the firmware, abort the scsi cmd,
- * If the command is already aborted in a previous call to the _abort entry
- *  point, return SCSI_ABORT_SNOOZE, suggesting a reset.
- * If the command is issued to the firmware, which might complete after
- *  some time, we will mark the scb as aborted, and return to the mid layer, 
- *  that abort could not be done.
- *  In the ISR, when this command actually completes, we will perform a normal
- *  completion.
- *
- * Oct 27, 1999
- */
-
-      switch(pScb->state) {
-      case SCB_ABORTED: /* Already aborted */
-	rc = SCSI_ABORT_SNOOZE;
-	break;
-      case SCB_ISSUED: /* Waiting on ISR result */
-	rc = SCSI_ABORT_NOT_RUNNING;
-	pScb->state = SCB_ABORTED;
-	break;
-      case SCB_ACTIVE: /* still on the pending queue */
-	mega_freeSCB (megaCfg, pScb);
-	SCpnt->result = (DID_ABORT << 16) ;
-        if( megaCfg->qCompletedH == NULL ) {
-          megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
-        }
-        else {
-          megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
-          megaCfg->qCompletedT = SCpnt;
-        }
-        megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
-        megaCfg->qCcnt++;
-	rc = SCSI_ABORT_SUCCESS;
-        break;
-      default:
-        printk("megaraid_abort: unknown command state!!\n");
-        rc = SCSI_ABORT_NOT_RUNNING;
-	break;
-      }
-      break;
-    }
-  }
+	/*
+	 * If the command is queued to be issued to the firmware, abort the scsi cmd,
+	 * If the command is already aborted in a previous call to the _abort entry
+	 *  point, return SCSI_ABORT_SNOOZE, suggesting a reset.
+	 * If the command is issued to the firmware, which might complete after
+	 *  some time, we will mark the scb as aborted, and return to the mid layer,
+	 *  that abort could not be done.
+	 *  In the ISR, when this command actually completes, we will perform a normal
+	 *  completion.
+	 *
+	 * Oct 27, 1999
+	 */
+
+			switch (pScb->state) {
+			case SCB_ABORTED:	/* Already aborted */
+				rc = SCSI_ABORT_SNOOZE;
+				break;
+			case SCB_ISSUED:	/* Waiting on ISR result */
+				rc = SCSI_ABORT_NOT_RUNNING;
+				pScb->state = SCB_ABORTED;
+				break;
+			case SCB_ACTIVE:	/* still on the pending queue */
+				mega_freeSCB (megaCfg, pScb);
+				SCpnt->result = (DID_ABORT << 16);
+				if (megaCfg->qCompletedH == NULL) {
+					megaCfg->qCompletedH =
+					    megaCfg->qCompletedT = SCpnt;
+				} else {
+					megaCfg->qCompletedT->host_scribble =
+					    (unsigned char *) SCpnt;
+					megaCfg->qCompletedT = SCpnt;
+				}
+				megaCfg->qCompletedT->host_scribble =
+				    (unsigned char *) NULL;
+				megaCfg->qCcnt++;
+				rc = SCSI_ABORT_SUCCESS;
+				break;
+			default:
+				printk
+				    ("megaraid_abort: unknown command state!!\n");
+				rc = SCSI_ABORT_NOT_RUNNING;
+				break;
+			}
+			break;
+		}
+	}
 
-  megaCfg->flag &= ~IN_ABORT;
+	megaCfg->flag &= ~IN_ABORT;
 
 #if DEBUG
-if(megaCfg->flag & IN_QUEUE)  printk("ma:flag is in queue\n");
-if(megaCfg->qCompletedH == NULL) printk("ma:qchead == null\n");
+	if (megaCfg->flag & IN_QUEUE)
+		printk ("ma:flag is in queue\n");
+	if (megaCfg->qCompletedH == NULL)
+		printk ("ma:qchead == null\n");
 #endif
-  
-/*
- * This is required here to complete any completed requests to be communicated
- * over to the mid layer.
- * Calling just mega_rundoneq() did not work.
- */
-if(megaCfg->qCompletedH) {
-  SCpnt = megaCfg->qCompletedH;
-  megaCfg->qCompletedH = (Scsi_Cmnd *)SCpnt->host_scribble;
-  megaCfg->qCcnt--;
-
-  SCpnt->host_scribble = (unsigned char *) NULL ;
-  /* Callback */
-  callDone (SCpnt);
-}
-  mega_rundoneq(megaCfg);
 
-  return rc;
+	/*
+	 * This is required here to complete any completed requests to be communicated
+	 * over to the mid layer.
+	 * Calling just mega_rundoneq() did not work.
+	 */
+	if (megaCfg->qCompletedH) {
+		SCpnt = megaCfg->qCompletedH;
+		megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble;
+		megaCfg->qCcnt--;
+
+		SCpnt->host_scribble = (unsigned char *) NULL;
+		/* Callback */
+		callDone (SCpnt);
+	}
+	mega_rundoneq (megaCfg);
+
+	return rc;
 }
 
 /*---------------------------------------------------------------------
  * Reset a previous SCSI request
  *---------------------------------------------------------------------*/
-int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
+
+static int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags)
+{
+	mega_host_config *megaCfg;
+	int idx;
+	int rc;
+	mega_scb *pScb;
+
+	rc = SCSI_RESET_NOT_RUNNING;
+	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
+
+	megaCfg->flag |= IN_RESET;
+
+	printk
+	    ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",
+	     SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
+	     SCpnt->target, SCpnt->lun, rstflags);
+
+	TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
+		SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
+		SCpnt->target, SCpnt->lun));
+
+	/*
+	 * Walk list of SCBs for any that are still outstanding
+	 */
+	for (idx = 0; idx < megaCfg->max_cmds; idx++) {
+		if (megaCfg->scbList[idx].state != SCB_FREE) {
+			SCpnt = megaCfg->scbList[idx].SCpnt;
+			pScb = &megaCfg->scbList[idx];
+			if (SCpnt != NULL) {
+				pScb->state = SCB_RESET;
+				break;
+			}
+		}
+	}
+
+	megaCfg->flag &= ~IN_RESET;
+
+	mega_rundoneq (megaCfg);
+	return rc;
+}
+
+#ifdef CONFIG_PROC_FS
+/* Following code handles /proc fs  */
+static int proc_printf (mega_host_config * megaCfg, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	if (megaCfg->procidx > PROCBUFSIZE)
+		return 0;
+
+	va_start (args, fmt);
+	i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args);
+	va_end (args);
+
+	megaCfg->procidx += i;
+	return i;
+}
+
+static int proc_read_config (char *page, char **start, off_t offset,
+		  int count, int *eof, void *data)
 {
-  mega_host_config *megaCfg;
-  int idx;
-  int rc;
-  mega_scb *pScb;
-
-  rc = SCSI_RESET_NOT_RUNNING;
-  megaCfg = (mega_host_config *) SCpnt->host->hostdata;
-
-  megaCfg->flag |= IN_RESET;
-
-  printk ("megaraid_RESET: %.08lx cmd=%.02x <c=%d.t=%d.l=%d>, flag = %x\n",
-	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
-	  SCpnt->lun, rstflags);
-
-  TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
-	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
-	  SCpnt->lun));
-
-  /*
-   * Walk list of SCBs for any that are still outstanding
-   */
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].state != SCB_FREE) {
-      SCpnt = megaCfg->scbList[idx].SCpnt;
-      pScb = &megaCfg->scbList[idx];
-      if (SCpnt != NULL) {
-        pScb->state = SCB_RESET;
-        break;
-      }
-    }
-  }
 
-  megaCfg->flag &= ~IN_RESET;
+	mega_host_config *megaCfg = (mega_host_config *) data;
+
+	*start = page;
+
+	if (megaCfg->productInfo.ProductName[0] != 0)
+		proc_printf (megaCfg, "%s\n", megaCfg->productInfo.ProductName);
+
+	proc_printf (megaCfg, "Controller Type: ");
 
-  mega_rundoneq(megaCfg);
-  return rc;
+	if (megaCfg->flag & BOARD_QUARTZ)
+		proc_printf (megaCfg, "438/466/467/471/493\n");
+	else
+		proc_printf (megaCfg, "418/428/434\n");
+
+	if (megaCfg->flag & BOARD_40LD)
+		proc_printf (megaCfg,
+			     "Controller Supports 40 Logical Drives\n");
+
+	if (megaCfg->flag & BOARD_64BIT)
+		proc_printf (megaCfg,
+			     "Controller / Driver uses 64 bit memory addressing\n");
+
+	proc_printf (megaCfg, "Base = %08x, Irq = %d, ", megaCfg->base,
+		     megaCfg->host->irq);
+
+	proc_printf (megaCfg, "Logical Drives = %d, Channels = %d\n",
+		     megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent);
+
+	proc_printf (megaCfg, "Version =%s:%s, DRAM = %dMb\n",
+		     megaCfg->fwVer, megaCfg->biosVer,
+		     megaCfg->productInfo.DramSize);
+
+	proc_printf (megaCfg,
+		     "Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+		     megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds);
+	COPY_BACK;
+	return count;
 }
 
+static int proc_read_stat (char *page, char **start, off_t offset,
+		int count, int *eof, void *data)
+{
+	int i;
+	mega_host_config *megaCfg = (mega_host_config *) data;
+
+	*start = page;
+
+	proc_printf (megaCfg, "Statistical Information for this controller\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020100 */
+	proc_printf (megaCfg, "Interrupts Collected = %Lu\n",
+		     megaCfg->nInterrupts);
+#else
+	proc_printf (megaCfg, "Interrupts Collected = %u\n",
+		     (u32) megaCfg->nInterrupts);
+#endif
+
+	for (i = 0; i < megaCfg->numldrv; i++) {
+		proc_printf (megaCfg, "Logical Drive %d:\n", i);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		proc_printf (megaCfg,
+			     "\tReads Issued = %Lu, Writes Issued = %Lu\n",
+			     megaCfg->nReads[i], megaCfg->nWrites[i]);
+
+		proc_printf (megaCfg,
+			     "\tSectors Read = %Lu, Sectors Written = %Lu\n\n",
+			     megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
+#else
+		proc_printf (megaCfg,
+			     "\tReads Issued = %10u, Writes Issued = %10u\n",
+			     (u32) megaCfg->nReads[i],
+			     (u32) megaCfg->nWrites[i]);
+
+		proc_printf (megaCfg,
+			     "\tSectors Read = %10u, Sectors Written = %10u\n\n",
+			     (u32) megaCfg->nReadBlocks[i],
+			     (u32) megaCfg->nWriteBlocks[i]);
+#endif
+
+	}
+
+	COPY_BACK;
+	return count;
+}
+
+static int proc_read_status (char *page, char **start, off_t offset,
+		  int count, int *eof, void *data)
+{
+	mega_host_config *megaCfg = (mega_host_config *) data;
+	*start = page;
+
+	proc_printf (megaCfg, "TBD\n");
+	COPY_BACK;
+	return count;
+}
+
+static int proc_read_mbox (char *page, char **start, off_t offset,
+		int count, int *eof, void *data)
+{
+
+	mega_host_config *megaCfg = (mega_host_config *) data;
+	volatile mega_mailbox *mbox = megaCfg->mbox;
+
+	*start = page;
+
+	proc_printf (megaCfg, "Contents of Mail Box Structure\n");
+	proc_printf (megaCfg, "  Fw Command   = 0x%02x\n", mbox->cmd);
+	proc_printf (megaCfg, "  Cmd Sequence = 0x%02x\n", mbox->cmdid);
+	proc_printf (megaCfg, "  No of Sectors= %04d\n", mbox->numsectors);
+	proc_printf (megaCfg, "  LBA          = 0x%02x\n", mbox->lba);
+	proc_printf (megaCfg, "  DTA          = 0x%08x\n", mbox->xferaddr);
+	proc_printf (megaCfg, "  Logical Drive= 0x%02x\n", mbox->logdrv);
+	proc_printf (megaCfg, "  No of SG Elmt= 0x%02x\n", mbox->numsgelements);
+	proc_printf (megaCfg, "  Busy         = %01x\n", mbox->busy);
+	proc_printf (megaCfg, "  Status       = 0x%02x\n", mbox->status);
+
+	/* proc_printf(megaCfg, "Dump of MailBox\n");
+	for (i = 0; i < 16; i++)
+        	proc_printf(megaCfg, "%02x ",*(mbox + i));
+
+	proc_printf(megaCfg, "\n\nNumber of Status = %02d\n",mbox->numstatus);
+
+	for (i = 0; i < 46; i++) {
+        	proc_printf(megaCfg,"%02d ",*(mbox + 16 + i));
+        if (i%16)
+                proc_printf(megaCfg,"\n");
+	}
+
+	if (!mbox->numsgelements) {
+	        dta = phys_to_virt(mbox->xferaddr);
+	        for (i = 0; i < mbox->numsgelements; i++)
+	                if (dta) {
+	                        proc_printf(megaCfg,"Addr = %08x\n", (ulong)*(dta + i));                        proc_printf(megaCfg,"Length = %08x\n",
+	                                (ulong)*(dta + i + 4));
+	                }
+	}*/
+	COPY_BACK;
+	return count;
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \
+                                         S_IRUSR | S_IFREG,\
+                                         controller_proc_dir_entry,\
+                                         fxn, megaCfg)
+#else
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg)
+
+static struct proc_dir_entry *
+create_proc_read_entry (const char *string,
+			int mode,
+			struct proc_dir_entry *parent,
+			read_proc_t * fxn, mega_host_config * megaCfg)
+{
+	struct proc_dir_entry *temp = NULL;
+
+	temp = kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
+	if (!temp)
+		return NULL;
+	memset (temp, 0, sizeof (struct proc_dir_entry));
+
+	if ((temp->name = kmalloc (strlen (string) + 1, GFP_KERNEL)) == NULL) {
+		kfree (temp);
+		return NULL;
+	}
+
+	strcpy ((char *) temp->name, string);
+	temp->namelen = strlen (string);
+	temp->mode = mode; /*S_IFREG | S_IRUSR */ ;
+	temp->data = (void *) megaCfg;
+	temp->read_proc = fxn;
+	proc_register (parent, temp);
+	return temp;
+}
+#endif
+
+static void mega_create_proc_entry (int index, struct proc_dir_entry *parent)
+{
+	u_char string[64] = { 0 };
+	mega_host_config *megaCfg = megaCtlrs[index];
+	struct proc_dir_entry *controller_proc_dir_entry = NULL;
+
+	sprintf (string, "%d", index);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)	/*0x20300 */
+	controller_proc_dir_entry =
+	    megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent);
+#else
+	controller_proc_dir_entry =
+	    megaCfg->controller_proc_dir_entry =
+	    create_proc_entry (string, S_IFDIR | S_IRUGO | S_IXUGO, parent);
+#endif
+
+	if (!controller_proc_dir_entry)
+		printk ("\nmegaraid: proc_mkdir failed\n");
+	else {
+		megaCfg->proc_read =
+		    CREATE_READ_PROC ("config", proc_read_config);
+		megaCfg->proc_status =
+		    CREATE_READ_PROC ("status", proc_read_status);
+		megaCfg->proc_stat = CREATE_READ_PROC ("stat", proc_read_stat);
+		megaCfg->proc_mbox =
+		    CREATE_READ_PROC ("mailbox", proc_read_mbox);
+	}
+
+}
+#endif				/* CONFIG_PROC_FS */
+
 /*-------------------------------------------------------------
  * Return the disk geometry for a particular disk
  * Input:
@@ -1969,51 +3564,749 @@
  *     geom[1] = sectors
  *     geom[2] = cylinders
  *-------------------------------------------------------------*/
-int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
+static int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
+{
+	int heads, sectors, cylinders;
+	mega_host_config *megaCfg;
+
+	/* Get pointer to host config structure */
+	megaCfg = (mega_host_config *) disk->device->host->hostdata;
+
+	/* Default heads (64) & sectors (32) */
+	heads = 64;
+	sectors = 32;
+	cylinders = disk->capacity / (heads * sectors);
+
+	/* Handle extended translation size for logical drives > 1Gb */
+	if (disk->capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+		cylinders = disk->capacity / (heads * sectors);
+	}
+
+	/* return result */
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+}
+
+/*
+ * This routine will be called when the use has done a forced shutdown on the
+ * system. Flush the Adapter cache, that's the most we can do.
+ */
+static int megaraid_reboot_notify (struct notifier_block *this, unsigned long code,
+			void *unused)
+{
+	struct Scsi_Host *pSHost;
+	mega_host_config *megaCfg;
+	mega_mailbox *mbox;
+	u_char mboxData[16];
+	int i;
+
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		for (i = 0; i < numCtlrs; i++) {
+			pSHost = megaCtlrs[i]->host;
+
+			megaCfg = (mega_host_config *) pSHost->hostdata;
+			mbox = (mega_mailbox *) mboxData;
+
+			/* Flush cache to disk */
+			memset (mbox, 0, 16);
+			mboxData[0] = 0xA;
+
+			/*
+			 * Free irq, otherwise extra interrupt is generated
+			 */
+			free_irq (megaCfg->host->irq, megaCfg);
+
+			/*
+			   * Issue a blocking (interrupts disabled) command to
+			   * the card
+			 */
+			megaIssueCmd (megaCfg, mboxData, NULL, 0);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+static int mega_init_scb (mega_host_config * megacfg)
+{
+	int idx;
+
+#if DEBUG
+	if (megacfg->max_cmds >= MAX_COMMANDS) {
+		printk ("megaraid:ctlr max cmds = %x : MAX_CMDS = %x",
+			megacfg->max_cmds, MAX_COMMANDS);
+	}
+#endif
+
+	for (idx = megacfg->max_cmds - 1; idx >= 0; idx--) {
+
+		megacfg->scbList[idx].idx = idx;
+
+		/*
+		 * ISR will make this flag zero to indicate the command has been
+		 * completed. This is only for user ioctl calls. Rest of the driver
+		 * and the mid-layer operations are not connected with this flag.
+		 */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		megacfg->scbList[idx].sgList =
+		    pci_alloc_consistent (megacfg->dev,
+					  sizeof (mega_64sglist) * MAX_SGLIST,
+					  &(megacfg->scbList[idx].
+					    dma_sghandle64));
+
+		megacfg->scbList[idx].sg64List =
+		    (mega_64sglist *) megacfg->scbList[idx].sgList;
+#else
+		megacfg->scbList[idx].sgList = kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA);
+#endif
+
+		if (megacfg->scbList[idx].sgList == NULL) {
+			printk (KERN_WARNING
+				"Can't allocate sglist for id %d\n", idx);
+			mega_freeSgList (megacfg);
+			return -1;
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev,
+					  sizeof (mega_passthru),
+					  &(megacfg->scbList[idx].
+					    dma_passthruhandle64));
+
+		if (megacfg->scbList[idx].pthru == NULL) {
+			printk (KERN_WARNING
+				"Can't allocate passthru for id %d\n", idx);
+		}
+		/* 
+		 * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA 
+		 */
+		megacfg->scbList[idx].bounce_buffer = pci_alloc_consistent (megacfg->dev,
+					  256,
+					  &(megacfg->scbList[idx].
+					    dma_bounce_buffer));
+
+		if (!megacfg->scbList[idx].bounce_buffer)
+			printk
+			    ("megaraid: allocation for bounce buffer failed\n");
+
+		megacfg->scbList[idx].dma_type = M_RD_DMA_TYPE_NONE;
+#endif
+
+		if (idx < MAX_COMMANDS) {
+			/*
+			 * Link to free list
+			 * lock not required since we are loading the driver, so no
+			 * commands possible right now.
+			 */
+			enq_scb_freelist (megacfg, &megacfg->scbList[idx],
+					  NO_LOCK, INTR_ENB);
+
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Enqueues a SCB
+ */
+static void enq_scb_freelist (mega_host_config * megacfg, mega_scb * scb, int lock,
+		  int intr)
+{
+
+	if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
+		if (intr == INTR_DIS)
+			spin_lock_irq (&megacfg->lock_free);
+		else
+			spin_lock (&megacfg->lock_free);
+	}
+
+	scb->state = SCB_FREE;
+	scb->SCpnt = NULL;
+
+	if (megacfg->qFreeH == (mega_scb *) NULL) {
+		megacfg->qFreeH = megacfg->qFreeT = scb;
+	} else {
+		megacfg->qFreeT->next = scb;
+		megacfg->qFreeT = scb;
+	}
+
+	megacfg->qFreeT->next = NULL;
+	megacfg->qFcnt++;
+
+	if (lock == INTERNAL_LOCK || intr == INTR_DIS) {
+		if (intr == INTR_DIS)
+			spin_unlock_irq (&megacfg->lock_free);
+		else
+			spin_unlock (&megacfg->lock_free);
+	}
+}
+
+/*
+ * Routines for the character/ioctl interface to the driver
+ */
+static int megadev_open (struct inode *inode, struct file *filep)
+{
+	MOD_INC_USE_COUNT;
+	return 0;		/* success */
+}
+
+static int megadev_ioctl_entry (struct inode *inode, struct file *filep,
+		     unsigned int cmd, unsigned long arg)
+{
+	int ret = -1;
+
+	/*
+	 * We do not allow parallel ioctls to the driver as of now.
+	 */
+	down (&mimd_entry_mtx);
+	ret = megadev_ioctl (inode, filep, cmd, arg);
+	up (&mimd_entry_mtx);
+
+	return ret;
+
+}
+
+static int megadev_ioctl (struct inode *inode, struct file *filep,
+	       unsigned int cmd, unsigned long arg)
 {
-  int heads, sectors, cylinders;
-  mega_host_config *megaCfg;
+	int adapno;
+	kdev_t dev;
+	u32 inlen;
+	struct uioctl_t ioc;
+	char *kphysaddr = NULL;
+	int nadap = numCtlrs;
+	int npages;
+	u8 opcode;
+	int order = 0;
+	u32 outlen;
+	int ret;
+	u8 subopcode;
+	Scsi_Cmnd *scsicmd;
+	struct Scsi_Host *shpnt;
+	char *uaddr;
+	struct uioctl_t *uioc;
+	IO_LOCK_T;
+
+	if (!inode || !(dev = inode->i_rdev))
+		return -EINVAL;
+
+	if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC)
+		return (-EINVAL);
+
+	/*
+	 * We do not transfer more than IOCTL_MAX_DATALEN (see megaraid.h) with
+	 * this interface.If the user needs to transfer more than this,he should
+	 * use 0x81 command op-code.
+	 */
+
+	/*
+	 * Get the user ioctl structure
+	 */
+	ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t));
+
+	if (ret)
+		return ret;
+
+	if(copy_from_user (&ioc, (char *) arg, sizeof (struct uioctl_t)))
+		return -EFAULT;
+
+	/*
+	 * The first call the applications should make is to find out the number
+	 * of controllers in the system. The next logical call should be for
+	 * getting the list of controllers in the system as detected by the
+	 * driver.
+	 */
+
+	/*
+	 * Get the opcode and subopcode for the commands
+	 */
+	opcode = ioc.ui.fcs.opcode;
+	subopcode = ioc.ui.fcs.subopcode;
+
+	switch (opcode) {
+	case M_RD_DRIVER_IOCTL_INTERFACE:
+		switch (subopcode) {
+		case MEGAIOC_QDRVRVER:	/* Query driver version */
+			put_user (driver_ver, (u32 *) ioc.data);
+			return 0;
+
+		case MEGAIOC_QNADAP:	/* Get # of adapters */
+			put_user (nadap, (int *) ioc.data);
+			return nadap;
+
+		case MEGAIOC_QADAPINFO:	/* Get adapter information */
+			/*
+			 * which adapter?
+			 */
+			adapno = ioc.ui.fcs.adapno;
+
+			/*
+			 * The adapter numbers do not start with 0, at least in
+			 * the user space. This is just to make sure, 0 is not the
+			 * default value which will refer to adapter 1. So the
+			 * user needs to make use of macros MKADAP() and GETADAP()
+			 * (See megaraid.h) while making ioctl() call.
+			 */
+			adapno = GETADAP (adapno);
+
+			if (adapno >= numCtlrs)
+				return (-ENODEV);
+
+			ret = verify_area (VERIFY_WRITE,
+					   ioc.data,
+					   sizeof (struct mcontroller));
+			if (ret)
+				return ret;
+
+			/*
+			 * Copy struct mcontroller to user area
+			 */
+			copy_to_user (ioc.data,
+				      mcontroller + adapno,
+				      sizeof (struct mcontroller));
+			return 0;
+
+		default:
+			return (-EINVAL);
+
+		}		/* inner switch */
+		break;
+
+	case M_RD_IOCTL_CMD_NEW:
+		/* which adapter?  */
+		adapno = ioc.ui.fcs.adapno;
+
+		/* See comment above: MEGAIOC_QADAPINFO */
+		adapno = GETADAP (adapno);
+
+		if (adapno >= numCtlrs)
+			return (-ENODEV);
+
+		/* Check for zero length buffer. */
+		if (!ioc.ui.fcs.length)
+			return -EINVAL;
 
-  /* Get pointer to host config structure */
-  megaCfg = (mega_host_config *) disk->device->host->hostdata;
+		/* save the user address */
+		uaddr = ioc.ui.fcs.buffer;
 
-  /* Default heads (64) & sectors (32) */
-  heads = 64;
-  sectors = 32;
-  cylinders = disk->capacity / (heads * sectors);
-
-  /* Handle extended translation size for logical drives > 1Gb */
-  if (disk->capacity >= 0x200000) {
-    heads = 255;
-    sectors = 63;
-    cylinders = disk->capacity / (heads * sectors);
-  }
-
-  /* return result */
-  geom[0] = heads;
-  geom[1] = sectors;
-  geom[2] = cylinders;
-
-  return 0;
-}
-
-static int __init megaraid_setup(char *str)
-{
-  skip_id = -1;
-  if (str && !strncmp(str, "skip", strlen("skip"))) {
-      if (str[4] != '\0') {
-          skip_id = str[4] - '0';
-          if (str[5] != '\0') {
-              skip_id = (skip_id * 10) + (str[5] - '0');
-          }
-      }
-      skip_id = (skip_id > 15) ? -1 : skip_id;
-  }
-  return 1;
+/*
+* For M_RD_IOCTL_CMD_NEW commands, the fields outlen and inlen of uioctl_t
+* structure are treated as flags. If outlen is 1, the data is
+* transferred from the device and if inlen is 1, the data is
+* transferred to the device.
+*/
+		outlen = ioc.outlen;
+		inlen = ioc.inlen;
+#if 0
+		if (inlen && outlen)
+			return -EINVAL;
+#endif
+		if (outlen) {
+			ret = verify_area (VERIFY_WRITE,
+					   (char *) ioc.ui.fcs.buffer,
+					   ioc.ui.fcs.length);
+			if (ret)
+				return ret;
+		} else if (inlen) {
+			ret = verify_area (VERIFY_READ,
+					   (char *) ioc.ui.fcs.buffer,
+					   ioc.ui.fcs.length);
+
+			if (ret)
+				return ret;
+		}
+
+		/* How many pages required of size PAGE_SIZE */
+		npages = ioc.ui.fcs.length / PAGE_SIZE;
+		/* Do we need one more? */
+
+		if (ioc.ui.fcs.length % PAGE_SIZE)
+			npages++;
+
+		/* ioctl does not support data xfer > 32KB */
+		if (npages == 1)
+			order = 0;
+		else if (npages == 2)
+			order = 1;
+		else if (npages <= 4)
+			order = 2;
+		else if (npages <= 8)
+			order = 3;
+		else
+			return -EINVAL;
+
+		if (outlen || inlen) {
+			/*
+			 * Allocate kernel space for npages.
+			 *
+			 * Since we need the memory for DMA, it needs to be physically
+			 * contiguous. __get_free_pags() return consecutive free pages
+			 * in kernel space.
+			 * Note: We don't do __get_dma_pages(), since for PCI devices,
+			 * the DMA memory is not restriceted to 16M, which is ensured
+			 * by __get_dma_pages()
+			 */
+
+			if ((kphysaddr = (char *) __get_free_pages (GFP_KERNEL,
+								    order)) ==
+			    0) {
+				printk (KERN_INFO
+					"megaraid:allocation failed\n");
+				return -ENOMEM;
+			}
+
+			memset (kphysaddr, 0, npages * PAGE_SIZE);
+			ioc.ui.fcs.buffer = kphysaddr;
+
+			if (inlen) {
+				/* copyin the user data */
+				copy_from_user (kphysaddr,
+						(char *) uaddr,
+						ioc.ui.fcs.length);
+			}
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd),
+						 GFP_KERNEL | GFP_DMA);
+		memset (scsicmd, 0, sizeof (Scsi_Cmnd));
+#else
+		scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
+							  GFP_ATOMIC | GFP_DMA);
+#endif
+		if (!scsicmd) {
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, order);
+			return -ENOMEM;
+		}
+
+		scsicmd->host = NULL;
+
+		/*
+		 * Find this host
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostdata ==
+			    (unsigned long *) megaCtlrs[adapno])
+				scsicmd->host = shpnt;
+		}
+
+		if (scsicmd->host == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			kfree (scsicmd);
+#else
+			scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, order);
+			return -ENODEV;
+		}
+
+		scsicmd->cmnd[0] = MEGADEVIOC;
+		scsicmd->request_buffer = (void *) &ioc;
+
+		init_MUTEX_LOCKED (&mimd_ioctl_sem);
+
+		IO_LOCK;
+		megaraid_queue (scsicmd, megadev_ioctl_done);
+
+		IO_UNLOCK;
+
+		down (&mimd_ioctl_sem);
+
+		if (!scsicmd->result && outlen) {
+			copy_to_user (uaddr, kphysaddr, ioc.ui.fcs.length);
+		}
+
+		/*
+		 * copyout the result
+		 */
+		uioc = (struct uioctl_t *) arg;
+
+		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+		} else {
+			put_user (1, &uioc->mbox[16]);	/* numstatus */
+			/* status */
+			put_user (scsicmd->result, &uioc->mbox[17]);
+		}
+
+		if (kphysaddr) {
+			free_pages ((ulong) kphysaddr, order);
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
+		kfree (scsicmd);
+#else
+		scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+
+		return ret;
+
+	case M_RD_IOCTL_CMD:
+		/* which adapter?  */
+		adapno = ioc.ui.fcs.adapno;
+		/* See comment above: MEGAIOC_QADAPINFO */
+		adapno = GETADAP (adapno);
+
+		if (adapno >= numCtlrs)
+			return (-ENODEV);
+
+		/* save the user address */
+		uaddr = ioc.data;
+		outlen = ioc.outlen;
+		inlen = ioc.inlen;
+
+		if ((outlen >= IOCTL_MAX_DATALEN)
+		    || (inlen >= IOCTL_MAX_DATALEN))
+			return (-EINVAL);
+
+		if (outlen) {
+			ret = verify_area (VERIFY_WRITE, ioc.data, outlen);
+			if (ret)
+				return ret;
+		} else if (inlen) {
+			ret = verify_area (VERIFY_READ, ioc.data, inlen);
+
+			if (ret)
+				return ret;
+		}
+
+		if (outlen || inlen) {
+			/*
+			 * Allocate a page of kernel space.
+			 */
+			if ((kphysaddr =
+			     (char *) __get_free_pages (GFP_KERNEL, 0)) == 0) {
+
+				printk (KERN_INFO
+					"megaraid:allocation failed\n");
+				return -ENOMEM;
+			}
+
+			memset (kphysaddr, 0, PAGE_SIZE);
+			ioc.data = kphysaddr;
+
+			if (inlen) {
+				if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+					/* copyin the user data */
+					copy_from_user (kphysaddr,
+							uaddr,
+							ioc.pthru.dataxferlen);
+				} else {
+					copy_from_user (kphysaddr,
+							uaddr, inlen);
+				}
+			}
+		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
+		scsicmd = (Scsi_Cmnd *) kmalloc (sizeof (Scsi_Cmnd),
+						 GFP_KERNEL | GFP_DMA);
+		memset (scsicmd, 0, sizeof (Scsi_Cmnd));
+#else
+		scsicmd = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd),
+							  GFP_ATOMIC | GFP_DMA);
+#endif
+
+		if (!scsicmd) {
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, 0);
+			return -ENOMEM;
+		}
+
+		scsicmd->host = NULL;
+
+		/*
+		 * Find this host in the hostlist
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostdata ==
+			    (unsigned long *) megaCtlrs[adapno])
+				scsicmd->host = shpnt;
+		}
+
+		if (scsicmd->host == NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			kfree (scsicmd);
+#else
+			scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+			if (kphysaddr)
+				free_pages ((unsigned long) kphysaddr, 0);
+
+			return -ENODEV;
+		}
+
+		scsicmd->cmnd[0] = MEGADEVIOC;
+		scsicmd->request_buffer = (void *) &ioc;
+
+		init_MUTEX_LOCKED (&mimd_ioctl_sem);
+
+		IO_LOCK;
+		megaraid_queue (scsicmd, megadev_ioctl_done);
+
+		IO_UNLOCK;
+		down (&mimd_ioctl_sem);
+
+		if (!scsicmd->result && outlen) {
+			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+				copy_to_user (uaddr,
+					      kphysaddr, ioc.pthru.dataxferlen);
+			} else {
+				copy_to_user (uaddr, kphysaddr, outlen);
+			}
+		}
+
+		/*
+		 * copyout the result
+		 */
+		uioc = (struct uioctl_t *) arg;
+
+		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
+			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+		} else {
+			put_user (1, &uioc->mbox[16]);	/* numstatus */
+			/* status */
+			put_user (scsicmd->result, &uioc->mbox[17]);
+		}
+
+		if (kphysaddr)
+			free_pages ((unsigned long) kphysaddr, 0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		kfree (scsicmd);
+#else
+		scsi_init_free ((char *) scsicmd, sizeof (Scsi_Cmnd));
+#endif
+		return ret;
+
+	default:
+		return (-EINVAL);
+
+	}			/* Outer switch */
+
+	return 0;
 }
 
-__setup("megaraid=", megaraid_setup);
+static void
+megadev_ioctl_done (Scsi_Cmnd * sc)
+{
+	up (&mimd_ioctl_sem);
+}
+
+static mega_scb *
+megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc)
+{
+	u8 cmd;
+	struct uioctl_t *ioc = NULL;
+	mega_mailbox *mbox = NULL;
+	mega_ioctl_mbox *mboxioc = NULL;
+	struct mbox_passthru *mboxpthru = NULL;
+	mega_scb *scb = NULL;
+	mega_passthru *pthru = NULL;
+
+	if ((scb = mega_allocateSCB (megacfg, sc)) == NULL) {
+		sc->result = (DID_ERROR << 16);
+		callDone (sc);
+		return NULL;
+	}
+
+	ioc = (struct uioctl_t *) sc->request_buffer;
+
+	memcpy (scb->mboxData, ioc->mbox, sizeof (scb->mboxData));
+
+	/* The generic mailbox */
+	mbox = (mega_mailbox *) ioc->mbox;
+
+	/*
+	 * Get the user command
+	 */
+	cmd = ioc->mbox[0];
+
+	switch (cmd) {
+	case MEGA_MBOXCMD_PASSTHRU:
+		/*
+		   * prepare the SCB with information from the user ioctl structure
+		 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pthru = scb->pthru;
+#else
+		pthru = &scb->pthru;
+#endif
+		memcpy (pthru, &ioc->pthru, sizeof (mega_passthru));
+		mboxpthru = (struct mbox_passthru *) scb->mboxData;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		if (megacfg->flag & BOARD_64BIT) {
+			/* This is just a sample with one element 
+			   * This if executes onlu on 2.4 kernels
+			 */
+			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
+			scb->sg64List[0].address =
+			    pci_map_single (megacfg->dev,
+					    ioc->data,
+					    4096, PCI_DMA_BIDIRECTIONAL);
+			scb->sg64List[0].length = 4096;	// TODO: Check this
+			pthru->dataxferaddr = scb->dma_sghandle64;
+			pthru->numsgelements = 1;
+			mboxpthru->cmd = 0xC3;
+		} else {
+			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
+			pthru->dataxferaddr =
+			    pci_map_single (megacfg->dev,
+					    ioc->data,
+					    4096, PCI_DMA_BIDIRECTIONAL);
+			pthru->numsgelements = 0;
+		}
+
+#else
+		{
+			mboxpthru->dataxferaddr = virt_to_bus (&scb->pthru);
+			pthru->dataxferaddr = virt_to_bus (ioc->data);
+			pthru->numsgelements = 0;
+		}
+#endif
+
+		pthru->reqsenselen = 14;
+		break;
 
+	default:		/* Normal command */
+		mboxioc = (mega_ioctl_mbox *) scb->mboxData;
+
+		if (ioc->ui.fcs.opcode == M_RD_IOCTL_CMD_NEW) {
+			scb->buff_ptr = ioc->ui.fcs.buffer;
+			scb->iDataSize = ioc->ui.fcs.length;
+		} else {
+			scb->buff_ptr = ioc->data;
+			scb->iDataSize = 4096;	// TODO:check it
+		}
+
+		set_mbox_xfer_addr (megacfg, scb, mboxioc, FROMTO_DEVICE);
+		mboxioc->numsgelements = 0;
+		break;
+	}
+
+	return scb;
+}
+
+static int
+megadev_close (struct inode *inode, struct file *filep)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static Scsi_Host_Template driver_template = MEGARAID;
+#include "scsi_module.c"
+#else
+#ifdef MODULE
+Scsi_Host_Template driver_template = MEGARAID;
 
 #include "scsi_module.c"
+#endif				/* MODULE */
+#endif				/* LINUX VERSION 2.4.XX  test */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.4.2/linux/drivers/scsi/megaraid.h	Mon Dec 11 13:19:40 2000
+++ linux/drivers/scsi/megaraid.h	Tue Mar  6 19:44:37 2001
@@ -5,14 +5,15 @@
 #include <linux/version.h>
 #endif
 
-#define IN_ISR                  0x80000000L
-#define IN_ABORT                0x40000000L
-#define IN_RESET                0x20000000L
-#define IN_QUEUE                0x10000000L
-#define BOARD_QUARTZ            0x08000000L
-#define BOARD_40LD              0x04000000L
+#define IN_ISR		  	0x80000000L
+#define IN_ABORT		0x40000000L
+#define IN_RESET		0x20000000L
+#define IN_QUEUE		0x10000000L
+
+#define BOARD_QUARTZ		0x08000000L
+#define BOARD_40LD	   	0x04000000L
+#define BOARD_64BIT		0x02000000L
 
-#ifndef HOSTS_C
 #define SCB_FREE     0x0
 #define SCB_ACTIVE   0x1
 #define SCB_WAITQ    0x2
@@ -20,619 +21,862 @@
 #define SCB_COMPLETE 0x4
 #define SCB_ABORTED  0x5
 #define SCB_RESET    0x6
-#endif
 
-#define MEGA_CMD_TIMEOUT        10
+#define M_RD_CRLFSTR 			"\n"
+#define M_RD_IOCTL_CMD			0x80
+#define M_RD_IOCTL_CMD_NEW		0x81
+#define M_RD_DRIVER_IOCTL_INTERFACE	0x82
+
+#define MEGARAID_VERSION "v1.14g (Release Date: Feb 5, 2001; 11:42)"
+#define MEGARAID_IOCTL_VERSION 	114
+
+/* Methods */
+#define GET_DRIVER_INFO 		0x1
+
+#define MEGA_CMD_TIMEOUT		10
 
 /* Feel free to fiddle with these.. max values are:
    SGLIST     0..26
    COMMANDS   0..253
    CMDPERLUN  0..63
 */
-#define MAX_SGLIST              0x1A
-#define MAX_COMMANDS            127
-#define MAX_CMD_PER_LUN         63
+
+#define MAX_SGLIST	      	0x1A
+#define MAX_COMMANDS	    	127
+#define MAX_CMD_PER_LUN	 	63
 #define MAX_FIRMWARE_STATUS     46
 
 #define MAX_LOGICAL_DRIVES      8
-#define MAX_CHANNEL             5
-#define MAX_TARGET              15
+#define MAX_CHANNEL	     	5
+#define MAX_TARGET	      	15
 #define MAX_PHYSICAL_DRIVES     MAX_CHANNEL*MAX_TARGET
 
 #define INQUIRY_DATA_SIZE       0x24
-#define MAX_CDB_LEN             0x0A
+#define MAX_CDB_LEN	     		0x0A
 #define MAX_REQ_SENSE_LEN       0x20
 
-#define INTR_VALID              0x40
+#define INTR_VALID	      	0x40
+
+/* Direction Macros for MBOX Data direction */
+#define TO_DEVICE		0x0
+#define FROM_DEVICE		0x1
+#define FROMTO_DEVICE		0x2
 
 /* Mailbox commands */
 #define MEGA_MBOXCMD_LREAD      0x01
 #define MEGA_MBOXCMD_LWRITE     0x02
+#define MEGA_MBOXCMD_LREAD64    0xA7
+#define MEGA_MBOXCMD_LWRITE64   0xA8
 #define MEGA_MBOXCMD_PASSTHRU   0x03
 #define MEGA_MBOXCMD_ADAPTERINQ 0x05
 
 /* Offsets into Mailbox */
-#define COMMAND_PORT       0x00
-#define COMMAND_ID_PORT    0x01
-#define SG_LIST_PORT0      0x08
-#define SG_LIST_PORT1      0x09
-#define SG_LIST_PORT2      0x0a
-#define SG_LIST_PORT3      0x0b
-#define SG_ELEMENT_PORT    0x0d
-#define NO_FIRED_PORT      0x0f
+#define COMMAND_PORT       	0x00
+#define COMMAND_ID_PORT    	0x01
+#define SG_LIST_PORT0      	0x08
+#define SG_LIST_PORT1      	0x09
+#define SG_LIST_PORT2      	0x0a
+#define SG_LIST_PORT3      	0x0b
+#define SG_ELEMENT_PORT    	0x0d
+#define NO_FIRED_PORT      	0x0f
 
 /* I/O Port offsets */
-#define I_CMD_PORT         0x00
-#define I_ACK_PORT         0x00
-#define I_TOGGLE_PORT      0x01
-#define INTR_PORT          0x0a
-
-#define MAILBOX_SIZE       (sizeof(mega_mailbox)-16)
-#define MBOX_BUSY_PORT     0x00
-#define MBOX_PORT0         0x04
-#define MBOX_PORT1         0x05
-#define MBOX_PORT2         0x06
-#define MBOX_PORT3         0x07
-#define ENABLE_MBOX_REGION 0x0B
+#define I_CMD_PORT	 	0x00
+#define I_ACK_PORT	 	0x00
+#define I_TOGGLE_PORT      	0x01
+#define INTR_PORT	  	0x0a
+
+#define MAILBOX_SIZE       	(sizeof(mega_mailbox)-16)
+#define MBOX_BUSY_PORT     	0x00
+#define MBOX_PORT0	 	0x04
+#define MBOX_PORT1	 	0x05
+#define MBOX_PORT2	 	0x06
+#define MBOX_PORT3	 	0x07
+#define ENABLE_MBOX_REGION 	0x0B
 
 /* I/O Port Values */
-#define ISSUE_BYTE         0x10
-#define ACK_BYTE           0x08
-#define ENABLE_INTR_BYTE   0xc0
-#define DISABLE_INTR_BYTE  0x00
-#define VALID_INTR_BYTE    0x40
-#define MBOX_BUSY_BYTE     0x10
-#define ENABLE_MBOX_BYTE   0x00
+#define ISSUE_BYTE	 	0x10
+#define ACK_BYTE	   	0x08
+#define ENABLE_INTR_BYTE   	0xc0
+#define DISABLE_INTR_BYTE  	0x00
+#define VALID_INTR_BYTE    	0x40
+#define MBOX_BUSY_BYTE     	0x10
+#define ENABLE_MBOX_BYTE   	0x00
 
 /* Setup some port macros here */
-#define WRITE_MAILBOX(base,offset,value)   *(base+offset)=value
-#define READ_MAILBOX(base,offset)          *(base+offset)
-
-#define WRITE_PORT(base,offset,value)      outb_p(value,base+offset)
-#define READ_PORT(base,offset)             inb_p(base+offset)
-
-#define ISSUE_COMMAND(base)   WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE)
-#define CLEAR_INTR(base)      WRITE_PORT(base,I_ACK_PORT,ACK_BYTE)
-#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)
+#define WRITE_MAILBOX(base,offset,value)   	*(base+offset)=value
+#define READ_MAILBOX(base,offset)		*(base+offset)
 
-/* Define AMI's PCI codes */
-#undef PCI_VENDOR_ID_AMI
-#undef PCI_DEVICE_ID_AMI_MEGARAID
+#define WRITE_PORT(base,offset,value)      	outb_p(value,base+offset)
+#define READ_PORT(base,offset)	     		inb_p(base+offset)
 
-#ifndef PCI_VENDOR_ID_AMI
-#define PCI_VENDOR_ID_AMI          0x101E
-#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
-#endif
-
-#define PCI_CONF_BASE_ADDR_OFFSET  0x10
-#define PCI_CONF_IRQ_OFFSET        0x3c
-#define PCI_CONF_AMISIG            0xa0
-#define AMI_SIGNATURE              0x3344
-#define AMI_SIGNATURE_471          0xCCCC
+#define ISSUE_COMMAND(base)	WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE)
+#define CLEAR_INTR(base)	WRITE_PORT(base,I_ACK_PORT,ACK_BYTE)
+#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)
+
+/* Special Adapter Commands */
+#define FW_FIRE_WRITE   	0x2C
+#define FW_FIRE_FLASH   	0x2D
+
+#define FC_NEW_CONFIG	   		0xA1
+#define DCMD_FC_CMD			0xA1
+#define DCMD_FC_PROCEED	     		0x02
+#define DCMD_DELETE_LOGDRV	  	0x03
+#define DCMD_FC_READ_NVRAM_CONFIG   	0x04
+#define DCMD_FC_READ_NVRAM_CONFIG_64   	0xC0
+#define DCMD_FC_READ_FINAL_CONFIG   	0x05
+#define DCMD_GET_DISK_CONFIG		0x06
+#define DCMD_GET_DISK_CONFIG_64		0xC2
+#define DCMD_CHANGE_LDNO	    	0x07
+#define DCMD_COMPACT_CONFIG	 	0x08
+#define DCMD_DELETE_DRIVEGROUP      	0x09
+#define DCMD_GET_LOOPID_INFO		0x0A
+#define DCMD_CHANGE_LOOPID	  	0x0B
+#define DCMD_GET_NUM_SCSI_CHANS     	0x0C
+#define DCMD_WRITE_CONFIG	   	0x0D
+#define DCMD_WRITE_CONFIG_64   		0xC1
+
+#define NC_SUBOP_PRODUCT_INFO       	0x0E
+#define NC_SUBOP_ENQUIRY3	   	0x0F
+#define ENQ3_GET_SOLICITED_NOTIFY_ONLY  0x01
+#define ENQ3_GET_SOLICITED_FULL	 	0x02
+#define ENQ3_GET_UNSOLICITED	    	0x03
+
+#define PCI_CONF_BASE_ADDR_OFFSET  	0x10
+#define PCI_CONF_IRQ_OFFSET		0x3c
+#define PCI_CONF_AMISIG	    		0xa0
+#define PCI_CONF_AMISIG64		0xa4
+
+/* Sub-System Vendor ID sorted on alphabetical order*/
+#define	AMI_SUBSYS_ID			0x101E
+#define DELL_SUBSYS_ID			0x1028
+#define	HP_SUBSYS_ID			0x103C
+
+#define AMI_SIGNATURE	      		0x3344
+#define AMI_SIGNATURE_471	  	0xCCCC
+#define AMI_64BIT_SIGNATURE		0x0299
 
-#if LINUX_VERSION_CODE < 0x20100
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)	/*0x20100 */
 #define MEGARAID \
-  { NULL,                               /* Next                      */\
-    NULL,                               /* Usage Count Pointer       */\
-    NULL,                               /* /proc Directory Entry     */\
-    megaraid_proc_info,                 /* /proc Info Function       */\
-    "MegaRAID",                         /* Driver Name               */\
-    megaraid_detect,                    /* Detect Host Adapter       */\
-    megaraid_release,                   /* Release Host Adapter      */\
-    megaraid_info,                      /* Driver Info Function      */\
-    megaraid_command,                   /* Command Function          */\
-    megaraid_queue,                     /* Queue Command Function    */\
-    megaraid_abort,                     /* Abort Command Function    */\
-    megaraid_reset,                     /* Reset Command Function    */\
-    NULL,                               /* Slave Attach Function     */\
-    megaraid_biosparam,                 /* Disk BIOS Parameters      */\
-    MAX_COMMANDS,                       /* # of cmds that can be\
-                                           outstanding at any time */\
-    7,                                  /* HBA Target ID             */\
-    MAX_SGLIST,                         /* Scatter/Gather Table Size */\
-    MAX_CMD_PER_LUN,                    /* SCSI Commands per LUN     */\
-    0,                                  /* Present                   */\
-    0,                                  /* Default Unchecked ISA DMA */\
-    ENABLE_CLUSTERING }		/* Enable Clustering         */
+  { NULL,			      	/* Next				*/\
+    NULL,			        /* Usage Count Pointer		*/\
+    NULL,			       	/* proc Directory Entry		*/\
+    megaraid_proc_info,		 	/* proc Info Function		*/\
+    "MegaRAID",			 	/* Driver Name			*/\
+    megaraid_detect,		    	/* Detect Host Adapter		*/\
+    megaraid_release,		   	/* Release Host Adapter		*/\
+    megaraid_info,		      	/* Driver Info Function		*/\
+    megaraid_command,		   	/* Command Function		*/\
+    megaraid_queue,		     	/* Queue Command Function	*/\
+    megaraid_abort,		     	/* Abort Command Function	*/\
+    megaraid_reset,		     	/* Reset Command Function	*/\
+    NULL,			       	/* Slave Attach Function	*/\
+    megaraid_biosparam,		 	/* Disk BIOS Parameters		*/\
+    MAX_COMMANDS,		       	/* # of cmds that can be\
+					outstanding at any time		*/\
+    7,				  	/* HBA Target ID		*/\
+    MAX_SGLIST,			 	/* Scatter/Gather Table Size	*/\
+    MAX_CMD_PER_LUN,		    	/* SCSI Commands per LUN	*/\
+    0,				  	/* Present			*/\
+    0,				  	/* Default Unchecked ISA DMA	*/\
+    ENABLE_CLUSTERING }			/* Enable Clustering		*/
 #else
 #define MEGARAID \
   {\
-    name:            "MegaRAID",               /* Driver Name               */\
-    proc_info:        megaraid_proc_info,      /* /proc driver info         */\
-    detect:           megaraid_detect,         /* Detect Host Adapter       */\
-    release:          megaraid_release,        /* Release Host Adapter      */\
-    info:             megaraid_info,           /* Driver Info Function      */\
-    command:          megaraid_command,        /* Command Function          */\
-    queuecommand:     megaraid_queue,          /* Queue Command Function    */\
-    abort:            megaraid_abort,          /* Abort Command Function    */\
-    reset:            megaraid_reset,          /* Reset Command Function    */\
-    bios_param:       megaraid_biosparam,      /* Disk BIOS Parameters      */\
-    can_queue:        MAX_COMMANDS,            /* Can Queue                 */\
-    this_id:          7,                       /* HBA Target ID             */\
-    sg_tablesize:     MAX_SGLIST,              /* Scatter/Gather Table Size */\
-    cmd_per_lun:      MAX_CMD_PER_LUN,         /* SCSI Commands per LUN     */\
-    present:          0,                       /* Present                   */\
-    unchecked_isa_dma:0,                       /* Default Unchecked ISA DMA */\
-    use_clustering:   ENABLE_CLUSTERING        /* Enable Clustering         */\
+    name:	    	"MegaRAID",		/* Driver Name			*/\
+    proc_info:		megaraid_proc_info,     /* /proc driver info		*/\
+    detect:		megaraid_detect,	/* Detect Host Adapter		*/\
+    release:	  	megaraid_release,	/* Release Host Adapter		*/\
+    info:	     	megaraid_info,	   	/* Driver Info Function		*/\
+    command:	  	megaraid_command,	/* Command Function		*/\
+    queuecommand:  	megaraid_queue,		/* Queue Command Function	*/\
+    abort:	    	megaraid_abort,	  	/* Abort Command Function	*/\
+    reset:	    	megaraid_reset,	  	/* Reset Command Function	*/\
+    bios_param:     	megaraid_biosparam, 	/* Disk BIOS Parameters		*/\
+    can_queue:		MAX_COMMANDS,	    	/* Can Queue			*/\
+    this_id:	  	7,		       	/* HBA Target ID		*/\
+    sg_tablesize:   	MAX_SGLIST,	  	/* Scatter/Gather Table Size	*/\
+    cmd_per_lun:    	MAX_CMD_PER_LUN,	/* SCSI Commands per LUN	*/\
+    present:	  	0,		       	/* Present			*/\
+    unchecked_isa_dma:	0,		       	/* Default Unchecked ISA DMA	*/\
+    use_clustering:   	ENABLE_CLUSTERING  	/* Enable Clustering		*/\
   }
 #endif
 
-
 /***********************************************************************
  * Structure Declarations for the Firmware supporting 40 Logical Drives
  * and 256 Physical Drives.
  ***********************************************************************/
 
-#define FC_MAX_LOGICAL_DRIVES       40
-#define FC_MAX_LOG_DEVICES          FC_MAX_LOGICAL_DRIVES
-#define FC_MAX_SPAN_DEPTH           8
-#define FC_MAX_ROW_SIZE             32
-
-#define FC_MAX_CHANNELS             16
-#define FC_MAX_TARGETS_PER_CHANNEL  16
-#define FC_MAX_PHYSICAL_DEVICES     256
-
-#define FC_NEW_CONFIG               0xA1
-#define DCMD_FC_CMD                 0xA1
-  #define NC_SUBOP_PRODUCT_INFO       0x0E
-  #define NC_SUBOP_ENQUIRY3           0x0F
-	#define ENQ3_GET_SOLICITED_NOTIFY_ONLY  0x01
-	#define ENQ3_GET_SOLICITED_FULL         0x02
-	#define ENQ3_GET_UNSOLICITED            0x03
-
+#define FC_MAX_LOGICAL_DRIVES       	40
+#define FC_MAX_LOG_DEVICES	  	FC_MAX_LOGICAL_DRIVES
+#define FC_MAX_SPAN_DEPTH	   	8
+#define FC_MAX_ROW_SIZE	     		32
+
+#define FC_MAX_CHANNELS	     		16
+#define FC_MAX_TARGETS_PER_CHANNEL  	16
+#define FC_MAX_PHYSICAL_DEVICES     	256
 
 /********************************************
- * PRODUCT_INFO Strucure
+ * PRODUCT_INFO
  ********************************************/
 
 #define SIG_40LOG_32STR_8SPN  0x00282008
 
-/* 
+/*
  * Utilities declare this strcture size as 1024 bytes. So more fields can
  * be added in future.
  */
 
-struct MRaidProductInfo
-{
-   u32   DataSize; /* current size in bytes (not including resvd) */
-   u32   ConfigSignature;
-                         /* Current value is 0x00282008
-                          * 0x28=MAX_LOGICAL_DRIVES, 
-                          * 0x20=Number of stripes and 
-                          * 0x08=Number of spans */
-   u8   FwVer[16];         /* printable ASCI string */
-   u8   BiosVer[16];       /* printable ASCI string */
-   u8   ProductName[80];   /* printable ASCI string */
-
-   u8   MaxConcCmds;       /* Max. concurrent commands supported */
-   u8   SCSIChanPresent;   /* Number of SCSI Channels detected */
-   u8   FCLoopPresent;     /* Number of Fibre Loops detected */
-   u8   memType;           /* EDO, FPM, SDRAM etc */
-
-   u32   signature;
-   u16  DramSize;          /* In terms of MB */
-   u16  subSystemID;
-
-   u16  subSystemVendorID;
-   u8   numNotifyCounters;
-   u8   pad1k[889];       /* 135 + 889 resvd = 1024 total size */
-}__attribute__((packed));
+struct MRaidProductInfo {
+	u32 DataSize;		/* current size in bytes (not including resvd) */
+	u32 ConfigSignature;
+	/* Current value is 0x00282008
+	 * 0x28=MAX_LOGICAL_DRIVES,
+	 * 0x20=Number of stripes and
+	 * 0x08=Number of spans */
+	u8 FwVer[16];		/* printable ASCI string */
+	u8 BiosVer[16];		/* printable ASCI string */
+	u8 ProductName[80];	/* printable ASCI string */
+
+	u8 MaxConcCmds;		/* Max. concurrent commands supported */
+	u8 SCSIChanPresent;	/* Number of SCSI Channels detected */
+	u8 FCLoopPresent;	/* Number of Fibre Loops detected */
+	u8 memType;		/* EDO, FPM, SDRAM etc */
+
+	u32 signature;
+	u16 DramSize;		/* In terms of MB */
+	u16 subSystemID;
+
+	u16 subSystemVendorID;
+	u8 numNotifyCounters;
+	u8 pad1k[889];		/* 135 + 889 resvd = 1024 total size */
+} __attribute__ ((packed));
 typedef struct MRaidProductInfo megaRaidProductInfo;
 
 /********************************************
- * Standard ENQUIRY Strucure
+ * Standard ENQUIRY
  ********************************************/
-struct FC_ADP_INFO
-{
-   u8  MaxConcCmds;         /* Max. concurrent commands supported. */
-   u8  RbldRate;            /* Rebuild Rate. Varies from 0%-100% */
-   u8  MaxTargPerChan;      /* Max. Targets supported per chan. */
-   u8  ChanPresent;         /* No. of Chans present on this adapter. */
-   u8  FwVer[4];            /* Firmware version. */
-   u16 AgeOfFlash;          /* No. of times FW has been downloaded. */
-   u8  ChipSetValue;        /* Contents of 0xC0000832 */
-   u8  DramSize;            /* In terms of MB */
-   u8  CacheFlushInterval;  /* In terms of Seconds */
-   u8  BiosVersion[4];
-   u8  BoardType;
-   u8  sense_alert;
-   u8  write_config_count;   /* Increase with evry configuration change */
-   u8  drive_inserted_count; /* Increase with every drive inserted */
-   u8  inserted_drive;       /* Channel: Id of inserted drive */
-   u8  battery_status;
-                           /*
-                              BIT 0 : battery module missing
-                              BIT 1 : VBAD
-                              BIT 2 : temp high
-                              BIT 3 : battery pack missing
-                              BIT 4,5 : 00 - charge complete
-                                        01 - fast charge in prog
-                                        10 - fast charge fail
-                                        11 - undefined
-                              BIt 6 : counter > 1000
-                              Bit 7 : undefined
-                           */
-   u8  dec_fault_bus_info;   /* was resvd */
-}__attribute__((packed));
-
-struct FC_LDRV_INFO
-{
-   u8  NumLDrv;      /* No. of Log. Drvs configured. */
-   u8  recon_state[FC_MAX_LOGICAL_DRIVES/8];    
-                                /* bit field for State of reconstruct */
-   u16 LDrvOpStatus[FC_MAX_LOGICAL_DRIVES/8];   
-                                /* bit field Status of Long Operations. */
-
-   u32  LDrvSize[FC_MAX_LOGICAL_DRIVES];   /* Size of each log. Drv. */
-   u8  LDrvProp[FC_MAX_LOGICAL_DRIVES];
-   u8  LDrvState[FC_MAX_LOGICAL_DRIVES];  /* State of Logical Drives. */
-}__attribute__((packed));
+struct FC_ADP_INFO {
+	u8 MaxConcCmds;		/* Max. concurrent commands supported. */
+	u8 RbldRate;		/* Rebuild Rate. Varies from 0%-100% */
+	u8 MaxTargPerChan;	/* Max. Targets supported per chan. */
+	u8 ChanPresent;		/* No. of Chans present on this adapter. */
+	u8 FwVer[4];		/* Firmware version. */
+	u16 AgeOfFlash;		/* No. of times FW has been downloaded. */
+	u8 ChipSetValue;	/* Contents of 0xC0000832 */
+	u8 DramSize;		/* In terms of MB */
+	u8 CacheFlushInterval;	/* In terms of Seconds */
+	u8 BiosVersion[4];
+	u8 BoardType;
+	u8 sense_alert;
+	u8 write_config_count;	/* Increase with evry configuration change */
+	u8 drive_inserted_count;/* Increase with every drive inserted */
+	u8 inserted_drive;	/* Channel: Id of inserted drive */
+	u8 battery_status;
+	/*
+	   BIT 0 : battery module missing
+	   BIT 1 : VBAD
+	   BIT 2 : temp high
+	   BIT 3 : battery pack missing
+	   BIT 4,5 : 00 - charge complete
+	   01 - fast charge in prog
+	   10 - fast charge fail
+	   11 - undefined
+	   BIt 6 : counter > 1000
+	   Bit 7 : undefined
+	 */
+	u8 dec_fault_bus_info;	/* was resvd */
+} __attribute__ ((packed));
+
+struct FC_LDRV_INFO {
+	u8 NumLDrv;		/* No. of Log. Drvs configured. */
+	u8 recon_state[FC_MAX_LOGICAL_DRIVES / 8];
+	/* bit field for State of reconstruct */
+	u16 LDrvOpStatus[FC_MAX_LOGICAL_DRIVES / 8];
+	/* bit field Status of Long Operations. */
+
+	u32 LDrvSize[FC_MAX_LOGICAL_DRIVES];	/* Size of each log. Drv. */
+	u8 LDrvProp[FC_MAX_LOGICAL_DRIVES];
+	u8 LDrvState[FC_MAX_LOGICAL_DRIVES];	/* State of Logical Drives. */
+} __attribute__ ((packed));
 
 #define PREVSTAT_MASK   0xf0
 #define CURRSTAT_MASK   0x0f
 
-struct FC_PDRV_INFO
-{
-   u8 PDrvState[FC_MAX_PHYSICAL_DEVICES]; /* State of Phys Drvs. */
-}__attribute__((packed));
+struct FC_PDRV_INFO {
+	u8 PDrvState[FC_MAX_PHYSICAL_DEVICES];	/* State of Phys Drvs. */
+} __attribute__ ((packed));
+
+struct FC_AdapterInq {
+	struct FC_ADP_INFO AdpInfo;
+	struct FC_LDRV_INFO LogdrvInfo;
+	struct FC_PDRV_INFO PhysdrvInfo;
+} __attribute__ ((packed));
 
-
-struct FC_AdapterInq
-{
-   struct FC_ADP_INFO    AdpInfo;
-   struct FC_LDRV_INFO   LogdrvInfo;
-   struct FC_PDRV_INFO   PhysdrvInfo;
-}__attribute__((packed));
-
-
-typedef struct FC_AdapterInq  mega_RAIDINQ_FC;
+typedef struct FC_AdapterInq mega_RAIDINQ_FC;
 
 /********************************************
- * NOTIFICATION Strucure
+ * NOTIFICATION
  ********************************************/
 
 #define MAX_NOTIFY_SIZE     0x80
 #define CUR_NOTIFY_SIZE     sizeof(struct MegaRAID_Notify)
 
-/* 
+/*
  * Utilities declare this strcture size as ?? bytes. So more fields can
  * be added in future.
  */
-struct MegaRAID_Notify
-{
-    u32   globalCounter;  /* Any change increments this counter */
-
-    u8   paramCounter;   /* Indicates any params changed  */
-    u8   paramId;        /* Param modified - defined below */
-    u16  paramVal;       /* New val of last param modified */
-
-    u8   writeConfigCounter; /* write config occurred */
-    u8   writeConfigRsvd[3];
-
-    u8   ldrvOpCounter;  /* Indicates ldrv op started/completed */
-    u8   ldrvOpId;       /* ldrv num */
-    u8   ldrvOpCmd;      /* ldrv operation - defined below */
-    u8   ldrvOpStatus;   /* status of the operation */
-
-    u8   ldrvStateCounter;   /* Indicates change of ldrv state */
-    u8   ldrvStateId;    /* ldrv num */
-    u8   ldrvStateNew;   /* New state */
-    u8   ldrvStateOld;   /* old state */
-
-    u8   pdrvStateCounter;   /* Indicates change of ldrv state */
-    u8   pdrvStateId;    /* pdrv id */
-    u8   pdrvStateNew;   /* New state */
-    u8   pdrvStateOld;   /* old state */
-
-    u8   pdrvFmtCounter; /* Indicates pdrv format started/over */
-    u8   pdrvFmtId;      /* pdrv id */
-    u8   pdrvFmtVal;     /* format started/over */
-    u8   pdrvFmtRsvd;
-
-    u8   targXferCounter;    /* Indicates SCSI-2 Xfer rate change */
-    u8   targXferId;     /* pdrv Id  */
-    u8   targXferVal;    /* new Xfer params of last pdrv */
-    u8   targXferRsvd;
-
-    u8   fcLoopIdChgCounter; /* Indicates loopid changed */
-    u8   fcLoopIdPdrvId; /* pdrv id */
-    u8   fcLoopId0;      /* loopid on fc loop 0 */
-    u8   fcLoopId1;      /* loopid on fc loop 1 */
-
-    u8   fcLoopStateCounter; /* Indicates loop state changed */
-    u8   fcLoopState0;   /* state of fc loop 0 */
-    u8   fcLoopState1;   /* state of fc loop 1 */
-    u8   fcLoopStateRsvd;
-}__attribute__((packed));
+struct MegaRAID_Notify {
+	u32 globalCounter;	/* Any change increments this counter */
 
+	u8 paramCounter;	/* Indicates any params changed  */
+	u8 paramId;		/* Param modified - defined below */
+	u16 paramVal;		/* New val of last param modified */
+
+	u8 writeConfigCounter;	/* write config occurred */
+	u8 writeConfigRsvd[3];
+
+	u8 ldrvOpCounter;	/* Indicates ldrv op started/completed */
+	u8 ldrvOpId;		/* ldrv num */
+	u8 ldrvOpCmd;		/* ldrv operation - defined below */
+	u8 ldrvOpStatus;	/* status of the operation */
+
+	u8 ldrvStateCounter;	/* Indicates change of ldrv state */
+	u8 ldrvStateId;		/* ldrv num */
+	u8 ldrvStateNew;	/* New state */
+	u8 ldrvStateOld;	/* old state */
+
+	u8 pdrvStateCounter;	/* Indicates change of ldrv state */
+	u8 pdrvStateId;		/* pdrv id */
+	u8 pdrvStateNew;	/* New state */
+	u8 pdrvStateOld;	/* old state */
+
+	u8 pdrvFmtCounter;	/* Indicates pdrv format started/over */
+	u8 pdrvFmtId;		/* pdrv id */
+	u8 pdrvFmtVal;		/* format started/over */
+	u8 pdrvFmtRsvd;
+
+	u8 targXferCounter;	/* Indicates SCSI-2 Xfer rate change */
+	u8 targXferId;		/* pdrv Id  */
+	u8 targXferVal;		/* new Xfer params of last pdrv */
+	u8 targXferRsvd;
+
+	u8 fcLoopIdChgCounter;	/* Indicates loopid changed */
+	u8 fcLoopIdPdrvId;	/* pdrv id */
+	u8 fcLoopId0;		/* loopid on fc loop 0 */
+	u8 fcLoopId1;		/* loopid on fc loop 1 */
+
+	u8 fcLoopStateCounter;	/* Indicates loop state changed */
+	u8 fcLoopState0;	/* state of fc loop 0 */
+	u8 fcLoopState1;	/* state of fc loop 1 */
+	u8 fcLoopStateRsvd;
+} __attribute__ ((packed));
 
 /********************************************
  * PARAM IDs in Notify struct
  ********************************************/
-#define PARAM_RBLD_RATE                 0x01
+#define PARAM_RBLD_RATE		 0x01
     /*--------------------------------------
-     * Param val = 
-     *      byte 0: new rbld rate 
+     * Param val =
+     *      byte 0: new rbld rate
      *--------------------------------------*/
 #define PARAM_CACHE_FLUSH_INTERVAL      0x02
     /*--------------------------------------
-     * Param val = 
+     * Param val =
      *      byte 0: new cache flush interval
      *--------------------------------------*/
-#define PARAM_SENSE_ALERT               0x03
+#define PARAM_SENSE_ALERT	       0x03
     /*--------------------------------------
-     * Param val = 
+     * Param val =
      *      byte 0: last pdrv id causing chkcond
      *--------------------------------------*/
-#define PARAM_DRIVE_INSERTED            0x04
+#define PARAM_DRIVE_INSERTED	    0x04
     /*--------------------------------------
-     * Param val = 
+     * Param val =
      *      byte 0: last pdrv id inserted
      *--------------------------------------*/
-#define PARAM_BATTERY_STATUS            0x05
+#define PARAM_BATTERY_STATUS	    0x05
     /*--------------------------------------
-     * Param val = 
+     * Param val =
      *      byte 0: battery status
      *--------------------------------------*/
 
 /********************************************
  * Ldrv operation cmd in Notify struct
  ********************************************/
-#define LDRV_CMD_CHKCONSISTANCY         0x01
-#define LDRV_CMD_INITIALIZE             0x02
-#define LDRV_CMD_RECONSTRUCTION         0x03
+#define LDRV_CMD_CHKCONSISTANCY	 0x01
+#define LDRV_CMD_INITIALIZE	 0x02
+#define LDRV_CMD_RECONSTRUCTION	 0x03
 
 /********************************************
  * Ldrv operation status in Notify struct
  ********************************************/
-#define	LDRV_OP_SUCCESS                 0x00
-#define	LDRV_OP_FAILED                  0x01
-#define	LDRV_OP_ABORTED                 0x02
-#define	LDRV_OP_CORRECTED               0x03
-#define	LDRV_OP_STARTED                 0x04
-
+#define LDRV_OP_SUCCESS		 0x00
+#define LDRV_OP_FAILED		 0x01
+#define LDRV_OP_ABORTED		 0x02
+#define LDRV_OP_CORRECTED	 0x03
+#define LDRV_OP_STARTED		 0x04
 
 /********************************************
  * Raid Logical drive states.
  ********************************************/
-#define     RDRV_OFFLINE                0
-#define     RDRV_DEGRADED               1
-#define     RDRV_OPTIMAL                2
-#define     RDRV_DELETED                3
+#define     RDRV_OFFLINE	0
+#define     RDRV_DEGRADED	1
+#define     RDRV_OPTIMAL	2
+#define     RDRV_DELETED	3
 
 /*******************************************
  * Physical drive states.
  *******************************************/
-#define     PDRV_UNCNF                  0
-#define     PDRV_ONLINE                 3
-#define     PDRV_FAILED                 4
-#define     PDRV_RBLD                   5
-/* #define     PDRV_HOTSPARE               6 */
+#define     PDRV_UNCNF		0
+#define     PDRV_ONLINE		3
+#define     PDRV_FAILED		4
+#define     PDRV_RBLD		5
 
 /*******************************************
  * Formal val in Notify struct
  *******************************************/
-#define PDRV_FMT_START                  0x01
-#define PDRV_FMT_OVER                   0x02
+#define PDRV_FMT_START		0x01
+#define PDRV_FMT_OVER		0x02
 
 /********************************************
  * FC Loop State in Notify Struct
  ********************************************/
-#define ENQ_FCLOOP_FAILED               0
-#define ENQ_FCLOOP_ACTIVE               1
-#define ENQ_FCLOOP_TRANSIENT            2
-
+#define ENQ_FCLOOP_FAILED	0
+#define ENQ_FCLOOP_ACTIVE	1
+#define ENQ_FCLOOP_TRANSIENT	2
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#define M_RD_DMA_TYPE_NONE	      	0xFFFF
+#define M_RD_PTHRU_WITH_BULK_DATA   	0x0001
+#define M_RD_PTHRU_WITH_SGLIST	  	0x0002
+#define M_RD_BULK_DATA_ONLY	     	0x0004
+#define M_RD_SGLIST_ONLY		0x0008
+#endif
 /********************************************
- * ENQUIRY3 Strucure
+ * ENQUIRY3
  ********************************************/
-/* 
+/*
  * Utilities declare this strcture size as 1024 bytes. So more fields can
  * be added in future.
  */
-struct MegaRAID_Enquiry3
-{
-   u32   dataSize; /* current size in bytes (not including resvd) */
-
-   struct MegaRAID_Notify   notify;
-
-   u8   notifyRsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
-
-   u8   rbldRate;     /* Rebuild rate (0% - 100%) */
-   u8   cacheFlushInterval; /* In terms of Seconds */
-   u8   senseAlert;
-   u8   driveInsertedCount; /* drive insertion count */
-
-   u8   batteryStatus;
-   u8   numLDrv;              /* No. of Log Drives configured */
-   u8   reconState[FC_MAX_LOGICAL_DRIVES/8]; /* State of reconstruct */
-   u16  lDrvOpStatus[FC_MAX_LOGICAL_DRIVES/8]; /* log. Drv Status */
-
-   u32   lDrvSize[FC_MAX_LOGICAL_DRIVES];  /* Size of each log. Drv */
-   u8   lDrvProp[FC_MAX_LOGICAL_DRIVES];
-   u8   lDrvState[FC_MAX_LOGICAL_DRIVES]; /* State of Logical Drives */
-   u8   pDrvState[FC_MAX_PHYSICAL_DEVICES];  /* State of Phys. Drvs. */
-   u16  physDrvFormat[FC_MAX_PHYSICAL_DEVICES/16];
-
-   u8   targXfer[80];               /* phys device transfer rate */
-   u8   pad1k[263];          /* 761 + 263reserved = 1024 bytes total size */
-}__attribute__((packed));
+struct MegaRAID_Enquiry3 {
+	u32 dataSize;		/* current size in bytes (not including resvd) */
+
+	struct MegaRAID_Notify notify;
+
+	u8 notifyRsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
+
+	u8 rbldRate;		/* Rebuild rate (0% - 100%) */
+	u8 cacheFlushInterval;	/* In terms of Seconds */
+	u8 senseAlert;
+	u8 driveInsertedCount;	/* drive insertion count */
+
+	u8 batteryStatus;
+	u8 numLDrv;		/* No. of Log Drives configured */
+	u8 reconState[FC_MAX_LOGICAL_DRIVES / 8];	/* State of reconstruct */
+	u16 lDrvOpStatus[FC_MAX_LOGICAL_DRIVES / 8];	/* log. Drv Status */
+
+	u32 lDrvSize[FC_MAX_LOGICAL_DRIVES];	/* Size of each log. Drv */
+	u8 lDrvProp[FC_MAX_LOGICAL_DRIVES];
+	u8 lDrvState[FC_MAX_LOGICAL_DRIVES];	/* State of Logical Drives */
+	u8 pDrvState[FC_MAX_PHYSICAL_DEVICES];	/* State of Phys. Drvs. */
+	u16 physDrvFormat[FC_MAX_PHYSICAL_DEVICES / 16];
+
+	u8 targXfer[80];	/* phys device transfer rate */
+	u8 pad1k[263];		/* 761 + 263reserved = 1024 bytes total size */
+} __attribute__ ((packed));
 typedef struct MegaRAID_Enquiry3 mega_Enquiry3;
 
 /* Structures */
 typedef struct _mega_ADP_INFO {
-    u8 MaxConcCmds;
-    u8 RbldRate;
-    u8 MaxTargPerChan;
-    u8 ChanPresent;
-    u8 FwVer[4];
-    u16 AgeOfFlash;
-    u8 ChipSetValue;
-    u8 DramSize;
-    u8 CacheFlushInterval;
-    u8 BiosVer[4];
-    u8 resvd[7];
+	u8 MaxConcCmds;
+	u8 RbldRate;
+	u8 MaxTargPerChan;
+	u8 ChanPresent;
+	u8 FwVer[4];
+	u16 AgeOfFlash;
+	u8 ChipSetValue;
+	u8 DramSize;
+	u8 CacheFlushInterval;
+	u8 BiosVer[4];
+	u8 resvd[7];
 } mega_ADP_INFO;
 
 typedef struct _mega_LDRV_INFO {
-    u8 NumLDrv;
-    u8 resvd[3];
-    u32 LDrvSize[MAX_LOGICAL_DRIVES];
-    u8 LDrvProp[MAX_LOGICAL_DRIVES];
-    u8 LDrvState[MAX_LOGICAL_DRIVES];
+	u8 NumLDrv;
+	u8 resvd[3];
+	u32 LDrvSize[MAX_LOGICAL_DRIVES];
+	u8 LDrvProp[MAX_LOGICAL_DRIVES];
+	u8 LDrvState[MAX_LOGICAL_DRIVES];
 } mega_LDRV_INFO;
 
 typedef struct _mega_PDRV_INFO {
-    u8 PDrvState[MAX_PHYSICAL_DRIVES];
-    u8 resvd;
+	u8 PDrvState[MAX_PHYSICAL_DRIVES];
+	u8 resvd;
 } mega_PDRV_INFO;
 
-// RAID inquiry: Mailbox command 0x5
+/* RAID inquiry: Mailbox command 0x5*/
 typedef struct _mega_RAIDINQ {
-    mega_ADP_INFO AdpInfo;
-    mega_LDRV_INFO LogdrvInfo;
-    mega_PDRV_INFO PhysdrvInfo;
+	mega_ADP_INFO AdpInfo;
+	mega_LDRV_INFO LogdrvInfo;
+	mega_PDRV_INFO PhysdrvInfo;
 } mega_RAIDINQ;
 
-// Passthrough command: Mailbox command 0x3
+/* Passthrough command: Mailbox command 0x3*/
 typedef struct mega_passthru {
-    u8 timeout:3;		/* 0=6sec/1=60sec/2=10min/3=3hrs */
-    u8 ars:1;
-    u8 reserved:3;
-    u8 islogical:1;
-    u8 logdrv;		/* if islogical == 1 */
-    u8 channel;		/* if islogical == 0 */
-    u8 target;		/* if islogical == 0 */
-    u8 queuetag;		/* unused */
-    u8 queueaction;		/* unused */
-    u8 cdb[MAX_CDB_LEN];
-    u8 cdblen;
-    u8 reqsenselen;
-    u8 reqsensearea[MAX_REQ_SENSE_LEN];
-    u8 numsgelements;
-    u8 scsistatus;
-    u32 dataxferaddr;
-    u32 dataxferlen;
+	u8 timeout:3;		/* 0=6sec/1=60sec/2=10min/3=3hrs */
+	u8 ars:1;
+	u8 reserved:3;
+	u8 islogical:1;
+	u8 logdrv;		/* if islogical == 1 */
+	u8 channel;		/* if islogical == 0 */
+	u8 target;		/* if islogical == 0 */
+	u8 queuetag;		/* unused */
+	u8 queueaction;		/* unused */
+	u8 cdb[MAX_CDB_LEN];
+	u8 cdblen;
+	u8 reqsenselen;
+	u8 reqsensearea[MAX_REQ_SENSE_LEN];
+	u8 numsgelements;
+	u8 scsistatus;
+	u32 dataxferaddr;
+	u32 dataxferlen;
 } mega_passthru;
 
 struct _mega_mailbox {
-    /* 0x0 */ u8 cmd;
-    /* 0x1 */ u8 cmdid;
-    /* 0x2 */ u16 numsectors;
-    /* 0x4 */ u32 lba;
-    /* 0x8 */ u32 xferaddr;
-    /* 0xC */ u8 logdrv;
-    /* 0xD */ u8 numsgelements;
-    /* 0xE */ u8 resvd;
-    /* 0xF */ u8 busy;
-    /* 0x10 */ u8 numstatus;
-    /* 0x11 */ u8 status;
-    /* 0x12 */ u8 completed[46];
-    u8 mraid_poll;
-    u8 mraid_ack;
-    u8 pad[16]; /* for alignment purposes */
-}__attribute__((packed));
+	/* 0x0 */ u8 cmd;
+	/* 0x1 */ u8 cmdid;
+	/* 0x2 */ u16 numsectors;
+	/* 0x4 */ u32 lba;
+	/* 0x8 */ u32 xferaddr;
+	/* 0xC */ u8 logdrv;
+	/* 0xD */ u8 numsgelements;
+	/* 0xE */ u8 resvd;
+	/* 0xF */ u8 busy;
+	/* 0x10 */ u8 numstatus;
+	/* 0x11 */ u8 status;
+	/* 0x12 */ u8 completed[46];
+	volatile u8 mraid_poll;
+	volatile u8 mraid_ack;
+	u8 pad[16];		/* for alignment purposes */
+} __attribute__ ((packed));
 typedef struct _mega_mailbox mega_mailbox;
 
 typedef struct {
-    u32 xferSegment;      /* for 64-bit controllers */
-    mega_mailbox mailbox;
+	u32 xferSegment_lo;
+	u32 xferSegment_hi;
+	mega_mailbox mailbox;
 } mega_mailbox64;
 
 typedef struct _mega_ioctl_mbox {
-    /* 0x0 */ u8 cmd;
-    /* 0x1 */ u8 cmdid;
-    /* 0x2 */ u8 channel;
-    /* 0x3 */ u8 param;
-    /* 0x4 */ u8 pad[4];
-    /* 0x8 */ u32 xferaddr;
-    /* 0xC */ u8 logdrv;
-    /* 0xD */ u8 numsgelements;
-    /* 0xE */ u8 resvd;
-    /* 0xF */ u8 busy;
-    /* 0x10 */ u8 numstatus;
-    /* 0x11 */ u8 status;
-    /* 0x12 */ u8 completed[46];
-    u8 mraid_poll;
-    u8 mraid_ack;
-    u8 malign[16];
+	/* 0x0 */ u8 cmd;
+	/* 0x1 */ u8 cmdid;
+	/* 0x2 */ u8 channel;
+	/* 0x3 */ u8 param;
+	/* 0x4 */ u8 pad[4];
+	/* 0x8 */ u32 xferaddr;
+	/* 0xC */ u8 logdrv;
+	/* 0xD */ u8 numsgelements;
+	/* 0xE */ u8 resvd;
+	/* 0xF */ u8 busy;
+	/* 0x10 */ u8 numstatus;
+	/* 0x11 */ u8 status;
+	/* 0x12 */ u8 completed[46];
+	u8 mraid_poll;
+	u8 mraid_ack;
+	u8 malign[16];
 } mega_ioctl_mbox;
 
+typedef struct _mega_64sglist32 {
+	u64 address;
+	u32 length;
+} __attribute__ ((packed)) mega_64sglist;
+
 typedef struct _mega_sglist {
-    u32 address;
-    u32 length;
+	u32 address;
+	u32 length;
 } mega_sglist;
 
 /* Queued command data */
 typedef struct _mega_scb mega_scb;
 
 struct _mega_scb {
-    int            idx;
-    u32            state;
-    u32            isrcount;
-    u8         mboxData[16];
-    mega_passthru  pthru;
-    Scsi_Cmnd     *SCpnt;
-    mega_sglist   *sgList;
-    char          *kern_area;  /* Only used for large ioctl xfers */
-    struct wait_queue  *ioctl_wait;
-    struct semaphore   sem;
-    mega_scb      *next;
+	int idx;
+	u32 state;
+	u32 isrcount;
+	u8 mboxData[16];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	u32 dma_type;
+	dma_addr_t dma_h_bulkdata;	/*Dma handle for bulk data transfter */
+	u32 dma_direction;	/*Dma direction */
+	dma_addr_t dma_h_sgdata;	/*Dma handle for the sglist structure */
+	dma_addr_t dma_h_sglist[MAX_SGLIST];	/*Dma handle for all SGL elements */
+	u8 sglist_count;
+	dma_addr_t dma_sghandle64;
+	dma_addr_t dma_passthruhandle64;
+	dma_addr_t dma_bounce_buffer;
+	u8 *bounce_buffer;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	mega_passthru *pthru;
+#else
+	mega_passthru pthru;
+#endif
+
+	Scsi_Cmnd *SCpnt;
+	mega_sglist *sgList;
+	mega_64sglist *sg64List;
+	struct semaphore ioctl_sem;
+	void *buff_ptr;
+	u32 iDataSize;
+	mega_scb *next;
 };
 
+/* internal locking by the queue manipulting routines */
+#define INTERNAL_LOCK   0
+/* external locking by the queue manipulting routines */
+#define EXTERNAL_LOCK   1
+#define NO_LOCK		2
+#define INTR_ENB	0	/* do not disable interrupt while manipulating */
+#define INTR_DIS	1	/* disable interrupt while manipulating */
+
 /* Per-controller data */
 typedef struct _mega_host_config {
-    u8 numldrv;
-    u32 flag;
-    u32 base;
- 
-    mega_scb *qFreeH;
-    mega_scb *qFreeT;
-    mega_scb *qPendingH;
-    mega_scb *qPendingT;
-    
-    Scsi_Cmnd *qCompletedH;
-    Scsi_Cmnd *qCompletedT;
-    u32 qFcnt;
-    u32 qPcnt;
-    u32 qCcnt;
-
-    u32 nReads[FC_MAX_LOGICAL_DRIVES];
-    u32 nWrites[FC_MAX_LOGICAL_DRIVES];
-
-    /* Host adapter parameters */
-    u8 fwVer[7];
-    u8 biosVer[7];
-
-    struct Scsi_Host *host;
-
-    volatile mega_mailbox64 *mbox64;  /* ptr to beginning of 64-bit mailbox */
-    volatile mega_mailbox *mbox;     /* ptr to beginning of standard mailbox */
-    volatile mega_mailbox64 mailbox64;
-#if 0
-    volatile union {
-         u8            generic_buffer[2 * 1024L];
-         mega_RAIDINQ  adapterInfoData;
-         mega_Enquiry3 enquiry3Data;
-    }mega_buffer;
+	u8 numldrv;
+	u32 flag;
+
+#ifdef __LP64__
+	u64 base;
+#else
+	u32 base;
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_addr_t dma_handle64, adjdmahandle64;
+	struct pci_dev *dev;
+#endif
+
+	mega_scb *qFreeH;
+	mega_scb *qFreeT;
+	spinlock_t lock_free;
+
+	mega_scb *qPendingH;
+	mega_scb *qPendingT;
+	spinlock_t lock_pend;
+
+	Scsi_Cmnd *qCompletedH;
+	Scsi_Cmnd *qCompletedT;
+	spinlock_t lock_scsicmd;
+
+	u32 qFcnt;
+	u32 qPcnt;
+	u32 qCcnt;
+
+	unsigned long nReads[FC_MAX_LOGICAL_DRIVES];
+	unsigned long nReadBlocks[FC_MAX_LOGICAL_DRIVES];
+	unsigned long nWrites[FC_MAX_LOGICAL_DRIVES];
+	unsigned long nWriteBlocks[FC_MAX_LOGICAL_DRIVES];
+	unsigned long nInterrupts;
+	/* Host adapter parameters */
+	u8 fwVer[7];
+	u8 biosVer[7];
+
+	struct Scsi_Host *host;
+
+	volatile mega_mailbox64 *mbox64;	/* ptr to beginning of 64-bit mailbox */
+	volatile mega_mailbox *mbox;	/* ptr to beginning of standard mailbox */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+/* ptr to beginning of standard mailbox */
+	volatile mega_mailbox64 *mailbox64ptr;
 #else
-    volatile u8 mega_buffer[2*1024L];
+	volatile mega_mailbox64 mailbox64;
 #endif
-    volatile megaRaidProductInfo productInfo;
 
-    u8 max_cmds;
-    mega_scb scbList[MAX_COMMANDS];
+	volatile u8 mega_buffer[2 * 1024L];
+	volatile megaRaidProductInfo productInfo;
+
+	u8 max_cmds;
+	mega_scb scbList[MAX_COMMANDS];
+
+#define PROCBUFSIZE 4096
+	char procbuf[PROCBUFSIZE];
+	int procidx;
+	struct proc_dir_entry *controller_proc_dir_entry;
+	struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
 } mega_host_config;
 
-const char *megaraid_info(struct Scsi_Host *);
-int megaraid_detect(Scsi_Host_Template *);
-int megaraid_release(struct Scsi_Host *);
-int megaraid_command(Scsi_Cmnd *);
-int megaraid_abort(Scsi_Cmnd *);
-int megaraid_reset(Scsi_Cmnd *, unsigned int);
-int megaraid_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-int megaraid_biosparam(Disk *, kdev_t, int *);
-int megaraid_proc_info(char *buffer, char **start, off_t offset,
-		       int length, int hostno, int inout);
+typedef struct _driver_info {
+	int size;
+	ulong version;
+} mega_driver_info;
+
+/*
+ * User ioctl structure.
+ * This structure will be used for Traditional Method ioctl interface
+ * commands (M_RD_IOCTL_CMD),Alternate Buffer Method (M_RD_IOCTL_CMD_NEW) 
+ * ioctl commands and the Driver ioctls(M_RD_DRIVER_IOCTL_INTERFACE).
+ * The Driver ioctl interface handles the commands at
+ * the driver level, without being sent to the card.
+ */
+#define MEGADEVIOC      0x84
+
+/* system call imposed limit. Change accordingly */
+#define IOCTL_MAX_DATALEN       4096
+
+#pragma pack(1)
+struct uioctl_t {
+	u32 inlen;
+	u32 outlen;
+	union {
+		u8 fca[16];
+		struct {
+			u8 opcode;
+			u8 subopcode;
+			u16 adapno;
+#if BITS_PER_LONG == 32
+			u8 *buffer;
+			u8 pad[4];
+#endif
+#if BITS_PER_LONG == 64
+			u8 *buffer;
+#endif
+			u32 length;
+		} fcs;
+	} ui;
+	u8 mbox[18];		/* 16 bytes + 2 status bytes */
+	mega_passthru pthru;
+#if BITS_PER_LONG == 32
+	char *data;		/* buffer <= 4096 for 0x80 commands */
+	char pad[4];
+#endif
+#if BITS_PER_LONG == 64
+	char *data;
+#endif
+};
+#pragma pack()
+
+/*
+ * struct mcontroller is used to pass information about the controllers in the
+ * system. Its upto the application how to use the information. We are passing
+ * as much info about the cards as possible and useful. Before issuing the
+ * call to find information about the cards, the applicaiton needs to issue a
+ * ioctl first to find out the number of controllers in the system.
+ */
+#define MAX_CONTROLLERS 32
+
+struct mcontroller {
+	u64 base;
+	u8 irq;
+	u8 numldrv;
+	u8 pcibus;
+	u16 pcidev;
+	u8 pcifun;
+	u16 pciid;
+	u16 pcivendor;
+	u8 pcislot;
+	u32 uid;
+};
+
+struct mbox_passthru {
+	u8 cmd;
+	u8 cmdid;
+	u16 pad1;
+	u32 pad2;
+	u32 dataxferaddr;
+	u8 pad3;
+	u8 pad4;
+	u8 rsvd;
+	u8 mboxbusy;
+	u8 nstatus;
+	u8 status;
+};
+
+/*
+ * Defines for Driver IOCTL interface, Op-code:M_RD_DRIVER_IOCTL_INTERFACE
+ */
+#define MEGAIOC_MAGIC  	'm'
+#define MEGAIOCCMD     	_IOWR(MEGAIOC_MAGIC, 0)	/* Mega IOCTL command */
+
+#define MEGAIOC_QNADAP		'm'	/* Query # of adapters */
+#define MEGAIOC_QDRVRVER	'e'	/* Query driver version */
+#define MEGAIOC_QADAPINFO   	'g'	/* Query adapter information */
+#define MKADAP(adapno)	  	(MEGAIOC_MAGIC << 8 | (adapno) )
+#define GETADAP(mkadap)	 	( (mkadap) ^ MEGAIOC_MAGIC << 8 )
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)	/*0x20300 */
+extern struct proc_dir_entry proc_scsi_megaraid;
+#endif
+
+/* For Host Re-Ordering */
+#define MAX_CONTROLLERS	32
+
+struct mega_hbas {
+	int is_bios_enabled;
+	mega_host_config *hostdata_addr;
+};
+
+#define		IS_BIOS_ENABLED		0x62
+#define		GET_BIOS		0x01
+
+/*================================================================
+ *
+ *                    Function prototypes
+ *
+ *================================================================
+ */
+static const char *megaraid_info (struct Scsi_Host *);
+int megaraid_detect (Scsi_Host_Template *);
+static int megaraid_release (struct Scsi_Host *);
+static int megaraid_command (Scsi_Cmnd *);
+static int megaraid_abort (Scsi_Cmnd *);
+static int megaraid_reset (Scsi_Cmnd *, unsigned int);
+static int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int megaraid_biosparam (Disk *, kdev_t, int *);
+static int megaraid_proc_info (char *buffer, char **start, off_t offset,
+			int length, int hostno, int inout);
+
+static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData,
+			 mega_scb * scb, int intr);
+static int mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
+			      u32 * buffer, u32 * length);
+static int mega_busyWaitMbox (mega_host_config *);
+static int mega_runpendq (mega_host_config *);
+static void mega_rundoneq (mega_host_config *);
+static void mega_cmd_done (mega_host_config *, mega_scb *, int);
+static inline void mega_freeSgList (mega_host_config * megaCfg);
+static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry,
+				   mega_Enquiry3 * enquiry3,
+				   megaRaidProductInfo * productInfo);
+
+static int megaraid_reboot_notify (struct notifier_block *,
+				   unsigned long, void *);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
+static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
+static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb,
+			   mega_ioctl_mbox * mbox);
+#endif
+
+static int megadev_open (struct inode *, struct file *);
+static int megadev_ioctl_entry (struct inode *, struct file *,
+				unsigned int, unsigned long);
+static int megadev_ioctl (struct inode *, struct file *,
+			  unsigned int, unsigned long);
+static mega_scb *megadev_doioctl (mega_host_config *, Scsi_Cmnd *);
+static int megadev_close (struct inode *, struct file *);
+static void megadev_ioctl_done (Scsi_Cmnd *);
+static int mega_init_scb (mega_host_config *);
+static void enq_scb_freelist (mega_host_config *, mega_scb *,
+			      int lock, int intr);
+
+static int mega_is_bios_enabled (mega_host_config *);
+static void mega_reorder_hosts (void);
+static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
+
+static void mega_create_proc_entry (int index, struct proc_dir_entry *);
 
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.4.2/linux/drivers/scsi/ncr53c8xx.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/ncr53c8xx.c	Tue Mar  6 19:34:25 2001
@@ -73,8 +73,6 @@
 */
 
 /*
-**	May 11 2000, version 3.3b
-**
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
 **	    Wide negotiation        (depends on the NCR Chip)
@@ -105,7 +103,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.3b"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx-3.4.3-20010212"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -136,7 +134,6 @@
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/time.h>
@@ -192,7 +189,8 @@
 **	Donnot compile integrity checking code for Linux-2.3.0 
 **	and above since SCSI data structures are not ready yet.
 */
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0)
+/* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */
+#if 0
 #define	SCSI_NCR_INTEGRITY_CHECKING
 #endif
 
@@ -556,50 +554,12 @@
 #define UC_SETORDER	13
 #define UC_SETWIDE	14
 #define UC_SETFLAG	15
-#define UC_CLEARPROF	16
 #define UC_SETVERBOSE	17
 
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
 #define	UF_NOSCAN	(0x04)
 
-/*---------------------------------------
-**
-**	Timestamps for profiling
-**
-**---------------------------------------
-*/
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-
-struct tstamp {
-	u_long start;
-	u_long end;
-	u_long command;
-	u_long status;
-	u_long disconnect;
-	u_long reselect;
-};
-
-/*
-**	profiling data (per device)
-*/
-
-struct profile {
-	u_long	num_trans;
-	u_long	num_kbytes;
-	u_long	rest_bytes;
-	u_long	num_disc;
-	u_long	num_break;
-	u_long	num_int;
-	u_long	num_fly;
-	u_long	ms_setup;
-	u_long	ms_data;
-	u_long	ms_disc;
-	u_long	ms_post;
-};
-#endif
-
 /*========================================================================
 **
 **	Declaration of structs:		target control block
@@ -841,14 +801,6 @@
 	*/
 	ccb_p	cp;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*----------------------------------------------------------------
-	**	Space for some timestamps to gather profiling data.
-	**----------------------------------------------------------------
-	*/
-	struct tstamp	stamp;
-#endif
-
 	/*----------------------------------------------------------------
 	**	Status fields.
 	**----------------------------------------------------------------
@@ -1176,11 +1128,6 @@
 	*/
 	struct ncr_reg	regdump;	/* Register dump		*/
 	u_long		regtime;	/* Time it has been done	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	struct profile	profile;	/* Profiling data		*/
-	u_int		disc_phys;	/* Disconnection counters 	*/
-	u_int		disc_ref;
-#endif
 
 	/*----------------------------------------------------------------
 	**	Miscellaneous buffers accessed by the scripts-processor.
@@ -1216,9 +1163,6 @@
 	**	Fields that should be removed or changed.
 	**----------------------------------------------------------------
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	u_long		ktime;		/* Copy of kernel time		*/
-#endif
 	struct ccb	*ccb;		/* Global CCB			*/
 	struct usrcmd	user;		/* Command from user		*/
 	u_char		release_stage;	/* Synchronisation stage on release  */
@@ -1272,19 +1216,11 @@
 	ncrcmd	send_ident	[  9];
 	ncrcmd	prepare		[  6];
 	ncrcmd	prepare2	[  7];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  command		[  9];
-#else
 	ncrcmd  command		[  6];
-#endif
 	ncrcmd  dispatch	[ 32];
 	ncrcmd  clrack		[  4];
 	ncrcmd	no_data		[ 17];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  status		[ 11];
-#else
 	ncrcmd  status		[  8];
-#endif
 	ncrcmd  msg_in		[  2];
 	ncrcmd  msg_in2		[ 16];
 	ncrcmd  msg_bad		[  4];
@@ -1303,22 +1239,14 @@
 #endif
 	ncrcmd  save_dp		[  7];
 	ncrcmd  restore_dp	[  5];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  disconnect	[ 28];
-#else
 	ncrcmd  disconnect	[ 17];
-#endif
 	ncrcmd	msg_out		[  9];
 	ncrcmd	msg_out_done	[  7];
 	ncrcmd  idle		[  2];
 	ncrcmd	reselect	[  8];
 	ncrcmd	reselected	[  8];
 	ncrcmd	resel_dsa	[  6];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd	loadpos1	[  7];
-#else
 	ncrcmd	loadpos1	[  4];
-#endif
 	ncrcmd  resel_lun	[  6];
 	ncrcmd	resel_tag	[  6];
 	ncrcmd	jump_to_nexus	[  4];
@@ -1416,10 +1344,6 @@
 static	int	ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
 #endif
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-static	void	ncb_profile	(ncb_p np, ccb_p cp);
-#endif
-
 static	void	ncr_script_copy_and_bind
 				(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
 static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
@@ -1673,14 +1597,6 @@
 		PADDR (dispatch),
 
 }/*-------------------------< COMMAND >--------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	... set a timestamp ...
-	*/
-	SCR_COPY (sizeof (u_long)),
-		NADDR (ktime),
-		NADDR (header.stamp.command),
-#endif
 	/*
 	**	... and send the command
 	*/
@@ -1786,14 +1702,6 @@
 		PADDR (no_data),
 
 }/*-------------------------< STATUS >--------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	set the timestamp.
-	*/
-	SCR_COPY (sizeof (u_long)),
-		NADDR (ktime),
-		NADDR (header.stamp.status),
-#endif
 	/*
 	**	get the status
 	*/
@@ -2020,24 +1928,6 @@
 	*/
 	SCR_WAIT_DISC,
 		0,
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	Profiling:
-	**	Set a time stamp,
-	**	and count the disconnects.
-	*/
-	SCR_COPY (sizeof (u_long)),
-		NADDR (ktime),
-		NADDR (header.stamp.disconnect),
-	SCR_COPY (4),
-		NADDR (disc_phys),
-		RADDR (scratcha),
-	SCR_REG_REG (scratcha, SCR_ADD, 0x01),
-		0,
-	SCR_COPY (4),
-		RADDR (scratcha),
-		NADDR (disc_phys),
-#endif
 	/*
 	**	Status is: DISCONNECTED.
 	*/
@@ -2178,14 +2068,6 @@
 }/*-------------------------< LOADPOS1 >-------------------*/,{
 		0,
 		NADDR (header),
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**      Set a time stamp for this reselection
-	*/
-	SCR_COPY (sizeof (u_long)),
-		NADDR (ktime),
-		NADDR (header.stamp.reselect),
-#endif
 	/*
 	**	The DSA contains the data structure address.
 	*/
@@ -3136,8 +3018,7 @@
 
 				switch (old & RELOC_MASK) {
 				case RELOC_REGISTER:
-					new = (old & ~RELOC_MASK)
-						+ pcivtobus(np->paddr);
+					new = (old & ~RELOC_MASK) + np->paddr;
 					break;
 				case RELOC_LABEL:
 					new = (old & ~RELOC_MASK) + np->p_script;
@@ -3359,11 +3240,19 @@
 
 	np->maxwide	= (np->features & FE_WIDE)? 1 : 0;
 
-	/*
-	**	Get the frequency of the chip's clock.
-	**	Find the right value for scntl3.
-	*/
+ 	/*
+	 *  Guess the frequency of the chip's clock.
+	 */
+	if	(np->features & (FE_ULTRA3 | FE_ULTRA2))
+		np->clock_khz = 160000;
+	else if	(np->features & FE_ULTRA)
+		np->clock_khz = 80000;
+	else
+		np->clock_khz = 40000;
 
+	/*
+	 *  Get the clock multiplier factor.
+ 	 */
 	if	(np->features & FE_QUAD)
 		np->multiplier	= 4;
 	else if	(np->features & FE_DBLR)
@@ -3371,10 +3260,11 @@
 	else
 		np->multiplier	= 1;
 
-	np->clock_khz	= (np->features & FE_CLK80)? 80000 : 40000;
-	np->clock_khz	*= np->multiplier;
-
-	if (np->clock_khz != 40000)
+	/*
+	 *  Measure SCSI clock frequency for chips 
+	 *  it may vary from assumed one.
+	 */
+	if (np->features & FE_VARCLK)
 		ncr_getclock(np, np->multiplier);
 
 	/*
@@ -3741,8 +3631,8 @@
 	np->paddr	= device->slot.base;
 	np->paddr2	= (np->features & FE_RAM)? device->slot.base_2 : 0;
 
-#ifndef NCR_IOMAPPED
-	np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128);
+#ifndef SCSI_NCR_IOMAPPED
+	np->vaddr = remap_pci_mem(device->slot.base_c, (u_long) 128);
 	if (!np->vaddr) {
 		printk(KERN_ERR
 			"%s: can't map memory mapped IO region\n",ncr_name(np));
@@ -3761,7 +3651,7 @@
 
 	np->reg = (struct ncr_reg*) np->vaddr;
 
-#endif /* !defined NCR_IOMAPPED */
+#endif /* !defined SCSI_NCR_IOMAPPED */
 
 	/*
 	**	Try to map the controller chip into iospace.
@@ -3810,7 +3700,7 @@
 	instance->this_id       = np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= SCSI_NCR_MAX_LUN;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29)
 	instance->base		= (unsigned long) np->reg;
 #else
@@ -3845,8 +3735,7 @@
 	np->scripth	= np->scripth0;
 	np->p_scripth	= vtobus(np->scripth);
 
-	np->p_script	= (np->paddr2) ?
-			  pcivtobus(np->paddr2) : vtobus(np->script0);
+	np->p_script	= (np->paddr2) ?  np->paddr2 : vtobus(np->script0);
 
 	ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
 	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
@@ -3988,14 +3877,14 @@
 	printk(KERN_INFO "%s: detaching...\n", ncr_name(np));
 	if (!np)
 		goto unregister;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (np->vaddr) {
 #ifdef DEBUG_NCR53C8XX
 		printk(KERN_DEBUG "%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 		unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
 	}
-#endif /* !NCR_IOMAPPED */
+#endif /* !SCSI_NCR_IOMAPPED */
 	if (np->base_io) {
 #ifdef DEBUG_NCR53C8XX
 		printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
@@ -4373,7 +4262,8 @@
 	**
 	**---------------------------------------------
 	*/
-	if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) {
+	if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && 
+	    (tp->usrflag & UF_NOSCAN)) {
 		tp->usrflag &= ~UF_NOSCAN;
 		return DID_BAD_TARGET;
 	}
@@ -4418,18 +4308,6 @@
 	}
 #endif
 
-	/*---------------------------------------------------
-	**
-	**	timestamp
-	**
-	**----------------------------------------------------
-	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
-	cp->phys.header.stamp.start = jiffies;
-#endif
-
-
 	/*----------------------------------------------------
 	**
 	**	Build the identify / tag / sdtr message
@@ -5105,12 +4983,12 @@
 	**	Release Memory mapped IO region and IO mapped region
 	*/
 
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 #ifdef DEBUG_NCR53C8XX
 	printk("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 	unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#endif /* !NCR_IOMAPPED */
+#endif /* !SCSI_NCR_IOMAPPED */
 
 #ifdef DEBUG_NCR53C8XX
 	printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
@@ -5190,12 +5068,8 @@
 		return;
 
 	/*
-	**	timestamp
-	**	Optional, spare some CPU time
+	**	Print minimal debug information.
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncb_profile (np, cp);
-#endif
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
 		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
@@ -5722,16 +5596,15 @@
 	/*
 	**    Start script processor.
 	*/
-	MEMORY_BARRIER();
 	if (np->paddr2) {
 		if (bootverbose)
 			printk ("%s: Downloading SCSI SCRIPTS.\n",
 				ncr_name(np));
 		OUTL (nc_scratcha, vtobus(np->script0));
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, start_ram));
 	}
 	else
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 }
 
 /*==========================================================
@@ -6201,12 +6074,6 @@
 			tp->usrflag = np->user.data;
 		};
 		break;
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	case UC_CLEARPROF:
-		bzero(&np->profile, sizeof(np->profile));
-		break;
-#endif
 	}
 	np->user.cmd=0;
 }
@@ -6241,12 +6108,7 @@
 		return;
 	}
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	np->ktime = thistime;
-	np->timer.expires = ktime_get(1);
-#else
 	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
-#endif
 	add_timer(&np->timer);
 
 	/*
@@ -6274,15 +6136,6 @@
 		**	block ncr interrupts
 		*/
 		np->lasttime = thistime;
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-		/*
-		**	Reset profile data to avoid ugly overflow
-		**	(Limited to 1024 GB for 32 bit architecture)
-		*/
-		if (np->profile.num_kbytes > (~0UL >> 2))
-			bzero(&np->profile, sizeof(np->profile));
-#endif
 	}
 
 #ifdef SCSI_NCR_BROKEN_INTR
@@ -6426,19 +6279,12 @@
 		OUTB (nc_istat, (istat & SIGP) | INTF);
 		istat = INB (nc_istat);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-		np->profile.num_fly++;
-#endif
 		ncr_wakeup_done (np);
 	};
 
 	if (!(istat & (SIP|DIP)))
 		return;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	np->profile.num_int++;
-#endif
-
 	if (istat & CABRT)
 		OUTB (nc_istat, CABRT);
 
@@ -6493,7 +6339,7 @@
 				ncr_name(np), istat, dstat, sist);
 			return;
 		}
-		OUTONB (nc_dcntl, (STD|NOCOM));
+		OUTONB_STD ();
 		return;
 	};
 
@@ -6570,7 +6416,7 @@
 	if (sist & UDC) {
 		printk ("%s: unexpected disconnect\n", ncr_name(np));
 		OUTB (HS_PRT, HS_UNEXPECTED);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, cleanup));
 		return;
 	};
 
@@ -6622,7 +6468,7 @@
 	**	repair start queue and jump to start point.
 	*/
 
-	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart));
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, sto_restart));
 	return;
 }
 
@@ -6740,7 +6586,7 @@
 	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
 
 	np->msgout[0] = msg;
-	OUTL (nc_dsp, jmp);
+	OUTL_DSP (jmp);
 	return 1;
 
 reset_all:
@@ -6991,11 +6837,8 @@
 	**	fake the return address (to the patch).
 	**	and restart script processor at dispatcher.
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	np->profile.num_break++;
-#endif
 	OUTL (nc_temp, newtmp);
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch));
 	return;
 
 	/*
@@ -7057,7 +6900,7 @@
 	}
 
 	if (nxtdsp) {
-		OUTL (nc_dsp, nxtdsp);
+		OUTL_DSP (nxtdsp);
 		return;
 	}
 
@@ -7131,7 +6974,7 @@
 		ncr_put_start_queue(np, cp);
 		if (disc_cnt)
 			INB (nc_ctest2);		/* Clear SIGP */
-		OUTL (nc_dsp,	NCB_SCRIPT_PHYS (np, reselect));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, reselect));
 		return;
 	case S_TERMINATED:
 	case S_CHECK_COND:
@@ -7199,12 +7042,12 @@
 
 		ncr_put_start_queue(np, cp);
 
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 		return;
 	}
 
 out:
-	OUTONB (nc_dcntl, (STD|NOCOM));
+	OUTONB_STD ();
 	return;
 }
 
@@ -7267,7 +7110,7 @@
 		**	We just assume lun=0, 1 CCB, no tag.
 		*/
 		if (tp->lp[0]) { 
-			OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0]));
+			OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0]));
 			return;
 		}
 	case SIR_RESEL_BAD_TARGET:	/* Will send a TARGET RESET message */
@@ -7489,13 +7332,13 @@
 					**	Answer wasn't acceptable.
 					*/
 					ncr_setsync (np, cp, 0, 0xe0);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
 					/*
 					**	Answer is ok.
 					*/
 					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
@@ -7528,7 +7371,7 @@
 		}
 
 		if (!ofs) {
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+			OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 			return;
 		}
 		np->msgin [0] = M_NOOP;
@@ -7586,13 +7429,13 @@
 					**	Answer wasn't acceptable.
 					*/
 					ncr_setwide (np, cp, 0, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
 					/*
 					**	Answer is ok.
 					*/
 					ncr_setwide (np, cp, wide, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
@@ -7700,7 +7543,7 @@
 	};
 
 out:
-	OUTONB (nc_dcntl, (STD|NOCOM));
+	OUTONB_STD ();
 }
 
 /*==========================================================
@@ -7888,8 +7731,7 @@
 }
 
 
-#define ncr_reg_bus_addr(r) \
-	(pcivtobus(np->paddr) + offsetof (struct ncr_reg, r))
+#define ncr_reg_bus_addr(r) (np->paddr + offsetof (struct ncr_reg, r))
 
 /*------------------------------------------------------------------------
 **	Initialize the fixed part of a CCB structure.
@@ -8321,7 +8163,7 @@
 **==========================================================
 */
 
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 static int __init ncr_regtest (struct ncb* np)
 {
 	register volatile u_int32 data;
@@ -8350,7 +8192,7 @@
 {
 	u_int32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
 	int	i, err=0;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (np->reg) {
             err |= ncr_regtest (np);
             if (err) return (err);
@@ -8370,7 +8212,7 @@
 	/*
 	**	Start script (exchange values)
 	*/
-	OUTL (nc_dsp, pc);
+	OUTL_DSP (pc);
 	/*
 	**	Wait 'til done (with timeout)
 	*/
@@ -8434,73 +8276,6 @@
 /*==========================================================
 **
 **
-**	Profiling the drivers and targets performance.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-
-/*
-**	Compute the difference in jiffies ticks.
-*/
-
-#define ncr_delta(from, to) \
-	( ((to) && (from))? (to) - (from) : -1 )
-
-#define PROFILE  cp->phys.header.stamp
-static	void ncb_profile (ncb_p np, ccb_p cp)
-{
-	long co, st, en, di, re, post, work, disc;
-	u_int diff;
-
-	PROFILE.end = jiffies;
-
-	st = ncr_delta (PROFILE.start,PROFILE.status);
-	if (st<0) return;	/* status  not reached  */
-
-	co = ncr_delta (PROFILE.start,PROFILE.command);
-	if (co<0) return;	/* command not executed */
-
-	en = ncr_delta (PROFILE.start,PROFILE.end),
-	di = ncr_delta (PROFILE.start,PROFILE.disconnect),
-	re = ncr_delta (PROFILE.start,PROFILE.reselect);
-	post = en - st;
-
-	/*
-	**	@PROFILE@  Disconnect time invalid if multiple disconnects
-	*/
-
-	if (di>=0) disc = re - di; else  disc = 0;
-
-	work = (st - co) - disc;
-
-	diff = (scr_to_cpu(np->disc_phys) - np->disc_ref) & 0xff;
-	np->disc_ref += diff;
-
-	np->profile.num_trans	+= 1;
-	if (cp->cmd) {
-		np->profile.num_kbytes	+= (cp->cmd->request_bufflen >> 10);
-		np->profile.rest_bytes	+= (cp->cmd->request_bufflen & (0x400-1));
-		if (np->profile.rest_bytes >= 0x400) {
-			++np->profile.num_kbytes;
-			np->profile.rest_bytes	-= 0x400;
-		}
-	}
-	np->profile.num_disc	+= diff;
-	np->profile.ms_setup	+= co;
-	np->profile.ms_data	+= work;
-	np->profile.ms_disc	+= disc;
-	np->profile.ms_post	+= post;
-}
-#undef PROFILE
-
-#endif /* SCSI_NCR_PROFILE_SUPPORT */
-
-/*==========================================================
-**
-**
 **	Device lookup.
 **
 **	@GENSCSI@ should be integrated to scsiconf.c
@@ -9179,8 +8954,6 @@
 		uc->cmd = UC_SETDEBUG;
 	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)
 		uc->cmd = UC_SETFLAG;
-	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
-		uc->cmd = UC_CLEARPROF;
 	else
 		arg_len = 0;
 
@@ -9297,11 +9070,9 @@
 
 #ifdef SCSI_NCR_USER_INFO_SUPPORT
 /*
-**	Copy formatted profile information into the input buffer.
+**	Copy formatted information into the input buffer.
 */
 
-#define to_ms(t) ((t) * 1000 / HZ)
-
 static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
 {
 	struct info_str info;
@@ -9335,20 +9106,6 @@
 			  driver_setup.debug, driver_setup.verbose);
 	}
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	copy_info(&info, "Profiling information:\n");
-	copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
-	copy_info(&info, "  %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
-	copy_info(&info, "  %-12s = %lu\n", "num_disc",	np->profile.num_disc);
-	copy_info(&info, "  %-12s = %lu\n", "num_break",np->profile.num_break);
-	copy_info(&info, "  %-12s = %lu\n", "num_int",	np->profile.num_int);
-	copy_info(&info, "  %-12s = %lu\n", "num_fly",	np->profile.num_fly);
-	copy_info(&info, "  %-12s = %lu\n", "ms_setup",	to_ms(np->profile.ms_setup));
-	copy_info(&info, "  %-12s = %lu\n", "ms_data",	to_ms(np->profile.ms_data));
-	copy_info(&info, "  %-12s = %lu\n", "ms_disc",	to_ms(np->profile.ms_disc));
-	copy_info(&info, "  %-12s = %lu\n", "ms_post",	to_ms(np->profile.ms_post));
-#endif
-	
 	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
@@ -9513,5 +9270,10 @@
 **	Module stuff
 */
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 static Scsi_Host_Template driver_template = NCR53C8XX;
 #include "scsi_module.c"
+#elif defined(MODULE)
+Scsi_Host_Template driver_template = NCR53C8XX;
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h
--- v2.4.2/linux/drivers/scsi/ncr53c8xx.h	Mon Sep 18 14:09:49 2000
+++ linux/drivers/scsi/ncr53c8xx.h	Tue Mar  6 19:34:25 2001
@@ -50,6 +50,8 @@
 **	Used by hosts.c and ncr53c8xx.c with module configuration.
 */
 
+#if (LINUX_VERSION_CODE >= 0x020400) || defined(HOSTS_C) || defined(MODULE)
+
 #include <scsi/scsicam.h>
 
 int ncr53c8xx_abort(Scsi_Cmnd *);
@@ -93,5 +95,7 @@
 			0,	0,	DISABLE_CLUSTERING} 
  
 #endif /* LINUX_VERSION_CODE */
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
 #endif /* NCR53C8XX_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.4.2/linux/drivers/scsi/pci2220i.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/pci2220i.c	Fri Mar  2 18:38:39 2001
@@ -2016,7 +2016,7 @@
 	del_timer (&padapter->timer);
 	if ( status )
 		{
-		DEB (printk ("\npci2220i Interupt hanlder return error"));
+		DEB (printk ("\npci2220i Interrupt handler return error"));
 		zl = DecodeError (padapter, status);
 		}
 	else
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/Config.in linux/drivers/scsi/pcmcia/Config.in
--- v2.4.2/linux/drivers/scsi/pcmcia/Config.in	Tue Feb 15 08:53:46 2000
+++ linux/drivers/scsi/pcmcia/Config.in	Sun Mar  4 14:30:19 2001
@@ -10,13 +10,10 @@
    dep_tristate '  Adaptec AHA152X PCMCIA support' CONFIG_PCMCIA_AHA152X m
    dep_tristate '  Qlogic PCMCIA support' CONFIG_PCMCIA_QLOGIC m
    dep_tristate '  Future Domain PCMCIA support' CONFIG_PCMCIA_FDOMAIN m
-   if [ "$CONFIG_CARDBUS" = "y" ]; then
-      dep_tristate '  Adaptec APA1480 CardBus support' CONFIG_PCMCIA_APA1480 m
-   fi
 fi
 
 if [ "$CONFIG_PCMCIA_QLOGIC" = "y" -o "$CONFIG_PCMCIA_AHA152X" = "y" -o \
-     "$CONFIG_PCMCIA_FDOMAIN" = "y" -o "$CONFIG_PCMCIA_APA1480" = "y" ]; then
+     "$CONFIG_PCMCIA_FDOMAIN" = "y" ]; then
    define_bool CONFIG_PCMCIA_SCSICARD y
 fi
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/Makefile linux/drivers/scsi/pcmcia/Makefile
--- v2.4.2/linux/drivers/scsi/pcmcia/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/scsi/pcmcia/Makefile	Sun Mar  4 14:30:19 2001
@@ -12,7 +12,6 @@
 vpath %c ..
 
 CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT
-CFLAGS_aic7xxx.o = -DPCMCIA -D__NO_VERSION__
 CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__
 CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__
 
@@ -21,12 +20,8 @@
 obj-$(CONFIG_PCMCIA_FDOMAIN)	+= fdomain_cs.o
 obj-$(CONFIG_PCMCIA_AHA152X)	+= aha152x_cs.o
 
-# Cardbus client drivers
-obj-$(CONFIG_PCMCIA_APA1480)	+= apa1480_cb.o
-
-list-multi	:= qlogic_cs.o fdomain_cs.o aha152x_cs.o apa1480_cb.o
+list-multi	:= qlogic_cs.o fdomain_cs.o aha152x_cs.o
 aha152x-objs	:= aha152x_stub.o aha152x.o
-apa1480-objs	:= apa1480_stub.o aic7xxx.o
 fdomain-objs	:= fdomain_stub.o fdomain.o
 qlogic-objs	:= qlogic_stub.o qlogicfas.o
 
@@ -34,9 +29,6 @@
 
 aha152x_cs.o: $(aha152x-objs)
 	$(LD) -r -o $@ $(aha152x-objs)
-
-apa1480_cb.o: $(apa1480-objs)
-	$(LD) -r -o $@ $(apa1480-objs)
 
 fdomain_cs.o: $(fdomain-objs)
 	$(LD) -r -o $@ $(fdomain-objs)
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/aha152x_stub.c linux/drivers/scsi/pcmcia/aha152x_stub.c
--- v2.4.2/linux/drivers/scsi/pcmcia/aha152x_stub.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/pcmcia/aha152x_stub.c	Fri Mar  2 18:38:39 2001
@@ -22,7 +22,7 @@
     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 Public License version 2 (the "GPL"), in which
+    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
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/apa1480_stub.c linux/drivers/scsi/pcmcia/apa1480_stub.c
--- v2.4.2/linux/drivers/scsi/pcmcia/apa1480_stub.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/pcmcia/apa1480_stub.c	Wed Dec 31 16:00:00 1969
@@ -1,174 +0,0 @@
-/*======================================================================
-
-    A driver for the Adaptec APA1480 CardBus SCSI Host Adapter
-
-    apa1480_cb.c 1.22 2000/06/12 21:27:25
-
-    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 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/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 <scsi/scsi.h>
-#include <linux/major.h>
-#include <linux/blk.h>
-
-#include <../drivers/scsi/scsi.h>
-#include <../drivers/scsi/hosts.h>
-#include <scsi/scsi_ioctl.h>
-#include <../drivers/scsi/aic7xxx.h>
-
-#include <pcmcia/driver_ops.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 =
-"apa1480_cb.c 1.22 2000/06/12 21:27:25 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-static int reset = 1;
-static int ultra = 0;
-
-MODULE_PARM(reset, "i");
-MODULE_PARM(ultra, "i");
-
-/*====================================================================*/
-
-static Scsi_Host_Template driver_template = AIC7XXX;
-
-extern void aic7xxx_setup(char *, int *);
-
-static dev_node_t *apa1480_attach(dev_locator_t *loc);
-static void apa1480_detach(dev_node_t *node);
-
-struct driver_operations apa1480_ops = {
-    "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach
-};
-
-/*====================================================================*/
-
-static dev_node_t *apa1480_attach(dev_locator_t *loc)
-{
-    u_char bus, devfn;
-    Scsi_Device *dev;
-    dev_node_t *node;
-    char s[60];
-    int n = 0;
-    struct Scsi_Host *host;
-    
-    if (loc->bus != LOC_PCI) return NULL;
-    bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-    printk(KERN_INFO "apa1480_attach(bus %d, function %d)\n",
-	   bus, devfn);
-
-    driver_template.module = &__this_module;
-
-    sprintf(s, "no_probe:1,no_reset:%d,ultra:%d",
-	    (reset==0), (ultra!=0));
-    aic7xxx_setup(s, NULL);
-    scsi_register_module(MODULE_SCSI_HA, &driver_template);
-
-    node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL);
-    for (host = scsi_hostlist; host; host = host->next)
-	if (host->hostt == &driver_template)
-	    for (dev = host->host_queue; dev; dev = dev->next) {
-	    u_long arg[2], id;
-	    kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
-	    id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
-		((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
-	    node[n].minor = 0;
-	    switch (dev->type) {
-	    case TYPE_TAPE:
-		node[n].major = SCSI_TAPE_MAJOR;
-		sprintf(node[n].dev_name, "st#%04lx", id);
-		break;
-	    case TYPE_DISK:
-	    case TYPE_MOD:
-		node[n].major = SCSI_DISK0_MAJOR;
-		sprintf(node[n].dev_name, "sd#%04lx", id);
-		break;
-	    case TYPE_ROM:
-	    case TYPE_WORM:
-		node[n].major = SCSI_CDROM_MAJOR;
-		sprintf(node[n].dev_name, "sr#%04lx", id);
-		break;
-	    default:
-		node[n].major = SCSI_GENERIC_MAJOR;
-		sprintf(node[n].dev_name, "sg#%04lx", id);
-		break;
-	    }
-	    if (n) node[n-1].next = &node[n];
-	    n++;
-	}
-    if (n == 0) {
-	printk(KERN_INFO "apa1480_cs: no SCSI devices found\n");
-	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
-	kfree(node);
-	return NULL;
-    } else
-	node[n-1].next = NULL;
-    
-    MOD_INC_USE_COUNT;
-    return node;
-}
-
-static void apa1480_detach(dev_node_t *node)
-{
-    MOD_DEC_USE_COUNT;
-    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
-    kfree(node);
-}
-
-/*====================================================================*/
-
-static int __init init_apa1480_cb(void) {
-    DEBUG(0, "%s\n", version);
-    register_driver(&apa1480_ops);
-    return 0;
-}
-
-static void __exit exit_apa1480_cb(void) {
-    DEBUG(0, "apa1480_cs: unloading\n");
-    unregister_driver(&apa1480_ops);
-}
-
-module_init(init_apa1480_cb);
-module_exit(exit_apa1480_cb);
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/fdomain_stub.c linux/drivers/scsi/pcmcia/fdomain_stub.c
--- v2.4.2/linux/drivers/scsi/pcmcia/fdomain_stub.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/pcmcia/fdomain_stub.c	Fri Mar  2 18:38:39 2001
@@ -19,7 +19,7 @@
     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 Public License version 2 (the "GPL"), in which
+    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
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/pcmcia/qlogic_stub.c linux/drivers/scsi/pcmcia/qlogic_stub.c
--- v2.4.2/linux/drivers/scsi/pcmcia/qlogic_stub.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/pcmcia/qlogic_stub.c	Fri Mar  2 18:38:39 2001
@@ -19,7 +19,7 @@
     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 Public License version 2 (the "GPL"), in which
+    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
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.4.2/linux/drivers/scsi/ppa.c	Sat Feb  3 19:51:29 2001
+++ linux/drivers/scsi/ppa.c	Fri Mar  2 18:38:39 2001
@@ -4,7 +4,7 @@
  * (The PPA3 is the embedded controller in the ZIP drive.)
  * 
  * (c) 1995,1996 Grant R. Guenther, grant@torque.net,
- * under the terms of the GNU Public License.
+ * under the terms of the GNU General Public License.
  * 
  * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
  *                     campbell@torque.net
@@ -29,7 +29,7 @@
     int mode;			/* Transfer mode                */
     int host;			/* Host number (for proc)       */
     Scsi_Cmnd *cur_cmd;		/* Current queued command       */
-    struct tq_struct ppa_tq;	/* Polling interupt stuff       */
+    struct tq_struct ppa_tq;	/* Polling interrupt stuff       */
     unsigned long jstart;	/* Jiffies at start             */
     unsigned long recon_tmo;    /* How many usecs to wait for reconnection (6th bit) */
     unsigned int failed:1;	/* Failure flag                 */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h
--- v2.4.2/linux/drivers/scsi/ppa.h	Thu Jan  4 13:00:55 2001
+++ linux/drivers/scsi/ppa.h	Fri Mar  2 18:38:39 2001
@@ -126,7 +126,7 @@
 #define PPA_SELECT_TMO  5000	/* how long to wait for target ? */
 #define PPA_SPIN_TMO    50000	/* ppa_wait loop limiter */
 #define PPA_RECON_TMO   500	/* scsi reconnection loop limiter */
-#define PPA_DEBUG	0	/* debuging option */
+#define PPA_DEBUG	0	/* debugging option */
 #define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
 
 /* args to ppa_connect */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/psi_dale.h linux/drivers/scsi/psi_dale.h
--- v2.4.2/linux/drivers/scsi/psi_dale.h	Fri Feb 18 14:50:03 2000
+++ linux/drivers/scsi/psi_dale.h	Fri Mar  2 18:38:39 2001
@@ -527,7 +527,7 @@
 	USHORT	PIOCycleTime		:8;		// 51 Transfer Cycle Timing - PIO
 	USHORT	Reserved6			:8;		// 52                       - DMA
 	USHORT	DMACycleTime		:8;		// 52                       - DMA
-	USHORT	Valid_54_58			:1;		// 53 words 54 - 58 are vaild
+	USHORT	Valid_54_58			:1;		// 53 words 54 - 58 are valid
 	USHORT	Valid_64_70			:1;		// 53 words 64 - 70 are valid
 	USHORT	Reserved7			:14;	// 53
 	USHORT	LogNumCyl;					// 54 Current Translation - Num Cyl
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c
--- v2.4.2/linux/drivers/scsi/qla1280.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/qla1280.c	Tue Mar  6 19:44:37 2001
@@ -810,6 +810,10 @@
 #endif
                 /* found a adapter */
 		host = scsi_register(template, sizeof(scsi_qla_host_t));
+                if (!host) { 
+			printk(KERN_WARNING "qla1280: Failed to register host, aborting.\n");
+                        return 0;
+                }
 		ha = (scsi_qla_host_t *) host->hostdata;
 		/* Clear our data area */
 		for( j =0, cp = (char *)ha;  j < sizeof(scsi_qla_host_t); j++)
@@ -1095,7 +1099,7 @@
     CMD_HANDLE(cmd) = (unsigned char *)handle;
 
     /* Bookkeeping information */
-    sp->r_start = jiffies;       /* time the request was recieved */
+    sp->r_start = jiffies;       /* time the request was received */
     sp->u_start = 0;              
 
     /* add the command to our queue */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.4.2/linux/drivers/scsi/qlogicfc.c	Mon Sep 18 13:36:25 2000
+++ linux/drivers/scsi/qlogicfc.c	Tue Mar 20 15:05:46 2001
@@ -732,7 +732,7 @@
 	int wait_time;
 	struct Scsi_Host *host = NULL;
 	struct isp2x00_hostdata *hostdata;
-	struct pci_dev *pdev = NULL;
+	struct pci_dev *pdev;
 	unsigned short device_ids[2];
 	dma64_addr_t busaddr;
 	int i;
@@ -751,6 +751,7 @@
 	}
 
 	for (i=0; i<2; i++){
+		pdev = NULL;
 	        while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) {
 			if (pci_enable_device(pdev))
 				continue;
@@ -1428,7 +1429,22 @@
 	        for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++){ 
 		        if (hostdata->handle_ptrs[i] && (hostdata->port_db[hostdata->handle_ptrs[i]->target].loop_id > QLOGICFC_MAX_LOOP_ID || hostdata->adapter_state & AS_REDO_LOOP_PORTDB)){
                                 if (hostdata->port_db[hostdata->handle_ptrs[i]->target].loop_id != hostdata->port_db[0].loop_id){
+					Scsi_Cmnd *Cmnd = hostdata->handle_ptrs[i];
+
+					 if (Cmnd->use_sg)
+						 pci64_unmap_sg(hostdata->pci_dev,
+								(struct scatterlist *)Cmnd->buffer,
+								Cmnd->use_sg,
+								scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					 else if (Cmnd->request_bufflen &&
+						  Cmnd->sc_data_direction != PCI_DMA_NONE)
+						 pci64_unmap_single(hostdata->pci_dev,
+								    *(dma64_addr_t *)&Cmnd->SCp,
+								    Cmnd->request_bufflen,
+								    scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
 					 hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16;
+
 					 if (hostdata->handle_ptrs[i]->scsi_done){
 					   (*hostdata->handle_ptrs[i]->scsi_done) (hostdata->handle_ptrs[i]);
 					 }
@@ -1521,6 +1537,17 @@
 			hostdata->handle_serials[handle] = 0;
 			hostdata->queued--;
 			if (Cmnd != NULL) {
+				if (Cmnd->use_sg)
+					pci64_unmap_sg(hostdata->pci_dev,
+						       (struct scatterlist *)Cmnd->buffer,
+						       Cmnd->use_sg,
+						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				else if (Cmnd->request_bufflen &&
+					 Cmnd->sc_data_direction != PCI_DMA_NONE)
+					pci64_unmap_single(hostdata->pci_dev,
+							   *(dma64_addr_t *)&Cmnd->SCp,
+							   Cmnd->request_bufflen,
+							   scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
 				Cmnd->result = 0x0;
 				(*Cmnd->scsi_done) (Cmnd);
 			} else
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.4.2/linux/drivers/scsi/qlogicisp.c	Mon Sep 18 13:36:25 2000
+++ linux/drivers/scsi/qlogicisp.c	Tue Mar  6 19:44:37 2001
@@ -682,6 +682,9 @@
 			continue;
 
 		host = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
+		if (!host)
+			continue;
+
 		hostdata = (struct isp1020_hostdata *) host->hostdata;
 
 		memset(hostdata, 0, sizeof(struct isp1020_hostdata));
@@ -690,7 +693,7 @@
 
 		if (isp1020_init(host))
 			goto fail_and_unregister;
-		
+
 		if (isp1020_reset_hardware(host)
 #if USE_NVRAM_DEFAULTS
 		    || isp1020_get_defaults(host)
@@ -698,9 +701,7 @@
 		    || isp1020_set_defaults(host)
 #endif /* USE_NVRAM_DEFAULTS */
 		    || isp1020_load_parameters(host)) {
-			iounmap((void *)hostdata->memaddr);
-			release_region(host->io_port, 0xff);
-			goto fail_and_unregister;
+			goto fail_uninit;
 		}
 
 		host->this_id = hostdata->host_param.initiator_scsi_id;
@@ -710,9 +711,7 @@
 		{
 			printk("qlogicisp : interrupt %d already in use\n",
 			       host->irq);
-			iounmap((void *)hostdata->memaddr);
-			release_region(host->io_port, 0xff);
-			goto fail_and_unregister;
+			goto fail_uninit;
 		}
 
 		isp_outw(0x0, host, PCI_SEMAPHORE);
@@ -722,6 +721,9 @@
 		hosts++;
 		continue;
 
+	fail_uninit:
+		iounmap((void *)hostdata->memaddr);
+		release_region(host->io_port, 0xff);
 	fail_and_unregister:
 		if (hostdata->res_cpu)
 			pci_free_consistent(hostdata->pci_dev,
@@ -1406,25 +1408,25 @@
 
 	sh->io_port = io_base;
 
-	if (check_region(sh->io_port, 0xff)) {
+	if (!request_region(sh->io_port, 0xff, "qlogicisp")) {
 		printk("qlogicisp : i/o region 0x%lx-0x%lx already "
 		       "in use\n",
 		       sh->io_port, sh->io_port + 0xff);
 		return 1;
 	}
 
-	request_region(sh->io_port, 0xff, "qlogicisp");
-
  	if ((command & PCI_COMMAND_MEMORY) &&
  	    ((mem_flags & 1) == 0)) {
  		mem_base = (u_long) ioremap(mem_base, PAGE_SIZE);
+		if (!mem_base) {
+ 			printk("qlogicisp : i/o remapping failed.\n");
+			goto out_release;
+		}
  		hostdata->memaddr = mem_base;
  	} else {
- 		if (command & PCI_COMMAND_IO && (io_flags & 3) != 1)
- 		{
- 			printk("qlogicisp : i/o mapping is disabled\n");
-			release_region(sh->io_port, 0xff);
- 			return 1;
+		if (command & PCI_COMMAND_IO && (io_flags & 3) != 1) {
+			printk("qlogicisp : i/o mapping is disabled\n");
+			goto out_release;
  		}
  		hostdata->memaddr = 0; /* zero to signify no i/o mapping */
  		mem_base = 0;
@@ -1439,9 +1441,7 @@
 		printk("qlogicisp : can't decode %s address space 0x%lx\n",
 		       (io_base ? "I/O" : "MEM"),
 		       (io_base ? io_base : mem_base));
-		iounmap((void *)hostdata->memaddr);
-		release_region(sh->io_port, 0xff);
-		return 1;
+		goto out_unmap;
 	}
 
 	hostdata->revision = revision;
@@ -1455,7 +1455,7 @@
 						 &hostdata->res_dma);
 	if (hostdata->res_cpu == NULL) {
 		printk("qlogicisp : can't allocate response queue\n");
-		return 1;
+		goto out_unmap;
 	}
 
 	hostdata->req_cpu = pci_alloc_consistent(hostdata->pci_dev,
@@ -1467,12 +1467,18 @@
 				    hostdata->res_cpu,
 				    hostdata->res_dma);
 		printk("qlogicisp : can't allocate request queue\n");
-		return 1;
+		goto out_unmap;
 	}
 
 	LEAVE("isp1020_init");
 
 	return 0;
+
+out_unmap:
+	iounmap((void *)hostdata->memaddr);
+out_release:
+	release_region(sh->io_port, 0xff);
+	return 1;
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.4.2/linux/drivers/scsi/scsi_error.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/scsi_error.c	Sun Mar  4 14:30:27 2001
@@ -492,31 +492,20 @@
 {
 	static unsigned char tur_command[6] =
 	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
-	unsigned char scsi_result0[256], *scsi_result = NULL;
 
 	memcpy((void *) SCpnt->cmnd, (void *) tur_command,
 	       sizeof(tur_command));
 
 	SCpnt->cmnd[1] = SCpnt->lun << 5;
 
-	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
-	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
-
-	if (scsi_result == NULL) {
-		printk("cannot allocate scsi_result in scsi_test_unit_ready.\n");
-		return FAILED;
-	}
 	/*
-	 * Zero the sense buffer.  Some host adapters automatically always request
-	 * sense, so it is not a good idea that SCpnt->request_buffer and
-	 * SCpnt->sense_buffer point to the same address (DB).
-	 * 0 is not a valid sense code. 
+	 * Zero the sense buffer.  The SCSI spec mandates that any
+	 * untransferred sense data should be interpreted as being zero.
 	 */
 	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-	memset((void *) scsi_result, 0, 256);
 
-	SCpnt->request_buffer = scsi_result;
-	SCpnt->request_bufflen = 256;
+	SCpnt->request_buffer = NULL;
+	SCpnt->request_bufflen = 0;
 	SCpnt->use_sg = 0;
 	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
 	SCpnt->underflow = 0;
@@ -524,15 +513,6 @@
 
 	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
 
-	/* Last chance to have valid sense data */
-	if (!scsi_sense_valid(SCpnt))
-		memcpy((void *) SCpnt->sense_buffer,
-		       SCpnt->request_buffer,
-		       sizeof(SCpnt->sense_buffer));
-
-	if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-		kfree(scsi_result);
-
 	/*
 	 * When we eventually call scsi_finish, we really wish to complete
 	 * the original request, so let's restore the original data. (DB)
@@ -549,6 +529,9 @@
 	/*
 	 * Hey, we are done.  Let's look to see what happened.
 	 */
+	SCSI_LOG_ERROR_RECOVERY(3,
+		printk("scsi_test_unit_ready: SCpnt %p eh_state %x\n",
+		SCpnt, SCpnt->eh_state));
 	return SCpnt->eh_state;
 }
 
@@ -671,11 +654,8 @@
 		spin_unlock_irqrestore(&io_request_lock, flags);
 
 		SCpnt->result = temp;
-		if (scsi_eh_completed_normally(SCpnt)) {
-			SCpnt->eh_state = SUCCESS;
-		} else {
-			SCpnt->eh_state = FAILED;
-		}
+		/* Fall through to code below to examine status. */
+		SCpnt->eh_state = SUCCESS;
 	}
 
 	/*
@@ -683,7 +663,10 @@
 	 * did complete normally.
 	 */
 	if (SCpnt->eh_state == SUCCESS) {
-		switch (scsi_eh_completed_normally(SCpnt)) {
+		int ret = scsi_eh_completed_normally(SCpnt);
+		SCSI_LOG_ERROR_RECOVERY(3,
+			printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret));
+		switch (ret) {
 		case SUCCESS:
 			SCpnt->eh_state = SUCCESS;
 			break;
@@ -1104,7 +1087,6 @@
  */
 STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt)
 {
-	int rtn;
 	/*
 	 * First check the host byte, to see if there is anything in there
 	 * that would indicate what we need to do.
@@ -1144,11 +1126,7 @@
 	case COMMAND_TERMINATED:
 		return SUCCESS;
 	case CHECK_CONDITION:
-		rtn = scsi_check_sense(SCpnt);
-		if (rtn == NEEDS_RETRY) {
-			return FAILED;
-		}
-		return rtn;
+		return scsi_check_sense(SCpnt);
 	case CONDITION_GOOD:
 	case INTERMEDIATE_GOOD:
 	case INTERMEDIATE_C_GOOD:
@@ -1634,8 +1612,10 @@
 						 * FIXME(eric) - is this really the correct thing to do?
 						 */
 						if (rtn != SUCCESS) {
-							SCloop->device->online = FALSE;
-							SCloop->host->host_failed--;
+							printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after bus reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+
+							SDloop->online = FALSE;
+							SDloop->host->host_failed--;
 							scsi_eh_finish_command(&SCdone, SCloop);
 						}
 					}
@@ -1725,8 +1705,9 @@
 							}
 						}
 						if (rtn != SUCCESS) {
-							SCloop->device->online = FALSE;
-							SCloop->host->host_failed--;
+							printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after host reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+							SDloop->online = FALSE;
+							SDloop->host->host_failed--;
 							scsi_eh_finish_command(&SCdone, SCloop);
 						}
 					}
@@ -1753,7 +1734,11 @@
 	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
 		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
 			if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) {
-				SCloop->device->online = FALSE;
+				SDloop = SCloop->device;
+				if (SDloop->online == TRUE) {
+					printk(KERN_INFO "scsi: device set offline - command error recover failed: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+					SDloop->online = FALSE;
+				}
 
 				/*
 				 * This should pass the failure up to the top level driver, and
@@ -1765,7 +1750,7 @@
 					SCloop->result |= (DRIVER_TIMEOUT << 24);
 				}
 				SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n",
-				    SCloop->device->id, SCloop->result));
+				    SDloop->id, SCloop->result));
 
 				scsi_eh_finish_command(&SCdone, SCloop);
 			}
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.4.2/linux/drivers/scsi/scsi_lib.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/scsi_lib.c	Fri Mar  2 18:38:39 2001
@@ -549,7 +549,7 @@
 	 *	number of sectors.  If we are done, the command block will
 	 *	be released, and the queue function will be goosed.  If we
 	 *	are not done, then scsi_end_request will directly goose
-	 *	the the queue.
+	 *	the queue.
 	 *
 	 *	We can just use scsi_queue_next_request() here.  This
 	 *	would be used if we just wanted to retry, for example.
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sun3_scsi.c linux/drivers/scsi/sun3_scsi.c
--- v2.4.2/linux/drivers/scsi/sun3_scsi.c	Fri Dec 29 14:07:22 2000
+++ linux/drivers/scsi/sun3_scsi.c	Fri Mar  2 18:38:39 2001
@@ -34,7 +34,7 @@
 
 
 /*
- * This is from mac_scsi.h, but hey, maybe this is usefull for Sun3 too! :)
+ * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :)
  *
  * Options :
  *
@@ -118,7 +118,7 @@
 /* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
 #define SUN3_DVMA_BUFSIZE 0xe000
 
-/* minimum number of bytes to to dma on */
+/* minimum number of bytes to do dma on */
 #define SUN3_DMA_MINSIZE 128
 
 static volatile unsigned char *sun3_scsi_regp;
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sun3x_esp.c linux/drivers/scsi/sun3x_esp.c
--- v2.4.2/linux/drivers/scsi/sun3x_esp.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/sun3x_esp.c	Tue Mar  6 19:44:37 2001
@@ -103,7 +103,11 @@
 					   sizeof (cmd_buffer));
 
 	esp->irq = 2;
-	request_irq(esp->irq, esp_intr, SA_INTERRUPT, "SUN3X SCSI", NULL);
+	if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
+			"SUN3X SCSI", NULL)) {
+		esp_deallocate(esp);
+		return 0;
+	}
 
 	esp->scsi_id = 7;
 	esp->diff = 0;
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c
--- v2.4.2/linux/drivers/scsi/sym53c416.c	Sat Nov 11 19:01:11 2000
+++ linux/drivers/scsi/sym53c416.c	Tue Mar  6 19:44:37 2001
@@ -183,14 +183,10 @@
 #define sym53c416_base_2 sym53c416_2
 #define sym53c416_base_3 sym53c416_3
 
-static unsigned short sym53c416_base = 0;
-static unsigned int sym53c416_irq = 0;
-static unsigned short sym53c416_base_1 = 0;
-static unsigned int sym53c416_irq_1 = 0;
-static unsigned short sym53c416_base_2 = 0;
-static unsigned int sym53c416_irq_2 = 0;
-static unsigned short sym53c416_base_3 = 0;
-static unsigned int sym53c416_irq_3 = 0;
+static unsigned int sym53c416_base[2] = {0,0};
+static unsigned int sym53c416_base_1[2] = {0,0};
+static unsigned int sym53c416_base_2[2] = {0,0};
+static unsigned int sym53c416_base_3[2] = {0,0};
 
 #endif
 
@@ -636,26 +632,26 @@
   ints[0] = 2;
   if(sym53c416_base)
     {
-    ints[1] = sym53c416_base;
-    ints[2] = sym53c416_irq;
+    ints[1] = sym53c416_base[0];
+    ints[2] = sym53c416_base[1];
     sym53c416_setup(NULL, ints);
     }
   if(sym53c416_base_1)
     {
-    ints[1] = sym53c416_base_1;
-    ints[2] = sym53c416_irq_1;
+    ints[1] = sym53c416_base_1[0];
+    ints[2] = sym53c416_base_1[1];
     sym53c416_setup(NULL, ints);
     }
   if(sym53c416_base_2)
     {
-    ints[1] = sym53c416_base_2;
-    ints[2] = sym53c416_irq_2;
+    ints[1] = sym53c416_base_2[0];
+    ints[2] = sym53c416_base_2[1];
     sym53c416_setup(NULL, ints);
     }
   if(sym53c416_base_3)
     {
-    ints[1] = sym53c416_base_3;
-    ints[2] = sym53c416_irq_3;
+    ints[1] = sym53c416_base_3[0];
+    ints[2] = sym53c416_base_3[1];
     sym53c416_setup(NULL, ints);
     }
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.4.2/linux/drivers/scsi/sym53c8xx.c	Wed Feb 21 18:20:33 2001
+++ linux/drivers/scsi/sym53c8xx.c	Tue Mar 20 12:04:58 2001
@@ -55,8 +55,6 @@
 */
 
 /*
-**	May 11 2000, sym53c8xx 1.6b
-**
 **	Supported SCSI features:
 **	    Synchronous data transfers
 **	    Wide16 SCSI BUS
@@ -87,11 +85,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.6b"
-
-/* #define DEBUG_896R1 */
-#define SCSI_NCR_OPTIMIZE_896
-/* #define SCSI_NCR_OPTIMIZE_896_1 */
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx-1.7.3a-20010304"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -107,7 +101,6 @@
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
-#include <linux/config.h>
 #ifdef MODULE
 #include <linux/module.h>
 #endif
@@ -126,7 +119,6 @@
 #include <linux/errno.h>
 #include <linux/pci.h>
 #include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/time.h>
@@ -182,7 +174,8 @@
 **	Donnot compile integrity checking code for Linux-2.3.0 
 **	and above since SCSI data structures are not ready yet.
 */
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0)
+/* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */
+#if 0
 #define	SCSI_NCR_INTEGRITY_CHECKING
 #endif
 
@@ -290,33 +283,6 @@
 
 /*==========================================================
 **
-**	On x86 architecture, write buffers management does 
-**	not reorder writes to memory. So, using compiler 
-**	optimization barriers is enough to guarantee some 
-**	ordering when the CPU is writing data accessed by 
-**	the NCR.
-**	On Alpha architecture, explicit memory barriers have 
-**	to be used.
-**	Other architectures are defaulted to mb() macro if  
-**	defined, otherwise use compiler barrier.
-**
-**==========================================================
-*/
-
-#if defined(__i386__)
-#define MEMORY_BARRIER()	barrier()
-#elif defined(__alpha__)
-#define MEMORY_BARRIER()	mb()
-#else
-#  ifdef mb
-#  define MEMORY_BARRIER()	mb()
-#  else
-#  define MEMORY_BARRIER()	barrier()
-#  endif
-#endif
-
-/*==========================================================
-**
 **	Configuration and Debugging
 **
 **==========================================================
@@ -437,14 +403,6 @@
 #define	SCR_SG_SIZE	(2)
 
 /*
-**    Io mapped or memory mapped.
-*/
-
-#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
-#define NCR_IOMAPPED
-#endif
-
-/*
 **	other
 */
 
@@ -495,30 +453,42 @@
 #define PciDeviceId(d)		(d)->device
 #define PciIrqLine(d)		(d)->irq
 
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
-
-static int __init 
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+static u_long __init
+pci_get_base_cookie(struct pci_dev *pdev, int index)
 {
-	*base = pdev->resource[index].start;
-	if ((pdev->resource[index].flags & 0x7) == 0x4)
-		++index;
-	return ++index;
-}
+	u_long base;
+
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
+	base = pdev->resource[index].start;
 #else
-static int __init 
+	base = pdev->base_address[index];
+#if BITS_PER_LONG > 32
+	if ((base & 0x7) == 0x4)
+		*base |= (((u_long)pdev->base_address[++index]) << 32);
+#endif
+#endif
+	return (base & ~0x7ul);
+}
+
+static int __init
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
 {
-	*base = pdev->base_address[index++];
-	if ((*base & 0x7) == 0x4) {
+	u32 tmp;
+#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
+
+	pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
+	*base = tmp;
+	++index;
+	if ((tmp & 0x7) == 0x4) {
 #if BITS_PER_LONG > 32
-		*base |= (((u_long)pdev->base_address[index]) << 32);
+		pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
+		*base |= (((u_long)tmp) << 32);
 #endif
 		++index;
 	}
 	return index;
+#undef PCI_BAR_OFFSET
 }
-#endif
 
 #else	/* Incomplete emulation of current PCI code for pre-2.2 kernels */
 
@@ -598,9 +568,23 @@
 	}
 	return offset;
 }
+static u_long __init
+pci_get_base_cookie(struct pci_dev *pdev, int offset)
+{
+	u_long base;
+
+	(void) pci_get_base_address(dev, offset, &base);
+
+	return base;
+}
 
 #endif	/* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
 
+/* Does not make sense in earlier kernels */
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
+#define pci_enable_device(pdev)		(0)
+#endif
+
 /*==========================================================
 **
 **	Debugging tags
@@ -694,16 +678,10 @@
 
 #ifdef __sparc__
 #  include <asm/irq.h>
-#  define pcivtobus(p)			bus_dvma_to_mem(p)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #elif defined(__alpha__)
-#  define pcivtobus(p)			((p) & 0xfffffffful)
-#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
-#elif defined(CONFIG_PPC)
-#  define pcivtobus(p)			phys_to_bus(p)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #else	/* others */
-#  define pcivtobus(p)			(p)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #endif
 
@@ -1383,6 +1361,8 @@
 	u_long	base;
 	u_long	base_2;
 	u_long	io_port;
+	u_long	base_c;
+	u_long	base_2_c;
 	int	irq;
 /* port and reg fields to use INB, OUTB macros */
 	u_long	base_io;
@@ -1439,175 +1419,6 @@
 
 /*==========================================================
 **
-**	Big/Little endian support.
-**
-**==========================================================
-*/
-
-/*
-**	If the NCR uses big endian addressing mode over the 
-**	PCI, actual io register addresses for byte and word 
-**	accesses must be changed according to lane routing.
-**	Btw, ncr_offb() and ncr_offw() macros only apply to 
-**	constants and so donnot generate bloated code.
-*/
-
-#if	defined(SCSI_NCR_BIG_ENDIAN)
-
-#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
-#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
-
-#else
-
-#define ncr_offb(o)	(o)
-#define ncr_offw(o)	(o)
-
-#endif
-
-/*
-**	If the CPU and the NCR use same endian-ness adressing,
-**	no byte reordering is needed for script patching.
-**	Macro cpu_to_scr() is to be used for script patching.
-**	Macro scr_to_cpu() is to be used for getting a DWORD 
-**	from the script.
-*/
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_le32(dw)
-#define scr_to_cpu(dw)	le32_to_cpu(dw)
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_be32(dw)
-#define scr_to_cpu(dw)	be32_to_cpu(dw)
-
-#else
-
-#define cpu_to_scr(dw)	(dw)
-#define scr_to_cpu(dw)	(dw)
-
-#endif
-
-/*==========================================================
-**
-**	Access to the controller chip.
-**
-**	If NCR_IOMAPPED is defined, the driver will use 
-**	normal IOs instead of the MEMORY MAPPED IO method  
-**	recommended by PCI specifications.
-**	If all PCI bridges, host brigdes and architectures 
-**	would have been correctly designed for PCI, this 
-**	option would be useless.
-**
-**==========================================================
-*/
-
-/*
-**	If the CPU and the NCR use same endian-ness adressing,
-**	no byte reordering is needed for accessing chip io 
-**	registers. Functions suffixed by '_raw' are assumed 
-**	to access the chip over the PCI without doing byte 
-**	reordering. Functions suffixed by '_l2b' are 
-**	assumed to perform little-endian to big-endian byte 
-**	reordering, those suffixed by '_b2l' blah, blah,
-**	blah, ...
-*/
-
-#if defined(NCR_IOMAPPED)
-
-/*
-**	IO mapped only input / ouput
-*/
-
-#define	INB_OFF(o)		inb (np->base_io + ncr_offb(o))
-#define	OUTB_OFF(o, val)	outb ((val), np->base_io + ncr_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define	INW_OFF(o)		inw_l2b (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_l2b (np->base_io + (o))
-
-#define	OUTW_OFF(o, val)	outw_b2l ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_b2l ((val), np->base_io + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define	INW_OFF(o)		inw_b2l (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_b2l (np->base_io + (o))
-
-#define	OUTW_OFF(o, val)	outw_l2b ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_l2b ((val), np->base_io + (o))
-
-#else
-
-#define	INW_OFF(o)		inw_raw (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_raw (np->base_io + (o))
-
-#define	OUTW_OFF(o, val)	outw_raw ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_raw ((val), np->base_io + (o))
-
-#endif	/* ENDIANs */
-
-#else	/* defined NCR_IOMAPPED */
-
-/*
-**	MEMORY mapped IO input / output
-*/
-
-#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
-#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
-
-#else
-
-#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
-
-#endif
-
-#endif	/* defined NCR_IOMAPPED */
-
-#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
-#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
-#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
-
-#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
-
-/*
-**	Set bit field ON, OFF 
-*/
-
-#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
-#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
-#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
-#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
-#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
-#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
-
-
-/*==========================================================
-**
 **	Command control block states.
 **
 **==========================================================
@@ -1657,7 +1468,9 @@
 #define	SIR_MSG_OUT_DONE	(19)
 #define	SIR_AUTO_SENSE_DONE	(20)
 #define	SIR_DUMMY_INTERRUPT	(21)
-#define	SIR_MAX			(21)
+#define	SIR_DATA_OVERRUN	(22)
+#define	SIR_BAD_PHASE		(23)
+#define	SIR_MAX			(23)
 
 /*==========================================================
 **
@@ -1757,7 +1570,6 @@
 #define UC_SETORDER	13
 #define UC_SETWIDE	14
 #define UC_SETFLAG	15
-#define UC_CLEARPROF	16
 #define UC_SETVERBOSE	17
 #define UC_RESETDEV	18
 #define UC_CLEARDEV	19
@@ -1766,29 +1578,6 @@
 #define	UF_NODISC	(0x02)
 #define	UF_NOSCAN	(0x04)
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-/*
-**	profiling data (per host)
-*/
-
-struct profile {
-	u_long	num_trans;
-	u_long	num_disc;
-	u_long	num_disc0;
-	u_long	num_break;
-	u_long	num_int;
-	u_long	num_fly;
-	u_long	num_kbytes;
-#if 000
-	u_long	num_br1k;
-	u_long	num_br2k;
-	u_long	num_br4k;
-	u_long	num_br8k;
-	u_long	num_brnk;
-#endif
-};
-#endif
-
 /*========================================================================
 **
 **	Declaration of structs:		target control block
@@ -1831,26 +1620,20 @@
 	ccb_p   nego_cp;
 
 	/*----------------------------------------------------------------
-	**	statistical data
-	**----------------------------------------------------------------
-	*/
-	u_long	transfers;
-	u_long	bytes;
-
-	/*----------------------------------------------------------------
 	**	negotiation of wide and synch transfer and device quirks.
 	**	sval, wval and uval are read from SCRIPTS and so have alignment 
 	**	constraints.
 	**----------------------------------------------------------------
 	*/
-/*0*/	u_char	minsync;
+/*0*/	u_char	uval;
 /*1*/	u_char	sval;
-/*2*/	u_short	period;
-/*0*/	u_char	maxoffs;
-/*1*/	u_char	quirks;
-/*2*/	u_char	widedone;
+/*2*/	u_char	filler2;
 /*3*/	u_char	wval;
-/*0*/	u_char	uval;
+	u_short	period;
+	u_char	minsync;
+	u_char	maxoffs;
+	u_char	quirks;
+	u_char	widedone;
 
 #ifdef	SCSI_NCR_INTEGRITY_CHECKING
 	u_char ic_min_sync;
@@ -2016,7 +1799,6 @@
 	**	Status fields.
 	**----------------------------------------------------------------
 	*/
-	u_char		scr_st[4];	/* script status		*/
 	u_char		status[4];	/* host status			*/
 };
 
@@ -2035,18 +1817,10 @@
 /*
 **	The status bytes are used by the host and the script processor.
 **
-**	The last four bytes (status[4]) are copied to the scratchb register
+**	The four bytes (status[4]) are copied to the scratchb register
 **	(declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
 **	and copied back just after disconnecting.
 **	Inside the script the XX_REG are used.
-**
-**	The first four bytes (scr_st[4]) are used inside the script by 
-**	"LOAD/STORE" commands.
-**	Because source and destination must have the same alignment
-**	in a DWORD, the fields HAVE to be at the choosen offsets.
-**		xerr_st		0	(0x34)	scratcha
-**		sync_st		1	(0x05)	sxfer
-**		wide_st		3	(0x03)	scntl3
 */
 
 /*
@@ -2089,20 +1863,6 @@
 */
 #define HF_DATA_ST	(1u<<7)
 
-/*
-**	First four bytes (script)
-*/
-#define  xerr_st       header.scr_st[0]
-#define  sync_st       header.scr_st[1]
-#define  nego_st       header.scr_st[2]
-#define  wide_st       header.scr_st[3]
-
-/*
-**	First four bytes (host)
-*/
-#define  xerr_status   phys.xerr_st
-#define  nego_status   phys.nego_st
-
 /*==========================================================
 **
 **      Declaration of structs:     Data structure block
@@ -2147,19 +1907,6 @@
 
 	struct pm_ctx pm0;
 	struct pm_ctx pm1;
-
-	/*
-	**	Extra bytes count transferred 
-	**	in case of data overrun.
-	*/
-	u_int32	extra_bytes;
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	Disconnection counter
-	*/
-	u_int32 num_disc;
-#endif
 };
 
 
@@ -2199,8 +1946,16 @@
 	**	a SDTR or WDTR message is appended.
 	**----------------------------------------------------------------
 	*/
-	u_char		scsi_smsg [8];
-	u_char		scsi_smsg2[8];
+	u_char		scsi_smsg [12];
+	u_char		scsi_smsg2[12];
+
+	/*----------------------------------------------------------------
+	**	Miscellaneous status'.
+	**----------------------------------------------------------------
+	*/
+	u_char		nego_status;	/* Negotiation status		*/
+	u_char		xerr_status;	/* Extended error flags		*/
+	u_int32		extra_bytes;	/* Extraneous bytes transferred	*/
 
 	/*----------------------------------------------------------------
 	**	Saved info for auto-sense
@@ -2365,6 +2120,7 @@
 	u_char		minsync;	/* Minimum sync period factor	*/
 	u_char		maxsync;	/* Maximum sync period factor	*/
 	u_char		maxoffs;	/* Max scsi offset		*/
+	u_char		maxoffs_st;	/* Max scsi offset in ST mode	*/
 	u_char		multiplier;	/* Clock multiplier (1,2,4)	*/
 	u_char		clock_divn;	/* Number of clock divisors	*/
 	u_long		clock_khz;	/* SCSI clock frequency in KHz	*/
@@ -2414,9 +2170,6 @@
 	*/
 	struct ncr_reg	regdump;	/* Register dump		*/
 	u_long		regtime;	/* Time it has been done	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	struct profile	profile;	/* Profiling data		*/
-#endif
 
 	/*----------------------------------------------------------------
 	**	Miscellaneous buffers accessed by the scripts-processor.
@@ -2496,7 +2249,7 @@
 	**----------------------------------------------------------------
 	*/
 	struct usrcmd	user;		/* Command from user		*/
-	u_char		release_stage;	/* Synchronisation stage on release  */
+	volatile u_char	release_stage;	/* Synchronisation stage on release  */
 
 	/*----------------------------------------------------------------
 	**	Fields that are used (primarily) for integrity check
@@ -2553,7 +2306,7 @@
 	ncrcmd	select2		[  2];
 #endif
 	ncrcmd  command		[  2];
-	ncrcmd  dispatch	[ 30];
+	ncrcmd  dispatch	[ 28];
 	ncrcmd  sel_no_cmd	[ 10];
 	ncrcmd  init		[  6];
 	ncrcmd  clrack		[  4];
@@ -2561,11 +2314,7 @@
 	ncrcmd  datai_done	[ 26];
 	ncrcmd  datao_done	[ 12];
 	ncrcmd  ign_i_w_r_msg	[  4];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  datai_phase	[  4];
-#else
 	ncrcmd  datai_phase	[  2];
-#endif
 	ncrcmd  datao_phase	[  4];
 	ncrcmd  msg_in		[  2];
 	ncrcmd  msg_in2		[ 10];
@@ -2588,11 +2337,7 @@
 	ncrcmd	done_end	[  2];
 	ncrcmd  save_dp		[  8];
 	ncrcmd  restore_dp	[  4];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  disconnect	[ 32];
-#else
 	ncrcmd  disconnect	[ 20];
-#endif
 #ifdef SCSI_NCR_IARB_SUPPORT
 	ncrcmd  idle		[  4];
 #else
@@ -2657,8 +2402,9 @@
 	ncrcmd	nego_bad_phase	[  4];
 	ncrcmd	msg_out		[  4];
 	ncrcmd	msg_out_done	[  4];
-	ncrcmd	data_ovrun	[ 18];
-	ncrcmd	data_ovrun1	[ 20];
+	ncrcmd	data_ovrun	[  2];
+	ncrcmd	data_ovrun1	[ 22];
+	ncrcmd	data_ovrun2	[  8];
 	ncrcmd	abort_resel	[ 16];
 	ncrcmd	resend_ident	[  4];
 	ncrcmd	ident_break	[  4];
@@ -2745,9 +2491,6 @@
 #ifdef	SCSI_NCR_INTEGRITY_CHECKING
 static	int	ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
 #endif
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-static	void	ncb_profile	(ncb_p np, ccb_p cp);
-#endif
 static	void	ncr_script_copy_and_bind
 				(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
 static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
@@ -3039,31 +2782,25 @@
 	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
 		PADDRH (msg_out),
 	/*
-	 *  Set the extended error flag.
+	 *  Discard as many illegal phases as 
+	 *  required and tell the C code about.
 	 */
-	SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR),
-		0,
-
-	/*
-	**      Discard one illegal phase byte, if required.
-	*/
-	SCR_LOAD_REL (scratcha, 1),
-		offsetof (struct ccb, xerr_status),
-	SCR_REG_REG (scratcha, SCR_OR, XE_BAD_PHASE),
-		0,
-	SCR_STORE_REL (scratcha, 1),
-		offsetof (struct ccb, xerr_status),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
-		8,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
+		16,
 	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
 		NADDR (scratch),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
-		8,
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
+		-16,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
+		16,
 	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
 		NADDR (scratch),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
+		-16,
+	SCR_INT,
+		SIR_BAD_PHASE,
 	SCR_JUMP,
 		PADDR (dispatch),
-
 }/*---------------------< SEL_NO_CMD >----------------------*/,{
 	/*
 	**	The target does not switch to command 
@@ -3230,10 +2967,6 @@
 		PADDR (clrack),
 
 }/*-------------------------< DATAI_PHASE >------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	SCR_REG_REG (QU_REG, SCR_OR, HF_DATA_ST),
-		0,
-#endif
 	SCR_RETURN,
 		0,
 }/*-------------------------< DATAO_PHASE >------------------*/,{
@@ -3478,25 +3211,6 @@
 	*/
 	SCR_WAIT_DISC,
 		0,
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	Count the disconnects.
-	**	Disconnect without DATA PHASE having been 
-	**	entered are counted in bits 8..15.
-	*/
-	SCR_LOAD_REL (scratcha, 4),
-		offsetof (struct ccb, phys.num_disc),
-	SCR_FROM_REG (QU_REG),
-		0,
-	SCR_JUMPR ^ IFTRUE (MASK (HF_DATA_ST, HF_DATA_ST)),
-		8,
-	SCR_REG_REG (scratcha1, SCR_ADD, 0x01),
-		0,
-	SCR_REG_REG (scratcha, SCR_ADD, 0x01),
-		0,
-	SCR_STORE_REL (scratcha, 4),
-		offsetof (struct ccb, phys.num_disc),
-#endif
 	/*
 	**	Status is: DISCONNECTED.
 	*/
@@ -4226,7 +3940,13 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATA_OVRUN >--------------------*/,{
+}/*-------------------------< DATA_OVRUN >-----------------------*/,{
+	/*
+	 *  Use scratcha to count the extra bytes.
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDRH (zero),
+}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
 	/*
 	 *  The target may want to transfer too much data.
 	 *
@@ -4237,7 +3957,7 @@
 	SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
 		NADDR (scratch),
 	SCR_JUMP,
-		PADDRH (data_ovrun1),
+		PADDRH (data_ovrun2),
 	/*
 	 *  If WSR is set, clear this condition, and 
 	 *  count this byte.
@@ -4249,48 +3969,38 @@
 	SCR_REG_REG (scntl2, SCR_OR, WSR),
 		0,
 	SCR_JUMP,
-		PADDRH (data_ovrun1),
+		PADDRH (data_ovrun2),
 	/*
 	 *  Finally check against DATA IN phase.
-	 *  Jump to dispatcher if not so.
+	 *  Signal data overrun to the C code 
+	 *  and jump to dispatcher if not so.
 	 *  Read 1 byte otherwise and count it.
 	 */
-	SCR_JUMP ^ IFFALSE (IF (SCR_DATA_IN)),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		16,
+	SCR_INT,
+		SIR_DATA_OVERRUN,
+	SCR_JUMP,
 		PADDR (dispatch),
 	SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
 		NADDR (scratch),
-}/*-------------------------< DATA_OVRUN1 >--------------------*/,{
-	/*
-	 *  Set the extended error flag.
-	 */
-	SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR),
-		0,
-	SCR_LOAD_REL (scratcha, 1),
-		offsetof (struct ccb, xerr_status),
-	SCR_REG_REG (scratcha,  SCR_OR,  XE_EXTRA_DATA),
-		0,
-	SCR_STORE_REL (scratcha, 1),
-		offsetof (struct ccb, xerr_status),
+}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
 	/*
 	 *  Count this byte.
 	 *  This will allow to return a negative 
 	 *  residual to user.
 	 */
-	SCR_LOAD_REL (scratcha, 4),
-		offsetof (struct ccb, phys.extra_bytes),
 	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
 		0,
 	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
 		0,
 	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
 		0,
-	SCR_STORE_REL (scratcha, 4),
-		offsetof (struct ccb, phys.extra_bytes),
 	/*
 	 *  .. and repeat as required.
 	 */
 	SCR_JUMP,
-		PADDRH (data_ovrun),
+		PADDRH (data_ovrun1),
 
 }/*-------------------------< ABORT_RESEL >----------------*/,{
 	SCR_SET (SCR_ATN),
@@ -4962,7 +4672,7 @@
 
 			switch (old & RELOC_MASK) {
 			case RELOC_REGISTER:
-				new = (old & ~RELOC_MASK) + pcivtobus(np->base_ba);
+				new = (old & ~RELOC_MASK) + np->base_ba;
 				break;
 			case RELOC_LABEL:
 				new = (old & ~RELOC_MASK) + np->p_script;
@@ -5207,11 +4917,19 @@
 
 	np->maxwide	= (np->features & FE_WIDE)? 1 : 0;
 
-	/*
-	**	Get the frequency of the chip's clock.
-	**	Find the right value for scntl3.
-	*/
+ 	/*
+	 *  Guess the frequency of the chip's clock.
+	 */
+	if	(np->features & (FE_ULTRA3 | FE_ULTRA2))
+		np->clock_khz = 160000;
+	else if	(np->features & FE_ULTRA)
+		np->clock_khz = 80000;
+	else
+		np->clock_khz = 40000;
 
+	/*
+	 *  Get the clock multiplier factor.
+ 	 */
 	if	(np->features & FE_QUAD)
 		np->multiplier	= 4;
 	else if	(np->features & FE_DBLR)
@@ -5219,10 +4937,11 @@
 	else
 		np->multiplier	= 1;
 
-	np->clock_khz	= (np->features & FE_CLK80)? 80000 : 40000;
-	np->clock_khz	*= np->multiplier;
-
-	if (np->clock_khz != 40000)
+	/*
+	 *  Measure SCSI clock frequency for chips 
+	 *  it may vary from assumed one.
+	 */
+	if (np->features & FE_VARCLK)
 		ncr_getclock(np, np->multiplier);
 
 	/*
@@ -5271,10 +4990,17 @@
 	/*
 	 * Fix up. If sync. factor is 10 (160000Khz clock) and chip
 	 * supports ultra3, then min. sync. period 12.5ns and the factor is 9 
+	 * Also keep track of the maximum offset in ST mode which may differ  
+	 * from the maximum offset in DT mode. For now hardcoded to 31. 
 	 */
 
-	if ((np->minsync == 10) && (np->features & FE_ULTRA3))
-		np->minsync = 9;
+	if (np->features & FE_ULTRA3) {
+		if (np->minsync == 10)
+			np->minsync = 9;
+		np->maxoffs_st = 31;
+	}
+	else
+		np->maxoffs_st = np->maxoffs;
 
 	/*
 	 * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
@@ -5302,7 +5028,7 @@
 	/*
 	**	64 bit (53C895A or 53C896) ?
 	*/
-	if (np->features & FE_64BIT)
+	if (np->features & FE_DAC)
 #ifdef SCSI_NCR_USE_64BIT_DAC
 		np->rv_ccntl1	|= (XTIMOD | EXTIBMV);
 #else
@@ -5373,7 +5099,7 @@
 		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
 	if (np->features & FE_ERMP)
 		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
-#ifdef SCSI_NCR_OPTIMIZE_896
+#if 1
 	if ((np->features & FE_PFEN) && !np->base2_ba)
 #else
 	if (np->features & FE_PFEN)
@@ -5785,8 +5511,8 @@
 	np->base_ws	= (np->features & FE_IO256)? 256 : 128;
 	np->base2_ba	= (np->features & FE_RAM)? device->slot.base_2 : 0;
 
-#ifndef NCR_IOMAPPED
-	np->base_va = remap_pci_mem(np->base_ba, np->base_ws);
+#ifndef SCSI_NCR_IOMAPPED
+	np->base_va = remap_pci_mem(device->slot.base_c, np->base_ws);
 	if (!np->base_va) {
 		printk(KERN_ERR "%s: can't map PCI MMIO region\n",ncr_name(np));
 		goto attach_error;
@@ -5802,7 +5528,7 @@
 
 	np->reg = (struct ncr_reg *) np->base_va;
 
-#endif /* !defined NCR_IOMAPPED */
+#endif /* !defined SCSI_NCR_IOMAPPED */
 
 	/*
 	**	If on-chip RAM is used, make sure SCRIPTS isn't too large.
@@ -5917,7 +5643,7 @@
 	np->p_scripth0	= np->p_scripth;
 
 	if (np->base2_ba) {
-		np->p_script	= pcivtobus(np->base2_ba);
+		np->p_script	= np->base2_ba;
 		if (np->features & FE_RAM8K) {
 			np->base2_ws = 8192;
 			np->p_scripth = np->p_script + 4096;
@@ -5928,7 +5654,8 @@
 		else
 			np->base2_ws = 4096;
 #ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
-		np->base2_va = remap_pci_mem(np->base2_ba, np->base2_ws);
+		np->base2_va = 
+			remap_pci_mem(device->slot.base_2_c, np->base2_ws);
 		if (!np->base2_va) {
 			printk(KERN_ERR "%s: can't map PCI MEMORY region\n",
 			       ncr_name(np));
@@ -6021,8 +5748,10 @@
 	/*
 	**	Patch the script to provide an extra clock cycle on
 	**	data out phase - 53C1010_66MHz part only.
+	**	(Fixed in rev. 1 of the chip)
 	*/
-	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66){
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 &&
+	    np->revision_id < 1){
 		np->script0->datao_phase[0] =
 				cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c));
 	}
@@ -6050,18 +5779,12 @@
 	if (np->device_id == PCI_DEVICE_ID_NCR_53C896 &&
 	    np->revision_id <= 0x1 && (np->features & FE_NOPM)) {
 		np->scatter = ncr_scatter_896R1;
-#ifndef SCSI_NCR_PROFILE_SUPPORT
-#define XXX	0
-#else
-#define XXX	2
-#endif
-		np->script0->datai_phase[XXX] = cpu_to_scr(SCR_JUMP);
-		np->script0->datai_phase[XXX+1] = 
+		np->script0->datai_phase[0] = cpu_to_scr(SCR_JUMP);
+		np->script0->datai_phase[1] = 
 				cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj));
 		np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP);
 		np->script0->datao_phase[1] = 
 				cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj));
-#undef XXX
 	}
 	else
 #ifdef DEBUG_896R1
@@ -6168,7 +5891,7 @@
 	instance->this_id	= np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= MAX_LUN;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29)
 	instance->base		= (unsigned long) np->reg;
 #else
@@ -6524,11 +6247,10 @@
 					new_period = 0x0A;
 					cmd->ic_nego_width = 1;
 					new_width = 1;
-					new_offset &= 0x1f;
 				}
 			}
-			else if (new_period > 0x09)
-				new_offset &= 0x1f;
+			if (!options_byte && new_offset > np->maxoffs_st)
+				new_offset = np->maxoffs_st;
 
 			nego = NS_PPR;
 			
@@ -6575,12 +6297,14 @@
 					tp->ic_min_sync = 0x0A;
 					new_period = 0x0A;
 				}
+				if (new_offset > np->maxoffs_st)
+					new_offset = np->maxoffs_st;
 				nego = NS_SYNC;
 				msgptr[msglen++] = M_EXTENDED;
 				msgptr[msglen++] = 3;
 				msgptr[msglen++] = M_X_SYNC_REQ;
 				msgptr[msglen++] = new_period;
-				msgptr[msglen++] = new_offset & 0x1f;
+				msgptr[msglen++] = new_offset;
 			    }
 			    else 
 				cmd->ic_nego_sync = 0;
@@ -6729,13 +6453,12 @@
 		if ( (factor==9) && offset) {
 			if (!width) {
 				factor = 0x0A;
-				offset &= 0x1f;
 			}
 			else 
 				last_byte = 0x02;
 		}
-		else if (factor > 0x09)
-			offset &= 0x1f;
+		if (!last_byte && offset > np->maxoffs_st)
+			offset = np->maxoffs_st;
 
 		msgptr[msglen++] = M_EXTENDED;
 		msgptr[msglen++] = 6;
@@ -6754,12 +6477,14 @@
 			factor = 0x0A;
 			tp->minsync = 0x0A;
 		}
+		if (offset > np->maxoffs_st)
+			offset = np->maxoffs_st;
 
 		msgptr[msglen++] = M_EXTENDED;
 		msgptr[msglen++] = 3;
 		msgptr[msglen++] = M_X_SYNC_REQ;
 		msgptr[msglen++] = factor;
-		msgptr[msglen++] = offset & 0x1f;
+		msgptr[msglen++] = offset;
 		break;
 	case NS_WIDE:
 		msgptr[msglen++] = M_EXTENDED;
@@ -6826,7 +6551,8 @@
 	**
 	**---------------------------------------------
 	*/
-	if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) {
+	if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && 
+	    (tp->usrflag & UF_NOSCAN)) {
 		tp->usrflag &= ~UF_NOSCAN;
 		return DID_BAD_TARGET;
 	}
@@ -6871,10 +6597,6 @@
 	}
 #endif
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	cp->phys.num_disc = 0;
-#endif
-
 	/*----------------------------------------------------
 	**
 	**	Build the identify / tag / sdtr message
@@ -7131,7 +6853,7 @@
 	cp->host_status		= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
 	cp->scsi_status		= S_ILLEGAL;
 	cp->xerr_status		= 0;
-	cp->phys.extra_bytes	= 0;
+	cp->extra_bytes		= 0;
 
 	/*
 	**	extreme data pointer.
@@ -7575,11 +7297,8 @@
 		return;
 
 	/*
-	**	Gather profiling data
+	**	Print some debugging info.
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncb_profile (np, cp);
-#endif
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
 		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
@@ -7622,7 +7341,8 @@
 	}
 	else {
 		cp->resid = 0;
-		if (cp->phys.header.lastp != cp->phys.header.goalp)
+		if (cp->xerr_status ||
+		    cp->phys.header.lastp != cp->phys.header.goalp)
 			cp->resid = ncr_compute_residual(np, cp);
 	}
 
@@ -7666,10 +7386,16 @@
 			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x "
 				"data_len=%d residual=%d\n",
 				cmd->cmnd[0], cp->host_status, cp->scsi_status,
-				cp->data_len, -cp->resid);
+				cp->data_len, cp->resid);
 		}
 	}
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,99)
+	/*
+	**	Move residual byte count to user structure.
+	*/
+	cmd->resid = cp->resid;
+#endif
 	/*
 	**	Check the status.
 	*/
@@ -7701,9 +7427,6 @@
 				       (char *) cmd->request_buffer);
 		}
 
-		tp->bytes     += cp->data_len;
-		tp->transfers ++;
-
 		/*
 		**	If tags was reduced due to queue full,
 		**	increase tags if 1000 good status received.
@@ -7844,6 +7567,10 @@
 /*
 **	The NCR has completed CCBs.
 **	Look at the DONE QUEUE.
+**
+**	On architectures that may reorder LOAD/STORE operations, 
+**	a memory barrier may be needed after the reading of the 
+**	so-called `flag' and prior to dealing with the data.
 */
 int ncr_wakeup_done (ncb_p np)
 {
@@ -7863,6 +7590,7 @@
 
 		cp = ncr_ccb_from_dsa(np, dsa);
 		if (cp) {
+			MEMORY_BARRIER();
 			ncr_complete (np, cp);
 			++n;
 		}
@@ -8014,12 +7742,11 @@
 		OUTB(nc_aipcntl1, (1<<3));
 
 	/*
-	**	If 64 bit (895A/896/1010/1010_66) write the CCNTL1 register to 
-	**	enable 40 bit address table indirect addressing for MOVE.
-	**	Also write CCNTL0 if 64 bit chip, since this register seems 
-	**	to only be used by 64 bit cores.
+	**  Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing 
+	**  and/or hardware phase mismatch, since only such chips 
+	**  seem to support those IO registers.
 	*/
-	if (np->features & FE_64BIT) {
+	if (np->features & (FE_DAC | FE_NOPM)) {
 		OUTB (nc_ccntl0, np->rv_ccntl0);
 		OUTB (nc_ccntl1, np->rv_ccntl1);
 	}
@@ -8102,7 +7829,6 @@
 	**    For platforms that may not support PCI memory mapping,
 	**    we use a simple SCRIPTS that performs MEMORY MOVEs.
 	*/
-	MEMORY_BARRIER();
 	if (np->base2_ba) {
 		if (bootverbose)
 			printk ("%s: Downloading SCSI SCRIPTS.\n",
@@ -8132,7 +7858,7 @@
 	np->istat_sem = 0;
 
 	OUTL (nc_dsa, np->p_ncb);
-	OUTL (nc_dsp, phys);
+	OUTL_DSP (phys);
 }
 
 /*==========================================================
@@ -8474,9 +8200,10 @@
 		else if	(tp->period < 2000)	scsi = "FAST-10";
 		else				scsi = "FAST-5";
 
-		printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+		printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi,
 			tp->widedone > 1 ? "WIDE " : "",
-			mb10 / 10, mb10 % 10, tp->period / 10, offset);
+			mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10,
+			offset);
 	} else
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
 next:
@@ -8645,9 +8372,10 @@
 		else if	(tp->period < 2000)	scsi = "FAST-10";
 		else				scsi = "FAST-5";
 
-		printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+		printk ("%s %sSCSI %d.%d MB/s (%d.%d ns, offset %d)\n", scsi,
 			tp->widedone > 1 ? "WIDE " : "",
-			mb10 / 10, mb10 % 10, tp->period / 10, offset);
+			mb10 / 10, mb10 % 10, tp->period / 10, tp->period % 10,
+			offset);
 	} else
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
 next:
@@ -8786,11 +8514,6 @@
 		np->verbose = np->user.data;
 		break;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	case UC_CLEARPROF:
-		bzero(&np->profile, sizeof(np->profile));
-		break;
-#endif
 	default:
 		/*
 		**	We assume that other commands apply to targets.
@@ -9093,70 +8816,24 @@
 	u_short	sist;
 	int	i;
 
-#ifdef SCSI_NCR_OPTIMIZE_896_1
-	/*
-	**	This optimization when used with a 896 that handles 
-	**	phase mismatch from the SCRIPTS allows to only do 
-	**	PCI memory writes transactions from the CPU and so to 
-	**	take advantage of PCI posted writes.
-	**	Who wants his 500 MHz CPU to wait several micro-seconds 
-	**	for the PCI BUS to be granted when this can be avoided?
-	**	I don't, even for my slow 233 MHz PII. :-)
-	**
-	**	We assume we have been called for command completion.
-	**	If no completion found, go with normal handling.
-	**	Ordering is ensured by the SCRIPTS performing a read 
-	**	from main memory prior to raising INTFLY.
-	**	We have to raise SIGP since the chip may be currently 
-	**	going to a wait reselect instruction. IMO, SIGP should 
-	**	not be clearable in ISTAT since it can be polled and 
-	**	cleared by reading CTEST2. This tiny chip misdesign is a 
-	**	penalty here.
-	**
-	**	The MA interrupt and interrupt sharing may also have 
-	**	adverse effects on this optimization, so we only want 
-	**	to use it if it is enabled by user.
-	**	(BTW, this optimization seems to even have some goodness 
-	**	with my 895 that unfortunately suffers of the MA int.).
-	*/
-	if (driver_setup.optimize & 1) {
-		OUTB(nc_istat, (INTF | SIGP | np->istat_sem));
-		if (ncr_wakeup_done (np)) {
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-			++np->profile.num_fly;
-#endif
-			return;
-		}
-	}
-#endif /* SCSI_NCR_OPTIMIZE_896_1 */
-
 	/*
 	**	interrupt on the fly ?
 	**
-	**	For bridges that donnot flush posted writes 
-	**	in the reverse direction on read, a dummy read 
-	**	may help not to miss completions.
+	**	A `dummy read' is needed to ensure that the 
+	**	clear of the INTF flag reaches the device 
+	**	before the scanning of the DONE queue.
 	*/
 	istat = INB (nc_istat);
 	if (istat & INTF) {
 		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
-#ifdef SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
 		istat = INB (nc_istat);		/* DUMMY READ */
-#endif
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
 		(void)ncr_wakeup_done (np);
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-		++np->profile.num_fly;
-#endif
 	};
 
 	if (!(istat & (SIP|DIP)))
 		return;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	++np->profile.num_int;
-#endif
-
 #if 0	/* We should never get this one */
 	if (istat & CABRT)
 		OUTB (nc_istat, CABRT);
@@ -9197,6 +8874,12 @@
 			(unsigned)INL(nc_dsp),
 			(unsigned)INL(nc_dbc));
 
+	/*
+	**	On paper, a memory barrier may be needed here.
+	**	And since we are paranoid ... :)
+	*/
+	MEMORY_BARRIER();
+
 	/*========================================================
 	**	First, interrupts we want to service cleanly.
 	**
@@ -9217,7 +8900,7 @@
 		if	(sist & PAR)	ncr_int_par (np, sist);
 		else if (sist & MA)	ncr_int_ma (np);
 		else if (dstat & SIR)	ncr_int_sir (np);
-		else if (dstat & SSI)	OUTONB (nc_dcntl, (STD|NOCOM));
+		else if (dstat & SSI)	OUTONB_STD ();
 		else			goto unknown_int;
 		return;
 	};
@@ -9367,7 +9050,7 @@
 		OUTL (nc_dsa, DSA_INVALID);
 		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
 		OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 	}
 	else
 		goto reset_all;
@@ -9419,7 +9102,6 @@
 {
 	u_int32 dsa = INL (nc_dsa);
 	ccb_p   cp  = ncr_ccb_from_dsa(np, dsa);
-	tcb_p   tp  = &np->target[cp->target];
 
 	/*
 	 * Fix Up. Some disks respond to a PPR negotation with
@@ -9427,9 +9109,11 @@
 	 * Disable ppr negotiation if this is first time
 	 * tried ppr negotiation.
 	 */
-	
-	if (tp->ppr_negotiation == 1)
-		tp->ppr_negotiation = 0;
+	if (cp) {
+		tcb_p tp = &np->target[cp->target];
+		if (tp->ppr_negotiation == 1)
+			tp->ppr_negotiation = 0;
+	}
 	
 	printk ("%s: unexpected disconnect\n", ncr_name(np));
 	ncr_recover_scsi_int(np, HS_UNEXPECTED);
@@ -9568,18 +9252,18 @@
 	if ((phase == 1) || (phase == 5)) {
 		/* Phase mismatch handled by SCRIPTS */
 		if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle))
-			OUTL (nc_dsp, dsp);
+			OUTL_DSP (dsp);
 		/* Phase mismatch handled by the C code */
 		else if (sist & MA)
 			ncr_int_ma (np);
 		/* No phase mismatch occurred */
 		else {
 			OUTL (nc_temp, dsp);
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+			OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch));
 		}
 	}
 	else 
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 	return;
 
 reset_all:
@@ -9618,10 +9302,6 @@
 	struct pm_ctx *pm;
 	ccb_p	cp;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	++np->profile.num_break;
-#endif
-
 	dsp	= INL (nc_dsp);
 	dbc	= INL (nc_dbc);
 	dsa	= INL (nc_dsa);
@@ -9646,7 +9326,7 @@
 	**	raising the MA interrupt for interrupted INPUT phases.
 	**	For DATA IN phase, we will check for the SWIDE later.
 	*/
-	if ( !(((cmd & 7) == 1) || ((cmd & 7) == 5) ) ) {
+	if ((cmd & 7) != 1 && (cmd & 7) != 5) {
 		u_int32 dfifo;
 		u_char ss0, ss2;
 
@@ -9772,9 +9452,11 @@
 
 	/*
 	**	check cmd against assumed interrupted script command.
+	**	If dt data phase, the MOVE instruction hasn't bit 4 of 
+	**	the phase.
 	*/
 
-	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
+	if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) {
 		PRINT_ADDR(cp->cmd);
 		printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
 			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
@@ -9896,7 +9578,7 @@
 	*/
 
 	OUTL (nc_temp, newcmd);
-	OUTL (nc_dsp,  nxtdsp);
+	OUTL_DSP (nxtdsp);
 	return;
 
 	/*
@@ -9969,7 +9651,7 @@
 	}
 
 	if (nxtdsp) {
-		OUTL (nc_dsp, nxtdsp);
+		OUTL_DSP (nxtdsp);
 		return;
 	}
 
@@ -10079,8 +9761,7 @@
 	/*
 	**	Now we can restart the SCRIPTS processor safely.
 	*/
-	MEMORY_BARRIER();
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 
 	switch(s_status) {
 	default:
@@ -10114,7 +9795,7 @@
 		cp->host_status 	= HS_BUSY;
 		cp->scsi_status 	= S_ILLEGAL;
 		cp->xerr_status		= 0;
-		cp->phys.extra_bytes	= 0;
+		cp->extra_bytes		= 0;
 		cp->host_flags		&= (HF_PM_TO_C|HF_DATA_IN);
 
 		break;
@@ -10416,7 +10097,7 @@
 			np->abrt_sel.sel_sxfer  = tp->sval;
 			np->abrt_sel.sel_scntl4 = tp->uval;
 			OUTL(nc_dsa, np->p_ncb);
-			OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
+			OUTL_DSP (NCB_SCRIPTH_PHYS (np, sel_for_abort));
 			return;
 		}
 
@@ -10503,7 +10184,7 @@
 		target = (INB (nc_sdid) & 0xf);
 		tp = &np->target[target];
 
-		np->abrt_tbl.addr = vtobus(np->abrt_msg);
+		np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg));
 
 		/*
 		**	If the target is to be reset, prepare a 
@@ -10685,7 +10366,7 @@
 	/*
 	**	Let the SCRIPTS processor continue.
 	*/
-	OUTONB (nc_dcntl, (STD|NOCOM));
+	OUTONB_STD ();
 }
 
 
@@ -10911,11 +10592,11 @@
 
 out_ok:
 	OUTL (nc_temp, dp_scr);
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 	return;
 
 out_reject:
-	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 }
 
 
@@ -10954,7 +10635,7 @@
 	 */
 	if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) {
 		if (cp->xerr_status & XE_EXTRA_DATA)
-			resid -= scr_to_cpu(cp->phys.extra_bytes);
+			resid -= cp->extra_bytes;
 		if (cp->xerr_status & XE_SODL_UNRUN)
 			++resid;
 		if (cp->xerr_status & XE_SWIDE_OVRUN)
@@ -10963,11 +10644,11 @@
 
 
 	/*
-	**	If all data has been transferred,
-	**	there is no residual.
+	**	If SCRIPTS reaches its goal point, then 
+	**	there is no additionnal residual.
 	*/
 	if (cp->phys.header.lastp == cp->phys.header.goalp)
-		return 0;
+		return resid;
 
 	/*
 	**	If the last data pointer is data_io (direction 
@@ -10975,35 +10656,27 @@
 	**	taken place.
 	*/
 	if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io))
-		return -cp->data_len;
-
-	/*
-	**	If the device asked for more data than available, 
-	**	return a positive residual value.
-	*/
-	if (cp->phys.extra_bytes)
-		return scr_to_cpu(cp->phys.extra_bytes);
+		return cp->data_len;
 
 	/*
-	**	Evaluate the pointer saved on message COMPLETE.
-	**	According to our alchemy:), the extreme data 
-	**	pointer will also be updated if needed.
-	**	On error, assume no data transferred (this may 
-	**	happen if the data direction is unknown).
+	**	If no data transfer occurs, or if the data
+	**	pointer is weird, return full residual.
 	*/
-	tmp = cpu_to_scr(cp->phys.header.lastp);
-	if (ncr_evaluate_dp(np, cp, tmp, &dp_ofs) < 0)
-		return -cp->data_len;
+	if (cp->startp == cp->phys.header.lastp ||
+	    ncr_evaluate_dp(np, cp, scr_to_cpu(cp->phys.header.lastp),
+			    &dp_ofs) < 0) {
+		return cp->data_len;
+	}
 
 	/*
 	**	We are now full comfortable in the computation 
 	**	of the data residual (2's complement).
 	*/
 	dp_sgmin = MAX_SCATTER - cp->segments;
-	resid = cp->ext_ofs;
+	resid = -cp->ext_ofs;
 	for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) {
 		tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
-		resid -= (tmp & 0xffffff);
+		resid += (tmp & 0xffffff);
 	}
 
 	/*
@@ -11141,6 +10814,8 @@
 		{chg = 1; per = np->minsync;}
 	if (per < tp->minsync)
 		{chg = 1; per = tp->minsync;}
+	if (ofs > np->maxoffs_st)
+		{chg = 1; ofs = np->maxoffs_st;}
 	if (ofs > tp->maxoffs)
 		{chg = 1; ofs = tp->maxoffs;}
 
@@ -11183,7 +10858,7 @@
 				**	Answer wasn't acceptable.
 				*/
 				ncr_setsync (np, cp, 0, 0xe0, 0);
-				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+				OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 			} else {
 				/*
 				**	Answer is ok.
@@ -11194,7 +10869,7 @@
 				else
 				  ncr_setsync (np, cp, scntl3, ofs, scntl4);
 
-				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+				OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 			};
 			return;
 
@@ -11230,9 +10905,9 @@
 	np->msgin [0] = M_NOOP;
 
 	if (!ofs)
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 	else
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sdtr_resp));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, sdtr_resp));
 }
 
 /*==========================================================
@@ -11296,13 +10971,13 @@
 				**	Answer wasn't acceptable.
 				*/
 				ncr_setwide (np, cp, 0, 1);
-				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+				OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 			} else {
 				/*
 				**	Answer is ok.
 				*/
 				ncr_setwide (np, cp, wide, 1);
-				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+				OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 			};
 			return;
 
@@ -11332,7 +11007,7 @@
 		ncr_print_msg(cp, "wide msgout", np->msgout);
 	}
 
-	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp));
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, wdtr_resp));
 }
 /*==========================================================
 **
@@ -11429,6 +11104,9 @@
 	else if (( (per > 0x09) && dt) ) 
 		chg = 2;
 
+	/* Not acceptable since beyond controller limit */
+	if (!dt && ofs > np->maxoffs_st)
+		{chg = 2; ofs = np->maxoffs_st;}
 
 	if (DEBUG_FLAGS & DEBUG_NEGO) {
 		PRINT_ADDR(cp->cmd);
@@ -11456,7 +11134,7 @@
 					tp->widedone = 0;
 				}
 				ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0);
-				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+				OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 			} else {
 				/*
 				**	Answer is ok.
@@ -11468,7 +11146,7 @@
 				else
 				  ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
 
-				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+				OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				
 			};
 			return;
@@ -11496,12 +11174,12 @@
 	if  ((per == 0x09) && ofs && (!wth || !dt)) {
 		per = 0x0A;
 		dt = 0;
-                ofs &= 0x1f;
 	}
 	else if ( (per > 0x09) && dt) {
 		dt = 0;
-                ofs &= 0x1f;
 	}
+	if (!dt && ofs > np->maxoffs_st)
+		ofs = np->maxoffs_st;
 
 	if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
 			(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
@@ -11527,9 +11205,9 @@
 	np->msgin [0] = M_NOOP;
 
 	if (!ofs)
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 	else
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, ppr_resp));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, ppr_resp));
 }
 
 
@@ -11679,7 +11357,7 @@
 		*/
 		if (tp->l0p) { 
 			OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+			OUTL_DSP (NCB_SCRIPT_PHYS (np, resel_go));
 			return;
 		}
 	/*
@@ -11770,6 +11448,28 @@
                 }
 		goto out;
 	/*
+	**	The device wants us to tranfer more data than 
+	**	expected or in the wrong direction.
+	**	The number of extra bytes is in scratcha.
+	**	It is a data overrun condition.
+	*/
+	case SIR_DATA_OVERRUN:
+		if (cp) {
+			OUTONB (HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_EXTRA_DATA;
+			cp->extra_bytes += INL (nc_scratcha);
+		}
+		goto out;
+	/*
+	**	The device switched to an illegal phase (4/5).
+	*/
+	case SIR_BAD_PHASE:
+		if (cp) {
+			OUTONB (HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_BAD_PHASE;
+		}
+		goto out;
+	/*
 	**	We received a message.
 	*/
 	case SIR_MSG_RECEIVED:
@@ -11835,7 +11535,7 @@
 	*/
 	case SIR_MSG_WEIRD:
 		ncr_print_msg(cp, "WEIRD message received", np->msgin);
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_weird));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_weird));
 		return;
 	/*
 	**	Negotiation failed.
@@ -11854,15 +11554,15 @@
 	};
 
 out:
-	OUTONB (nc_dcntl, (STD|NOCOM));
+	OUTONB_STD ();
 	return;
 out_reject:
-	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
 	return;
 out_clrack:
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 	return;
-out_stuck:;
+out_stuck:
 }
 
 
@@ -12493,7 +12193,7 @@
 **==========================================================
 */
 
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 static int __init ncr_regtest (struct ncb* np)
 {
 	register volatile u_int32 data;
@@ -12522,7 +12222,7 @@
 {
 	u_int32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
 	int	i, err=0;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (np->reg) {
             err |= ncr_regtest (np);
             if (err) return (err);
@@ -12543,7 +12243,7 @@
 	**	Start script (exchange values)
 	*/
 	OUTL (nc_dsa, np->p_ncb);
-	OUTL (nc_dsp, pc);
+	OUTL_DSP (pc);
 	/*
 	**	Wait 'til done (with timeout)
 	*/
@@ -12601,44 +12301,6 @@
 
 /*==========================================================
 **
-**
-**	Profiling the drivers and targets performance.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-
-static	void ncb_profile (ncb_p np, ccb_p cp)
-{
-	int num_disc	= (cp->phys.num_disc & 0xff);
-	int num_disc0	= (cp->phys.num_disc >> 8);
-
-	++np->profile.num_trans;
-	np->profile.num_disc	+= num_disc;
-	np->profile.num_disc0	+= num_disc0;
-	np->profile.num_kbytes	+= (cp->data_len >> 10);
-#if 000
-	if (num_disc > num_disc0) {
-		if (cp->data_len <= 1024)
-			np->profile.num_br1k += (num_disc - num_disc0);
-		else if (cp->data_len <= 2048)
-			np->profile.num_br2k += (num_disc - num_disc0);
-		else if (cp->data_len <= 4096)
-			np->profile.num_br4k += (num_disc - num_disc0);
-		else if (cp->data_len <= 8192)
-			np->profile.num_br8k += (num_disc - num_disc0);
-		else
-			np->profile.num_brnk += (num_disc - num_disc0);
-	}
-#endif
-}
-
-#endif /* SCSI_NCR_PROFILE_SUPPORT */
-
-/*==========================================================
-**
 **	Determine the ncr's clock frequency.
 **	This is essential for the negotiation
 **	of the synchronous transfer rate.
@@ -12745,14 +12407,8 @@
 
   	/*
  	 * adjust for prescaler, and convert into KHz 
-	 * scale values derived empirically. C1010 uses
-	 * different dividers
+	 * scale values derived empirically.
   	 */
-#if 0
-	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010)
-		f = ms ? ((1 << gen) * 2866 ) / ms : 0;
-	else
-#endif
 	f = ms ? ((1 << gen) * 4340) / ms : 0;
 
 	if (bootverbose >= 2)
@@ -12796,19 +12452,11 @@
 	}
 
 	/*
-	**	If multiplier not found but a C1010, assume a mult of 4.
 	**	If multiplier not found or scntl3 not 7,5,3,
 	**	reset chip and get frequency from general purpose timer.
 	**	Otherwise trust scntl3 BIOS setting.
 	*/
-	if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010)  ||
-			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
-		f1=40000;
-		np->multiplier = mult;
-		if (bootverbose >= 2)
-			printk ("%s: clock multiplier assumed\n", ncr_name(np));
-	}
-	else if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
+	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
 		OUTB (nc_stest1, 0);		/* make sure doubler is OFF */
 		f1 = ncr_getfreq (np);
 
@@ -12898,7 +12546,7 @@
 #define OPT_SCSI_PARITY		3
 #define OPT_DISCONNECTION	4
 #define OPT_SPECIAL_FEATURES	5
-#define OPT_ULTRA_SCSI		6
+#define OPT_RESERVED_1		6
 #define OPT_FORCE_SYNC_NEGO	7
 #define OPT_REVERSE_PROBE	8
 #define OPT_DEFAULT_SYNC	9
@@ -12926,7 +12574,7 @@
 static char setup_token[] __initdata = 
 	"tags:"   "mpar:"
 	"spar:"   "disc:"
-	"specf:"  "ultra:"
+	"specf:"  "_rsvd1:"
 	"fsn:"    "revprob:"
 	"sync:"   "verb:"
 	"debug:"  "burst:"
@@ -13012,9 +12660,6 @@
 		case OPT_SPECIAL_FEATURES:
 			driver_setup.special_features = val;
 			break;
-		case OPT_ULTRA_SCSI:
-			driver_setup.ultra_scsi	= val;
-			break;
 		case OPT_FORCE_SYNC_NEGO:
 			driver_setup.force_sync_nego = val;
 			break;
@@ -13118,11 +12763,10 @@
 static void __init ncr_print_driver_setup(void)
 {
 #define YesNo(y)	y ? 'y' : 'n'
-	printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
+	printk (NAME53C8XX ": setup=disc:%c,specf:%d,tags:%d,sync:%d,"
 		"burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
 		YesNo(driver_setup.disconnection),
 		driver_setup.special_features,
-		driver_setup.ultra_scsi,
 		driver_setup.default_tags,
 		driver_setup.default_sync,
 		driver_setup.burst_max,
@@ -13294,6 +12938,8 @@
 			++j;
 			continue;
 		}
+		if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */
+			continue;
 		/* Some HW as the HP LH4 may report twice PCI devices */
 		for (i = 0; i < count ; i++) {
 			if (devtbl[i].slot.bus	     == PciBusNumber(pcidev) && 
@@ -13414,7 +13060,7 @@
 	u_char pci_fix_up = driver_setup.pci_fix_up;
 	u_char revision;
 	u_int irq;
-	u_long base, base_2, io_port; 
+	u_long base, base_c, base_2, base_2_c, io_port; 
 	int i;
 	ncr_chip *chip;
 
@@ -13424,7 +13070,7 @@
 		(int) (PciDeviceFn(pdev) & 7));
 
 #ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
-	if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) {
+	if (pci_set_dma_mask(pdev, (dma_addr_t) (0xffffffffUL))) {
 		printk(KERN_WARNING NAME53C8XX
 		       "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
 		return -1;
@@ -13439,10 +13085,15 @@
 	vendor_id = PciVendorId(pdev);
 	device_id = PciDeviceId(pdev);
 	irq	  = PciIrqLine(pdev);
-	i =	0;
-	i =	pci_get_base_address(pdev, i, &io_port);
-	i =	pci_get_base_address(pdev, i, &base);
-	(void)	pci_get_base_address(pdev, i, &base_2);
+
+	i = pci_get_base_address(pdev, 0, &io_port);
+	io_port = pci_get_base_cookie(pdev, 0);
+
+	base_c = pci_get_base_cookie(pdev, i);
+	i = pci_get_base_address(pdev, i, &base);
+
+	base_2_c = pci_get_base_cookie(pdev, i);
+	(void) pci_get_base_address(pdev, i, &base_2);
 
 	pci_read_config_word(pdev, PCI_COMMAND,		&command);
 	pci_read_config_byte(pdev, PCI_CLASS_REVISION,	&revision);
@@ -13498,7 +13149,7 @@
 	**	This controller sets value 0x52414944 at RAM end - 16.
 	*/
 #if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
-	if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
+	if (chip && (base_2_c & PCI_BASE_ADDRESS_MEM_MASK)) {
 		unsigned int ram_size, ram_val;
 		u_long ram_ptr;
 
@@ -13507,7 +13158,7 @@
 		else
 			ram_size = 4096;
 
-		ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
+		ram_ptr = remap_pci_mem(base_2_c & PCI_BASE_ADDRESS_MEM_MASK,
 					ram_size);
 		if (ram_ptr) {
 			ram_val = readl_raw(ram_ptr + ram_size - 16);
@@ -13589,7 +13240,7 @@
 	**    from attaching devices from the both drivers.
 	**    If you have a better idea, let me know.
 	*/
-/* #ifdef NCR_IOMAPPED */
+/* #ifdef SCSI_NCR_IOMAPPED */
 #if 1
 	if (!(command & PCI_COMMAND_IO)) { 
 		printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
@@ -13606,7 +13257,7 @@
 	base	&= PCI_BASE_ADDRESS_MEM_MASK;
 	base_2	&= PCI_BASE_ADDRESS_MEM_MASK;
 
-/* #ifdef NCR_IOMAPPED */
+/* #ifdef SCSI_NCR_IOMAPPED */
 #if 1
 	if (io_port && check_region (io_port, 128)) {
 		printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
@@ -13616,7 +13267,7 @@
 	if (!io_port)
 		return -1;
 #endif
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (!base) {
 		printk(NAME53C8XX ": MMIO base address disabled.\n");
 		return -1;
@@ -13670,28 +13321,6 @@
 		}
 	}
 
-	if (driver_setup.ultra_scsi < 3 && (chip->features & FE_ULTRA3)) {
-		chip->features |=  FE_ULTRA2;
-		chip->features &= ~FE_ULTRA3;
-	}
-	if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
-		chip->features |=  FE_ULTRA;
-		chip->features &= ~FE_ULTRA2;
-	}
-	if (driver_setup.ultra_scsi < 1)
-		chip->features &= ~FE_ULTRA;
-
-	if (!driver_setup.max_wide)
-		chip->features &= ~FE_WIDE;
-
-	/*
-	 * C1010 Ultra3 support requires 16 bit data transfers.
-	 */
-	if (!driver_setup.max_wide && (chip->features & FE_ULTRA3)) {
-		chip->features |= FE_ULTRA2;
-		chip->features |= ~FE_ULTRA3;
-	}
-
 	/*
 	**	Some features are required to be enabled in order to 
 	**	work around some chip problems. :) ;)
@@ -13751,6 +13380,8 @@
 	device->slot.device_fn	= PciDeviceFn(pdev);
 	device->slot.base	= base;
 	device->slot.base_2	= base_2;
+	device->slot.base_c	= base_c;
+	device->slot.base_2_c	= base_2_c;
 	device->slot.io_port	= io_port;
 	device->slot.irq	= irq;
 	device->attach_done	= 0;
@@ -13780,11 +13411,12 @@
 	/*
 	**    Get access to chip IO registers
 	*/
-#ifdef NCR_IOMAPPED
+#ifdef SCSI_NCR_IOMAPPED
 	request_region(devp->slot.io_port, 128, NAME53C8XX);
 	devp->slot.base_io = devp->slot.io_port;
 #else
-	devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128);
+	devp->slot.reg = 
+		(struct ncr_reg *) remap_pci_mem(devp->slot.base_c, 128);
 	if (!devp->slot.reg)
 		return;
 #endif
@@ -13806,7 +13438,7 @@
 	/*
 	** Release access to chip IO registers
 	*/
-#ifdef NCR_IOMAPPED
+#ifdef SCSI_NCR_IOMAPPED
 	release_region(devp->slot.base_io, 128);
 #else
 	unmap_pci_mem((u_long) devp->slot.reg, 128ul);
@@ -14241,7 +13873,7 @@
 /*=========================================================================
 **	Proc file system stuff
 **
-**	A read operation returns profile information.
+**	A read operation returns adapter information.
 **	A write operation is a control command.
 **	The string is parsed in the driver code and the command is passed 
 **	to the ncr_usercmd() function.
@@ -14335,10 +13967,6 @@
 		uc->cmd = UC_RESETDEV;
 	else if	((arg_len = is_keyword(ptr, len, "cleardev")) != 0)
 		uc->cmd = UC_CLEARDEV;
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
-		uc->cmd = UC_CLEARPROF;
-#endif
 	else
 		arg_len = 0;
 
@@ -14499,11 +14127,9 @@
 }
 
 /*
-**	Copy formatted profile information into the input buffer.
+**	Copy formatted information into the input buffer.
 */
 
-#define to_ms(t) ((t) * 1000 / HZ)
-
 static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
 {
 	struct info_str info;
@@ -14538,24 +14164,6 @@
 			  driver_setup.debug, driver_setup.verbose);
 	}
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	copy_info(&info, "Profiling information:\n");
-	copy_info(&info, "  %-12s = %lu\n", "num_fly",	np->profile.num_fly);
-	copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
-	copy_info(&info, "  %-12s = %lu\n", "num_disc",	np->profile.num_disc);
-	copy_info(&info, "  %-12s = %lu\n", "num_disc0",np->profile.num_disc0);
-	copy_info(&info, "  %-12s = %lu\n", "num_break",np->profile.num_break);
-#if 000
-	copy_info(&info, "  %-12s = %lu\n", "num_br1k",np->profile.num_br1k);
-	copy_info(&info, "  %-12s = %lu\n", "num_br2k",np->profile.num_br2k);
-	copy_info(&info, "  %-12s = %lu\n", "num_br4k",np->profile.num_br4k);
-	copy_info(&info, "  %-12s = %lu\n", "num_br8k",np->profile.num_br8k);
-	copy_info(&info, "  %-12s = %lu\n", "num_brnk",np->profile.num_brnk);
-#endif
-	copy_info(&info, "  %-12s = %lu\n", "num_int",	np->profile.num_int);
-	copy_info(&info, "  %-12s = %lu\n","num_kbytes",np->profile.num_kbytes);
-#endif
-
 	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
@@ -14563,7 +14171,7 @@
 
 /*
 **	Entry point of the scsi proc fs of the driver.
-**	- func = 0 means read  (returns profile data)
+**	- func = 0 means read  (returns adapter infos)
 **	- func = 1 means write (parse user control command)
 */
 
@@ -14830,10 +14438,10 @@
 	return retv;
 }
 
-#undef SET_BIT /* 0 */
-#undef CLR_BIT /* 1 */
-#undef SET_CLK /* 2 */
-#undef CLR_CLK /* 3 */
+#undef SET_BIT
+#undef CLR_BIT
+#undef SET_CLK
+#undef CLR_CLK
 
 /*
  *  Try reading Symbios NVRAM.
@@ -15063,5 +14671,10 @@
 **	Module stuff
 */
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 static Scsi_Host_Template driver_template = SYM53C8XX;
 #include "scsi_module.c"
+#elif defined(MODULE)
+Scsi_Host_Template driver_template = SYM53C8XX;
+#include "scsi_module.c"
+#endif
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h
--- v2.4.2/linux/drivers/scsi/sym53c8xx.h	Thu Jan  4 14:52:35 2001
+++ linux/drivers/scsi/sym53c8xx.h	Fri Mar 23 18:25:08 2001
@@ -65,6 +65,8 @@
 **	Used by hosts.c and sym53c8xx.c with module configuration.
 */
 
+#if (LINUX_VERSION_CODE >= 0x020400) || defined(HOSTS_C) || defined(MODULE)
+
 #include <scsi/scsicam.h>
 
 int sym53c8xx_abort(Scsi_Cmnd *);
@@ -108,5 +110,7 @@
 			0,	0,	DISABLE_CLUSTERING} 
  
 #endif /* LINUX_VERSION_CODE */
+
+#endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
 #endif /* SYM53C8XX_H */
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h
--- v2.4.2/linux/drivers/scsi/sym53c8xx_comm.h	Mon Oct 16 12:56:50 2000
+++ linux/drivers/scsi/sym53c8xx_comm.h	Tue Mar  6 19:34:25 2001
@@ -80,17 +80,6 @@
 
 /*==========================================================
 **
-**    Io mapped versus memory mapped.
-**
-**==========================================================
-*/
-
-#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
-#define NCR_IOMAPPED
-#endif
-
-/*==========================================================
-**
 **	Miscallaneous defines.
 **
 **==========================================================
@@ -261,33 +250,6 @@
 
 /*==========================================================
 **
-**	On x86 architecture, write buffers management does 
-**	not reorder writes to memory. So, using compiler 
-**	optimization barriers is enough to guarantee some 
-**	ordering when the CPU is writing data accessed by 
-**	the NCR.
-**	On Alpha architecture, explicit memory barriers have 
-**	to be used.
-**	Other architectures are defaulted to mb() macro if  
-**	defined, otherwise use compiler barrier.
-**
-**==========================================================
-*/
-
-#if defined(__i386__)
-#define MEMORY_BARRIER()	barrier()
-#elif defined(__alpha__)
-#define MEMORY_BARRIER()	mb()
-#else
-#  ifdef mb
-#  define MEMORY_BARRIER()	mb()
-#  else
-#  define MEMORY_BARRIER()	barrier()
-#  endif
-#endif
-
-/*==========================================================
-**
 **	Simple Wrapper to kernel PCI bus interface.
 **
 **	This wrapper allows to get rid of old kernel PCI 
@@ -310,30 +272,42 @@
 #define PciDeviceId(d)		(d)->device
 #define PciIrqLine(d)		(d)->irq
 
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
-
-static int __init 
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+static u_long __init
+pci_get_base_cookie(struct pci_dev *pdev, int index)
 {
-	*base = pdev->resource[index].start;
-	if ((pdev->resource[index].flags & 0x7) == 0x4)
-		++index;
-	return ++index;
-}
+	u_long base;
+
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,3,12)
+	base = pdev->resource[index].start;
 #else
-static int __init 
+	base = pdev->base_address[index];
+#if BITS_PER_LONG > 32
+	if ((base & 0x7) == 0x4)
+		*base |= (((u_long)pdev->base_address[++index]) << 32);
+#endif
+#endif
+	return (base & ~0x7ul);
+}
+
+static int __init
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
 {
-	*base = pdev->base_address[index++];
-	if ((*base & 0x7) == 0x4) {
+	u32 tmp;
+#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
+
+	pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
+	*base = tmp;
+	++index;
+	if ((tmp & 0x7) == 0x4) {
 #if BITS_PER_LONG > 32
-		*base |= (((u_long)pdev->base_address[index]) << 32);
+		pci_read_config_dword(pdev, PCI_BAR_OFFSET(index), &tmp);
+		*base |= (((u_long)tmp) << 32);
 #endif
 		++index;
 	}
 	return index;
+#undef PCI_BAR_OFFSET
 }
-#endif
 
 #else	/* Incomplete emulation of current PCI code for pre-2.2 kernels */
 
@@ -413,9 +387,23 @@
 	}
 	return offset;
 }
+static u_long __init
+pci_get_base_cookie(struct pci_dev *pdev, int offset)
+{
+	u_long base;
+
+	(void) pci_get_base_address(dev, offset, &base);
+
+	return base;
+}
 
 #endif	/* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
 
+/* Does not make sense in earlier kernels */
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0)
+#define pci_enable_device(pdev)		(0)
+#endif
+
 /*==========================================================
 **
 **	SMP threading.
@@ -488,18 +476,14 @@
 
 #ifdef __sparc__
 #  include <asm/irq.h>
-#  define pcivtobus(p)			bus_dvma_to_mem(p)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #elif defined(__alpha__)
-#  define pcivtobus(p)			((p) & 0xfffffffful)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #else	/* others */
-#  define pcivtobus(p)			(p)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #endif
 
-#if (defined(SCSI_NCR_NVRAM_SUPPORT) && !defined(NCR_IOMAPPED)) || \
-	(defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED))
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 static u_long __init remap_pci_mem(u_long base, u_long size)
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
@@ -1105,168 +1089,6 @@
 #define initverbose (driver_setup.verbose)
 #define bootverbose (np->verbose)
 
-/*==========================================================
-**
-**	Big/Little endian support.
-**
-**	If the NCR uses big endian addressing mode over the 
-**	PCI, actual io register addresses for byte and word 
-**	accesses must be changed according to lane routing.
-**	Btw, ncr_offb() and ncr_offw() macros only apply to 
-**	constants and so donnot generate bloated code.
-**
-**	If the CPU and the NCR use same endian-ness adressing,
-**	no byte reordering is needed for script patching.
-**	Macro cpu_to_scr() is to be used for script patching.
-**	Macro scr_to_cpu() is to be used for getting a DWORD 
-**	from the script.
-**
-**==========================================================
-*/
-
-#if	defined(SCSI_NCR_BIG_ENDIAN)
-
-#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
-#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
-
-#else
-
-#define ncr_offb(o)	(o)
-#define ncr_offw(o)	(o)
-
-#endif
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_le32(dw)
-#define scr_to_cpu(dw)	le32_to_cpu(dw)
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_be32(dw)
-#define scr_to_cpu(dw)	be32_to_cpu(dw)
-
-#else
-
-#define cpu_to_scr(dw)	(dw)
-#define scr_to_cpu(dw)	(dw)
-
-#endif
-
-/*==========================================================
-**
-**	Access to the controller chip.
-**
-**	If NCR_IOMAPPED is defined, the driver will use 
-**	normal IOs instead of the MEMORY MAPPED IO method  
-**	recommended by PCI specifications.
-**	If all PCI bridges, host brigdes and architectures 
-**	would have been correctly designed for PCI, this 
-**	option would be useless.
-**
-**	If the CPU and the NCR use same endian-ness adressing,
-**	no byte reordering is needed for accessing chip io 
-**	registers. Functions suffixed by '_raw' are assumed 
-**	to access the chip over the PCI without doing byte 
-**	reordering. Functions suffixed by '_l2b' are 
-**	assumed to perform little-endian to big-endian byte 
-**	reordering, those suffixed by '_b2l' blah, blah,
-**	blah, ...
-**
-**==========================================================
-*/
-
-#if defined(NCR_IOMAPPED)
-
-/*
-**	IO mapped only input / ouput
-*/
-
-#define	INB_OFF(o)		inb (np->base_io + ncr_offb(o))
-#define	OUTB_OFF(o, val)	outb ((val), np->base_io + ncr_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define	INW_OFF(o)		inw_l2b (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_l2b (np->base_io + (o))
-
-#define	OUTW_OFF(o, val)	outw_b2l ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_b2l ((val), np->base_io + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define	INW_OFF(o)		inw_b2l (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_b2l (np->base_io + (o))
-
-#define	OUTW_OFF(o, val)	outw_l2b ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_l2b ((val), np->base_io + (o))
-
-#else
-
-#define	INW_OFF(o)		inw_raw (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_raw (np->base_io + (o))
-
-#define	OUTW_OFF(o, val)	outw_raw ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_raw ((val), np->base_io + (o))
-
-#endif	/* ENDIANs */
-
-#else	/* defined NCR_IOMAPPED */
-
-/*
-**	MEMORY mapped IO input / output
-*/
-
-#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
-#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
-
-#else
-
-#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
-
-#endif
-
-#endif	/* defined NCR_IOMAPPED */
-
-#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
-#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
-#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
-
-#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
-
-/*
-**	Set bit field ON, OFF 
-*/
-
-#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
-#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
-#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
-#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
-#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
-#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
-
 
 /*==========================================================
 **
@@ -1281,6 +1103,8 @@
 	u_long	base;
 	u_long	base_2;
 	u_long	io_port;
+	u_long	base_c;
+	u_long	base_2_c;
 	int	irq;
 /* port and reg fields to use INB, OUTB macros */
 	u_long	base_io;
@@ -1546,10 +1370,10 @@
 	return retv;
 }
 
-#undef SET_BIT 
-#undef CLR_BIT 
-#undef SET_CLK 
-#undef CLR_CLK 
+#undef SET_BIT
+#undef CLR_BIT
+#undef SET_CLK
+#undef CLR_CLK
 
 /*
  *  Try reading Symbios NVRAM.
@@ -1798,11 +1622,12 @@
 	/*
 	**    Get access to chip IO registers
 	*/
-#ifdef NCR_IOMAPPED
+#ifdef SCSI_NCR_IOMAPPED
 	request_region(devp->slot.io_port, 128, NAME53C8XX);
 	devp->slot.base_io = devp->slot.io_port;
 #else
-	devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128);
+	devp->slot.reg = 
+		(struct ncr_reg *) remap_pci_mem(devp->slot.base_c, 128);
 	if (!devp->slot.reg)
 		return;
 #endif
@@ -1824,7 +1649,7 @@
 	/*
 	** Release access to chip IO registers
 	*/
-#ifdef NCR_IOMAPPED
+#ifdef SCSI_NCR_IOMAPPED
 	release_region(devp->slot.base_io, 128);
 #else
 	unmap_pci_mem((u_long) devp->slot.reg, 128ul);
@@ -1991,7 +1816,7 @@
 #define OPT_SCSI_PARITY		3
 #define OPT_DISCONNECTION	4
 #define OPT_SPECIAL_FEATURES	5
-#define OPT_ULTRA_SCSI		6
+#define OPT_UNUSED_1		6
 #define OPT_FORCE_SYNC_NEGO	7
 #define OPT_REVERSE_PROBE	8
 #define OPT_DEFAULT_SYNC	9
@@ -2104,9 +1929,6 @@
 		case OPT_SPECIAL_FEATURES:
 			driver_setup.special_features = val;
 			break;
-		case OPT_ULTRA_SCSI:
-			driver_setup.ultra_scsi	= val;
-			break;
 		case OPT_FORCE_SYNC_NEGO:
 			driver_setup.force_sync_nego = val;
 			break;
@@ -2248,11 +2070,10 @@
 static void __init ncr_print_driver_setup(void)
 {
 #define YesNo(y)	y ? 'y' : 'n'
-	printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
+	printk (NAME53C8XX ": setup=disc:%c,specf:%d,tags:%d,sync:%d,"
 		"burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
 		YesNo(driver_setup.disconnection),
 		driver_setup.special_features,
-		driver_setup.ultra_scsi,
 		driver_setup.default_tags,
 		driver_setup.default_sync,
 		driver_setup.burst_max,
@@ -2352,7 +2173,7 @@
 	u_char pci_fix_up = driver_setup.pci_fix_up;
 	u_char revision;
 	u_int irq;
-	u_long base, base_2, io_port; 
+	u_long base, base_c, base_2, base_2_c, io_port; 
 	int i;
 	ncr_chip *chip;
 
@@ -2377,10 +2198,15 @@
 	vendor_id = PciVendorId(pdev);
 	device_id = PciDeviceId(pdev);
 	irq	  = PciIrqLine(pdev);
-	i =	0;
-	i =	pci_get_base_address(pdev, i, &io_port);
-	i =	pci_get_base_address(pdev, i, &base);
-	(void)	pci_get_base_address(pdev, i, &base_2);
+
+	i = pci_get_base_address(pdev, 0, &io_port);
+	io_port = pci_get_base_cookie(pdev, 0);
+
+	base_c = pci_get_base_cookie(pdev, i);
+	i = pci_get_base_address(pdev, i, &base);
+
+	base_2_c = pci_get_base_cookie(pdev, i);
+	(void) pci_get_base_address(pdev, i, &base_2);
 
 	pci_read_config_word(pdev, PCI_COMMAND,		&command);
 	pci_read_config_byte(pdev, PCI_CLASS_REVISION,	&revision);
@@ -2438,7 +2264,7 @@
 	**	This controller sets value 0x52414944 at RAM end - 16.
 	*/
 #if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
-	if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
+	if (chip && (base_2_c & PCI_BASE_ADDRESS_MEM_MASK)) {
 		unsigned int ram_size, ram_val;
 		u_long ram_ptr;
 
@@ -2447,7 +2273,7 @@
 		else
 			ram_size = 4096;
 
-		ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
+		ram_ptr = remap_pci_mem(base_2_c & PCI_BASE_ADDRESS_MEM_MASK,
 					ram_size);
 		if (ram_ptr) {
 			ram_val = readl_raw(ram_ptr + ram_size - 16);
@@ -2529,7 +2355,7 @@
 	**    from attaching devices from the both drivers.
 	**    If you have a better idea, let me know.
 	*/
-/* #ifdef NCR_IOMAPPED */
+/* #ifdef SCSI_NCR_IOMAPPED */
 #if 1
 	if (!(command & PCI_COMMAND_IO)) { 
 		printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
@@ -2546,7 +2372,7 @@
 	base	&= PCI_BASE_ADDRESS_MEM_MASK;
 	base_2	&= PCI_BASE_ADDRESS_MEM_MASK;
 
-/* #ifdef NCR_IOMAPPED */
+/* #ifdef SCSI_NCR_IOMAPPED */
 #if 1
 	if (io_port && check_region (io_port, 128)) {
 		printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
@@ -2556,7 +2382,7 @@
 	if (!io_port)
 		return -1;
 #endif
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (!base) {
 		printk(NAME53C8XX ": MMIO base address disabled.\n");
 		return -1;
@@ -2602,14 +2428,6 @@
 		if (driver_setup.special_features & 4)
 			chip->features &= ~FE_NOPM;
 	}
-	if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
-		chip->features |=  FE_ULTRA;
-		chip->features &= ~FE_ULTRA2;
-	}
-	if (driver_setup.ultra_scsi < 1)
-		chip->features &= ~FE_ULTRA;
-	if (!driver_setup.max_wide)
-		chip->features &= ~FE_WIDE;
 
 	/*
 	**	Some features are required to be enabled in order to 
@@ -2670,6 +2488,8 @@
 	device->slot.device_fn	= PciDeviceFn(pdev);
 	device->slot.base	= base;
 	device->slot.base_2	= base_2;
+	device->slot.base_c	= base_c;
+	device->slot.base_2_c	= base_2_c;
 	device->slot.io_port	= io_port;
 	device->slot.irq	= irq;
 	device->attach_done	= 0;
@@ -2754,6 +2574,8 @@
 			++j;
 			continue;
 		}
+		if (pci_enable_device(pcidev)) /* @!*!$&*!%-*#;! */
+			continue;
 		/* Some HW as the HP LH4 may report twice PCI devices */
 		for (i = 0; i < count ; i++) {
 			if (devtbl[i].slot.bus	     == PciBusNumber(pcidev) && 
diff -u --recursive --new-file v2.4.2/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- v2.4.2/linux/drivers/scsi/sym53c8xx_defs.h	Thu Jan  4 14:52:24 2001
+++ linux/drivers/scsi/sym53c8xx_defs.h	Fri Mar 23 18:24:58 2001
@@ -95,9 +95,6 @@
 #define SCSI_NCR_DEBUG_INFO_SUPPORT
 #define SCSI_NCR_PCI_FIX_UP_SUPPORT
 #ifdef	SCSI_NCR_PROC_INFO_SUPPORT
-#	ifdef	CONFIG_SCSI_NCR53C8XX_PROFILE
-#		define	SCSI_NCR_PROFILE_SUPPORT
-#	endif
 #	define	SCSI_NCR_USER_COMMAND_SUPPORT
 #	define	SCSI_NCR_USER_INFO_SUPPORT
 #endif
@@ -141,18 +138,6 @@
  */
 #define	SCSI_NCR_SETUP_SPECIAL_FEATURES		(3)
 
-/*
- * For Ultra2 and Ultra3 SCSI support allow 80Mhz synchronous data transfers.
- * Value means:
- *  0 - Ultra speeds disabled
- *  1 - Ultra enabled  (Maximum 20Mtrans/sec)
- *  2 - Ultra2 enabled (Maximum 40Mtrans/sec)
- *  3 - Ultra3 enabled (Maximum 80Mtrans/sec)
- *
- * Use boot options sym53c8xx=ultra:3 to enable Ultra3 support.
- */
-
-#define SCSI_NCR_SETUP_ULTRA_SCSI		(3)
 #define SCSI_NCR_MAX_SYNC			(80)
 
 /*
@@ -183,17 +168,35 @@
 #endif
 
 /*
- * Use normal IO if configured. Forced for alpha and ppc.
+ * Use normal IO if configured. Forced for alpha and powerpc.
+ * Powerpc fails copying to on-chip RAM using memcpy_toio().
  */
 #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
 #define	SCSI_NCR_IOMAPPED
-#elif defined(__alpha__) || defined(__powerpc__)
+#elif defined(__alpha__)
 #define	SCSI_NCR_IOMAPPED
+#elif defined(__powerpc__)
+#define	SCSI_NCR_IOMAPPED
+#define SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 #elif defined(__sparc__)
 #undef SCSI_NCR_IOMAPPED
 #endif
 
 /*
+ * Should we enable DAC cycles on Sparc64 platform?
+ * Until further investigation we do not enable it
+ * at the moment.
+ * We may want to enable it for __ia64__ (untested)
+ */
+#if defined(__ia64__)
+#    if !defined(SCSI_NCR_USE_64BIT_DAC)
+#        define SCSI_NCR_USE_64BIT_DAC
+#    endif
+#else
+#    undef SCSI_NCR_USE_64BIT_DAC
+#endif
+
+/*
  * Immediate arbitration
  */
 #if defined(CONFIG_SCSI_NCR53C8XX_IARB)
@@ -376,12 +379,11 @@
 #define ktime_add(a, o)		((a) + (u_long)(o))
 #define ktime_sub(a, o)		((a) - (u_long)(o))
 
+
 /*
-**	IO functions definition for big/little endian support.
-**	For now, the NCR is only supported in little endian addressing mode, 
-**	and big endian byte ordering is only supported for the PPC.
-**	MMIO is not used on PPC.
-*/
+ *  IO functions definition for big/little endian CPU support.
+ *  For now, the NCR is only supported in little endian addressing mode, 
+ */
 
 #ifdef	__BIG_ENDIAN
 
@@ -389,27 +391,34 @@
 #error	"BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
 #endif
 
-#if defined(__powerpc__)
 #define	inw_l2b		inw
 #define	inl_l2b		inl
 #define	outw_b2l	outw
 #define	outl_b2l	outl
-#elif defined(__sparc__)
+
+#define	readb_raw	readb
+#define	writeb_raw	writeb
+
+#if defined(__hppa__)
+#define	readw_l2b(a)	le16_to_cpu(readw(a))
+#define	readl_l2b(a)	le32_to_cpu(readl(a))
+#define	writew_b2l(v,a)	writew(cpu_to_le16(v),a)
+#define	writel_b2l(v,a)	writel(cpu_to_le32(v),a)
+#else	/* Other bid-endian */
 #define	readw_l2b	readw
 #define	readl_l2b	readl
 #define	writew_b2l	writew
 #define	writel_b2l	writel
-#else
-#error	"Support for BIG ENDIAN is only available for PowerPC and SPARC"
 #endif
 
 #else	/* little endian */
 
-#if defined(__i386__)	/* i386 implements full FLAT memory/MMIO model */
 #define	inw_raw		inw
 #define	inl_raw		inl
 #define	outw_raw	outw
 #define	outl_raw	outl
+
+#if defined(__i386__)	/* i386 implements full FLAT memory/MMIO model */
 #define readb_raw(a)	(*(volatile unsigned char *) (a))
 #define readw_raw(a)	(*(volatile unsigned short *) (a))
 #define readl_raw(a)	(*(volatile unsigned int *) (a))
@@ -417,13 +426,11 @@
 #define writew_raw(b,a)	((*(volatile unsigned short *) (a)) = (b))
 #define writel_raw(b,a)	((*(volatile unsigned int *) (a)) = (b))
 
-#else	/* Other little-endian (for now alpha) */
-#define	inw_raw		inw
-#define	inl_raw		inl
-#define	outw_raw	outw
-#define	outl_raw	outl
+#else	/* Other little-endian */
+#define	readb_raw	readb
 #define	readw_raw	readw
 #define	readl_raw	readl
+#define	writeb_raw	writeb
 #define	writew_raw	writew
 #define	writel_raw	writel
 
@@ -434,6 +441,204 @@
 #error	"The NCR in BIG ENDIAN addressing mode is not (yet) supported"
 #endif
 
+
+/*
+ *  IA32 architecture does not reorder STORES and prevents
+ *  LOADS from passing STORES. It is called `program order' 
+ *  by Intel and allows device drivers to deal with memory 
+ *  ordering by only ensuring that the code is not reordered  
+ *  by the compiler when ordering is required.
+ *  Other architectures implement a weaker ordering that 
+ *  requires memory barriers (and also IO barriers when they 
+ *  make sense) to be used.
+ *  We want to be paranoid for ppc and ia64. :)
+ */
+
+#if	defined	__i386__
+#define MEMORY_BARRIER()	do { ; } while(0)
+#elif	defined	__powerpc__
+#define MEMORY_BARRIER()	__asm__ volatile("eieio; sync" : : : "memory")
+#elif	defined	__ia64__
+#define MEMORY_BARRIER()	__asm__ volatile("mf.a; mf" : : : "memory")
+#else
+#define MEMORY_BARRIER()	mb()
+#endif
+
+
+/*
+ *  If the NCR uses big endian addressing mode over the 
+ *  PCI, actual io register addresses for byte and word 
+ *  accesses must be changed according to lane routing.
+ *  Btw, ncr_offb() and ncr_offw() macros only apply to 
+ *  constants and so donnot generate bloated code.
+ */
+
+#if	defined(SCSI_NCR_BIG_ENDIAN)
+
+#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
+#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
+
+#else
+
+#define ncr_offb(o)	(o)
+#define ncr_offw(o)	(o)
+
+#endif
+
+/*
+ *  If the CPU and the NCR use same endian-ness adressing,
+ *  no byte reordering is needed for script patching.
+ *  Macro cpu_to_scr() is to be used for script patching.
+ *  Macro scr_to_cpu() is to be used for getting a DWORD 
+ *  from the script.
+ */
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_le32(dw)
+#define scr_to_cpu(dw)	le32_to_cpu(dw)
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_be32(dw)
+#define scr_to_cpu(dw)	be32_to_cpu(dw)
+
+#else
+
+#define cpu_to_scr(dw)	(dw)
+#define scr_to_cpu(dw)	(dw)
+
+#endif
+
+/*
+ *  Access to the controller chip.
+ *
+ *  If SCSI_NCR_IOMAPPED is defined, the driver will use 
+ *  normal IOs instead of the MEMORY MAPPED IO method  
+ *  recommended by PCI specifications.
+ *  If all PCI bridges, host brigdes and architectures 
+ *  would have been correctly designed for PCI, this 
+ *  option would be useless.
+ *
+ *  If the CPU and the NCR use same endian-ness adressing,
+ *  no byte reordering is needed for accessing chip io 
+ *  registers. Functions suffixed by '_raw' are assumed 
+ *  to access the chip over the PCI without doing byte 
+ *  reordering. Functions suffixed by '_l2b' are 
+ *  assumed to perform little-endian to big-endian byte 
+ *  reordering, those suffixed by '_b2l' blah, blah,
+ *  blah, ...
+ */
+
+#if defined(SCSI_NCR_IOMAPPED)
+
+/*
+ *  IO mapped only input / ouput
+ */
+
+#define	INB_OFF(o)		inb (np->base_io + ncr_offb(o))
+#define	OUTB_OFF(o, val)	outb ((val), np->base_io + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_l2b (np->base_io + ncr_offw(o))
+#define	INL_OFF(o)		inl_l2b (np->base_io + (o))
+
+#define	OUTW_OFF(o, val)	outw_b2l ((val), np->base_io + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_b2l ((val), np->base_io + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_b2l (np->base_io + ncr_offw(o))
+#define	INL_OFF(o)		inl_b2l (np->base_io + (o))
+
+#define	OUTW_OFF(o, val)	outw_l2b ((val), np->base_io + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_l2b ((val), np->base_io + (o))
+
+#else
+
+#define	INW_OFF(o)		inw_raw (np->base_io + ncr_offw(o))
+#define	INL_OFF(o)		inl_raw (np->base_io + (o))
+
+#define	OUTW_OFF(o, val)	outw_raw ((val), np->base_io + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_raw ((val), np->base_io + (o))
+
+#endif	/* ENDIANs */
+
+#else	/* defined SCSI_NCR_IOMAPPED */
+
+/*
+ *  MEMORY mapped IO input / output
+ */
+
+#define INB_OFF(o)		readb_raw((char *)np->reg + ncr_offb(o))
+#define OUTB_OFF(o, val)	writeb_raw((val), (char *)np->reg + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
+
+#else
+
+#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
+
+#endif
+
+#endif	/* defined SCSI_NCR_IOMAPPED */
+
+#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
+#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
+#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
+
+#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+
+/*
+ *  Set bit field ON, OFF 
+ */
+
+#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
+#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
+
+/*
+ *  We normally want the chip to have a consistent view
+ *  of driver internal data structures when we restart it.
+ *  Thus these macros.
+ */
+#define OUTL_DSP(v)				\
+	do {					\
+		MEMORY_BARRIER();		\
+		OUTL (nc_dsp, (v));		\
+	} while (0)
+
+#define OUTONB_STD()				\
+	do {					\
+		MEMORY_BARRIER();		\
+		OUTONB (nc_dcntl, (STD|NOCOM));	\
+	} while (0)
+
+
 /*
 **	NCR53C8XX Device Ids
 */
@@ -486,6 +691,10 @@
 #define PCI_DEVICE_ID_NCR_53C895A 0x12
 #endif
 
+#ifndef PCI_DEVICE_ID_NCR_53C875A
+#define PCI_DEVICE_ID_NCR_53C875A 0x13
+#endif
+
 #ifndef PCI_DEVICE_ID_NCR_53C1510D
 #define PCI_DEVICE_ID_NCR_53C1510D 0xa
 #endif
@@ -525,15 +734,16 @@
 #define FE_PFEN		(1<<12)   /* Prefetch enable */
 #define FE_LDSTR	(1<<13)   /* Load/Store supported */
 #define FE_RAM		(1<<14)   /* On chip RAM present */
-#define FE_CLK80	(1<<15)   /* Board clock is 80 MHz */
+#define FE_VARCLK	(1<<15)   /* SCSI lock may vary */
 #define FE_RAM8K	(1<<16)   /* On chip RAM sized 8Kb */
-#define FE_64BIT	(1<<17)   /* Supports 64-bit addressing */
+#define FE_64BIT	(1<<17)   /* Have a 64-bit PCI interface */
 #define FE_IO256	(1<<18)   /* Requires full 256 bytes in PCI space */
 #define FE_NOPM		(1<<19)   /* Scripts handles phase mismatch */
 #define FE_LEDC		(1<<20)   /* Hardware control of LED */
 #define FE_DIFF		(1<<21)   /* Support Differential SCSI */
 #define FE_ULTRA3	(1<<22)   /* Ultra-3 80Mtrans/sec */
 #define FE_66MHZ 	(1<<23)   /* 66MHz PCI Support */
+#define FE_DAC	 	(1<<24)   /* Support DAC cycles (64 bit addressing) */
 
 #define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
 #define FE_SCSI_SET	(FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
@@ -574,35 +784,23 @@
  FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF}	\
  ,									\
  {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
- FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}		\
+ FE_ULTRA|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}				\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|\
- FE_RAM|FE_DIFF}							\
- ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_DIFF}							\
- ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0x1f, "876",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_DIFF}							\
+ FE_WIDE|FE_ULTRA|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|		\
+ FE_RAM|FE_DIFF|FE_VARCLK}						\
  ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0x2f, "875E",  6, 16, 5,			\
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875",  6, 16, 5,			\
  FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_DIFF}							\
- ,									\
- {PCI_DEVICE_ID_NCR_53C875, 0xff, "876",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_DIFF}							\
+ FE_RAM|FE_DIFF|FE_VARCLK}						\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5,			\
  FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM}								\
+ FE_RAM|FE_VARCLK}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  6, 16, 5,			\
  FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_DIFF}							\
+ FE_RAM|FE_DIFF|FE_VARCLK}						\
  ,									\
  {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  6, 31, 7,			\
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
@@ -610,23 +808,28 @@
  ,									\
  {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  6, 31, 7,			\
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}			\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC}		\
  ,									\
  {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a",  6, 31, 7,			\
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
- FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}			\
+ FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC}			\
+ ,									\
+ {PCI_DEVICE_ID_NCR_53C875A, 0xff, "875a",  6, 31, 7,			\
+ FE_WIDE|FE_ULTRA|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC}				\
  ,									\
  {PCI_DEVICE_ID_NCR_53C1510D, 0xff, "1510D",  7, 31, 7,			\
  FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
  FE_RAM|FE_IO256}							\
  ,									\
- {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010",  6, 62, 7,			\
+ {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010-33",  6, 62, 7,		\
  FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|		\
- FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3}		\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3}	\
  ,									\
- {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010_66",  6, 62, 7,		\
+ {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66",  6, 62, 7,		\
  FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|		\
- FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3|FE_66MHZ}	\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3|	\
+ FE_66MHZ}								\
 }
 
 /*
@@ -662,7 +865,6 @@
 	u_char	scsi_parity;
 	u_char	disconnection;
 	u_char	special_features;
-	u_char	ultra_scsi;
 	u_char	force_sync_nego;
 	u_char	reverse_probe;
 	u_char	pci_fix_up;
@@ -696,15 +898,14 @@
 	SCSI_NCR_SETUP_SCSI_PARITY,		\
 	SCSI_NCR_SETUP_DISCONNECTION,		\
 	SCSI_NCR_SETUP_SPECIAL_FEATURES,	\
-	SCSI_NCR_SETUP_ULTRA_SCSI,		\
 	SCSI_NCR_SETUP_FORCE_SYNC_NEGO,		\
 	0,					\
 	0,					\
 	1,					\
-	1,					\
+	0,					\
 	SCSI_NCR_SETUP_DEFAULT_TAGS,		\
 	SCSI_NCR_SETUP_DEFAULT_SYNC,		\
-	0x0200,					\
+	0x00,					\
 	7,					\
 	SCSI_NCR_SETUP_LED_PIN,			\
 	1,					\
@@ -727,7 +928,6 @@
 {						\
 	0,					\
 	1,					\
-	0,					\
 	0,					\
 	0,					\
 	0,					\
diff -u --recursive --new-file v2.4.2/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.4.2/linux/drivers/sgi/char/graphics.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sgi/char/graphics.c	Mon Mar 19 12:35:09 2001
@@ -153,11 +153,11 @@
 		 * sgi_graphics_mmap
 		 */
 		disable_gconsole ();
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 		r = do_mmap (file, (unsigned long)vaddr,
 			     cards[board].g_regs_size, PROT_READ|PROT_WRITE,
 			     MAP_FIXED|MAP_PRIVATE, 0);
-		up(&current->mm->mmap_sem);
+		up_write(&current->mm->mmap_sem);
 		if (r)
 			return r;
 	}
diff -u --recursive --new-file v2.4.2/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.4.2/linux/drivers/sgi/char/shmiq.c	Wed Jul 12 21:58:43 2000
+++ linux/drivers/sgi/char/shmiq.c	Mon Mar 19 12:35:09 2001
@@ -286,11 +286,11 @@
 			s = req.arg * sizeof (struct shmqevent) +
 			    sizeof (struct sharedMemoryInputQueue);
 			v = sys_munmap (vaddr, s);
-			down(&current->mm->mmap_sem);
+			down_write(&current->mm->mmap_sem);
 			do_munmap(current->mm, vaddr, s);
 			do_mmap(filp, vaddr, s, PROT_READ | PROT_WRITE,
 			        MAP_PRIVATE|MAP_FIXED, 0);
-			up(&current->mm->mmap_sem);
+			up_write(&current->mm->mmap_sem);
 			shmiqs[minor].events = req.arg;
 			shmiqs[minor].mapped = 1;
 
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.4.2/linux/drivers/sound/Config.in	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/Config.in	Tue Mar  6 19:28:32 2001
@@ -6,7 +6,7 @@
 
 # Prompt user for primary drivers.
 
-dep_tristate '  C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND
+dep_tristate '  C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI
 if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
     bool '    Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP
     bool '    Enable 4 channel mode for CMI8738' CONFIG_SOUND_CMPCI_4CH
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/awe_wave.c linux/drivers/sound/awe_wave.c
--- v2.4.2/linux/drivers/sound/awe_wave.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/awe_wave.c	Fri Mar  2 11:12:11 2001
@@ -206,7 +206,7 @@
 int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
 int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-static int isapnp = 1;
+static int isapnp = -1;
 #else
 static int isapnp = 0;
 #endif
@@ -4843,10 +4843,12 @@
 	if (isapnp) {
 		if (awe_probe_isapnp(&io) < 0) {
 			printk(KERN_ERR "AWE32: No ISAPnP cards found\n");
-			return 0;
+			if (isapnp != -1)
+			  return 0;
+		} else {
+			setup_ports(io, 0, 0);
+			return 1;
 		}
-		setup_ports(io, 0, 0);
-		return 1;
 	}
 #endif /* isapnp */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- v2.4.2/linux/drivers/sound/cs46xx.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/cs46xx.c	Tue Mar 20 12:04:58 2001
@@ -4020,8 +4020,8 @@
 	}
 	memset(card, 0, sizeof(*card));
 
-	card->ba0_addr = pci_dev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK;
-	card->ba1_addr = pci_dev->resource[1].start&PCI_BASE_ADDRESS_MEM_MASK;
+	card->ba0_addr = pci_resource_start(pci_dev, 0);
+	card->ba1_addr = pci_resource_start(pci_dev, 1);
 	card->pci_dev = pci_dev;
 	card->irq = pci_dev->irq;
 	card->magic = CS_CARD_MAGIC;
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c
--- v2.4.2/linux/drivers/sound/emu10k1/main.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/emu10k1/main.c	Tue Mar 20 12:04:59 2001
@@ -619,7 +619,7 @@
 	}
 	memset(card, 0, sizeof(struct emu10k1_card));
 
-	if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) {
+	if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) {
 		printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n");
 		kfree(card);
 		return -ENODEV;
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.4.2/linux/drivers/sound/es1370.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/es1370.c	Tue Mar 20 12:04:58 2001
@@ -2524,9 +2524,10 @@
 		return -1;
 	if (pcidev->irq == 0) 
 		return -1;
-	if (!pci_dma_supported(pcidev, 0xffffffff)) {
+	i = pci_set_dma_mask(pcidev, 0xffffffff);
+	if (i) {
 		printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
-		return -1;
+		return i;
 	}
 	if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
 		printk(KERN_WARNING "es1370: out of memory\n");
@@ -2608,7 +2609,6 @@
 	set_fs(fs);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
-	pcidev->dma_mask = 0xffffffff;
 	/* put it into driver list */
 	list_add_tail(&s->devs, &devs);
 	/* increment devindex */
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.4.2/linux/drivers/sound/es1371.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/es1371.c	Tue Mar 20 12:04:58 2001
@@ -2737,9 +2737,10 @@
 		return -1;
 	if (pcidev->irq == 0) 
 		return -1;
-	if (!pci_dma_supported(pcidev, 0xffffffff)) {
+	i = pci_set_dma_mask(pcidev, 0xffffffff);
+	if (i) {
 		printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n");
-		return -1;
+		return i;
 	}
 	if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) {
 		printk(KERN_WARNING PFX "out of memory\n");
@@ -2874,7 +2875,6 @@
 	outl(cssr, s->io+ES1371_REG_STATUS);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
-	pcidev->dma_mask = 0xffffffff;
 	/* put it into driver list */
 	list_add_tail(&s->devs, &devs);
 	/* increment devindex */
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.4.2/linux/drivers/sound/esssolo1.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/esssolo1.c	Tue Mar 20 12:04:59 2001
@@ -2244,7 +2244,6 @@
 {
 	struct solo1_state *s;
 	struct pm_dev *pmdev;
-	dma_addr_t dma_mask;
 
 	if (!RSRCISIOREGION(pcidev, 0) ||
 	    !RSRCISIOREGION(pcidev, 1) ||
@@ -2253,14 +2252,16 @@
 		return -1;
 	if (pcidev->irq == 0)
 		return -1;
-	if (pci_dma_supported(pcidev, 0x00ffffff)) {
-		dma_mask = 0x00ffffff; /* this enables playback and recording */
-	} else if (pci_dma_supported(pcidev, 0xffffffff)) {
-		dma_mask = 0xffffffff; /* this enables only playback, as the recording BMDMA can handle only 24bits  */
-	} else {
+
+	/* Recording requires 24-bit DMA, so attempt to set dma mask
+	 * to 24 bits first, then 32 bits (playback only) if that fails.
+	 */
+	if (pci_set_dma_mask(pcidev, 0x00ffffff) &&
+	    pci_set_dma_mask(pcidev, 0xffffffff)) {
 		printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
 		return -1;
 	}
+
 	if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
 		printk(KERN_WARNING "solo1: out of memory\n");
 		return -1;
@@ -2318,7 +2319,6 @@
 		goto err;
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
-	pcidev->dma_mask = dma_mask;
 	/* put it into driver list */
 	list_add_tail(&s->devs, &devs);
 
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v2.4.2/linux/drivers/sound/gus_midi.c	Sun Nov 12 20:35:35 2000
+++ linux/drivers/sound/gus_midi.c	Tue Mar  6 19:28:32 2001
@@ -15,7 +15,7 @@
  *		Added __init to gus_midi_init()
  */
 
-#include "linux/init.h"
+#include <linux/init.h>
 #include "sound_config.h"
 
 #include "gus.h"
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.4.2/linux/drivers/sound/i810_audio.c	Wed Feb 21 18:20:34 2001
+++ linux/drivers/sound/i810_audio.c	Tue Mar  6 19:44:37 2001
@@ -194,8 +194,12 @@
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
 #define NR_AC97		2
 
+/* 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 */
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
+/* values are one less than might be expected */
+static const unsigned sample_shift[] = { -1, 0, 0, 1 };
 
 enum {
 	ICH82801AA = 0,
@@ -246,7 +250,8 @@
 		unsigned char fmt, enable;
 
 		/* hardware channel */
-		struct i810_channel *channel;
+		struct i810_channel *read_channel;
+		struct i810_channel *write_channel;
 
 		/* OSS buffer management stuff */
 		void *rawbuf;
@@ -258,7 +263,7 @@
 		/* our buffer acts like a circular ring */
 		unsigned hwptr;		/* where dma last started, updated by update_ptr */
 		unsigned swptr;		/* where driver last clear/filled, updated by read/write */
-		int count;		/* bytes to be comsumed or been generated by dma machine */
+		int count;		/* bytes to be consumed or been generated by dma machine */
 		unsigned total_bytes;	/* total bytes dmaed by hardware */
 
 		unsigned error;		/* number of over/underruns */
@@ -313,6 +318,7 @@
 	/* Function support */
 	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
 	struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *);
+	struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *);
 	void (*free_pcm_channel)(struct i810_card *, int chan);
 };
 
@@ -356,9 +362,6 @@
 	if(card->channel[1].used==1)
 		return NULL;
 	card->channel[1].used=1;
-	card->channel[1].offset = 0;
-	card->channel[1].port = 0x10;
-	card->channel[1].num=1;
 	return &card->channel[1];
 }
 
@@ -367,12 +370,17 @@
 	if(card->channel[0].used==1)
 		return NULL;
 	card->channel[0].used=1;
-	card->channel[0].offset = 0;
-	card->channel[0].port = 0x00;
-	card->channel[1].num=0;
 	return &card->channel[0];
 }
 
+static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card)
+{
+	if(card->channel[2].used==1)
+		return NULL;
+	card->channel[2].used=1;
+	return &card->channel[2];
+}
+
 static void i810_free_pcm_channel(struct i810_card *card, int channel)
 {
 	card->channel[channel].used=0;
@@ -382,7 +390,7 @@
 static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate)
 {	
 	struct dmabuf *dmabuf = &state->dmabuf;
-	u32 dacp;
+	u32 dacp, new_rate;
 	struct ac97_codec *codec=state->card->ac97_codec[0];
 	
 	if(!(state->card->ac97_features&0x0001))
@@ -395,6 +403,7 @@
 		rate = 48000;
 	if (rate < 8000)
 		rate = 8000;
+	dmabuf->rate = rate;
 		
 	/*
 	 *	Adjust for misclocked crap
@@ -402,12 +411,6 @@
 	 
 	rate = ( rate * clocking)/48000;
 	
-	/* Analog codecs can go lower via magic registers but others
-	   might not */
-	   
-	if(rate < 8000)
-		rate = 8000;
-
 	if(rate != i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE))
 	{
 		/* Power down the DAC */
@@ -415,24 +418,25 @@
 		i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0200);
 		/* Load the rate and read the effective rate */
 		i810_ac97_set(codec, AC97_PCM_FRONT_DAC_RATE, rate);
-		rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
+		new_rate=i810_ac97_get(codec, AC97_PCM_FRONT_DAC_RATE);
 		/* Power it back up */
 		i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+		if(new_rate != rate) {
+			dmabuf->rate = (new_rate * 48000)/clocking;
+			rate = new_rate;
+		}
 	}
-	rate=(rate * 48000) / clocking;
-	dmabuf->rate = rate;
 #ifdef DEBUG
-	printk("i810_audio: called i810_set_dac_rate : rate = %d\n", rate);
+	printk("i810_audio: called i810_set_dac_rate : rate = %d/%d\n", dmabuf->rate, rate);
 #endif
-
-	return rate;
+	return dmabuf->rate;
 }
 
 /* set recording sample rate */
 static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	u32 dacp;
+	u32 dacp, new_rate;
 	struct ac97_codec *codec=state->card->ac97_codec[0];
 	
 	if(!(state->card->ac97_features&0x0001))
@@ -445,6 +449,7 @@
 		rate = 48000;
 	if (rate < 8000)
 		rate = 8000;
+	dmabuf->rate = rate;
 
 	/*
 	 *	Adjust for misclocked crap
@@ -452,12 +457,6 @@
 	 
 	rate = ( rate * clocking)/48000;
 	
-	/* Analog codecs can go lower via magic registers but others
-	   might not */
-	   
-	if(rate < 8000)
-		rate = 8000;
-
 	if(rate != i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE))
 	{
 		/* Power down the ADC */
@@ -465,16 +464,18 @@
 		i810_ac97_set(codec, AC97_POWER_CONTROL, dacp|0x0100);
 		/* Load the rate and read the effective rate */
 		i810_ac97_set(codec, AC97_PCM_LR_DAC_RATE, rate);
-		rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
+		new_rate=i810_ac97_get(codec, AC97_PCM_LR_DAC_RATE);
 		/* Power it back up */
 		i810_ac97_set(codec, AC97_POWER_CONTROL, dacp);
+		if(new_rate != rate) {
+			dmabuf->rate = (new_rate * 48000)/clocking;
+			rate = new_rate;
+		}
 	}
-	rate = (rate * 48000) / clocking;
-	dmabuf->rate = rate;
 #ifdef DEBUG
-	printk("i810_audio: called i810_set_adc_rate : rate = %d\n", rate);
+	printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate);
 #endif
-	return rate;
+	return dmabuf->rate;
 }
 
 /* prepare channel attributes for playback */ 
@@ -508,10 +509,18 @@
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
 	unsigned int civ, offset;
-	struct i810_channel *c = dmabuf->channel;
+	struct i810_channel *c;
 	
 	if (!dmabuf->enable)
 		return 0;
+	if (dmabuf->enable & DAC_RUNNING)
+		c = dmabuf->write_channel;
+	else if (dmabuf->enable & ADC_RUNNING)
+		c = dmabuf->read_channel;
+	else {
+		printk("i810_audio: invalid dmabuf->enable state in get_dma_addr\n");
+		return 0;
+	}
 	do {
 		civ = inb(state->card->iobase+c->port+OFF_CIV);
 		offset = (civ + 1) * (dmabuf->dmasize/SG_LEN) -
@@ -523,12 +532,17 @@
 	return offset;
 }
 
-static void resync_dma_ptrs(struct i810_state *state)
+static void resync_dma_ptrs(struct i810_state *state, int rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	struct i810_channel *c = dmabuf->channel;
+	struct i810_channel *c;
 	int offset;
-	
+
+	if(rec) {
+		c = dmabuf->read_channel;
+	} else {
+		c = dmabuf->write_channel;
+	}
 	offset = inb(state->card->iobase+c->port+OFF_CIV);
 	offset *= (dmabuf->dmasize/SG_LEN);
 	
@@ -597,23 +611,20 @@
 
 	spin_lock_irqsave(&card->lock, flags);
 	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
-		if(!(dmabuf->enable&DAC_RUNNING))
-		{
-			dmabuf->enable |= DAC_RUNNING;
-			outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR);
-		}
+		dmabuf->enable |= DAC_RUNNING;
+		outb((1<<4) | 1<<2 | 1, card->iobase + PO_CR);
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
 }
 
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
+#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
 
 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */
 static int alloc_dmabuf(struct i810_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	void *rawbuf;
+	void *rawbuf= NULL;
 	int order;
 	struct page *page, *pend;
 
@@ -664,6 +675,7 @@
 static int prog_dmabuf(struct i810_state *state, unsigned rec)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
+	struct i810_channel *c;
 	struct sg_item *sg;
 	unsigned bytepersec;
 	unsigned bufsize;
@@ -673,7 +685,7 @@
 	int i;
 
 	spin_lock_irqsave(&state->card->lock, flags);
-	resync_dma_ptrs(state);
+	resync_dma_ptrs(state, rec);
 	dmabuf->total_bytes = 0;
 	dmabuf->count = dmabuf->error = 0;
 	spin_unlock_irqrestore(&state->card->lock, flags);
@@ -684,7 +696,8 @@
 			return ret;
 
 	/* FIXME: figure out all this OSS fragment stuff */
-	bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];
+	/* sample_shift is for 16 byte samples, add an extra shift for bytes */
+	bytepersec = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1);
 	bufsize = PAGE_SIZE << dmabuf->buforder;
 	if (dmabuf->ossfragshift) {
 		if ((1000 << dmabuf->ossfragshift) < bytepersec)
@@ -709,44 +722,52 @@
 	memset(dmabuf->rawbuf, (dmabuf->fmt & I810_FMT_16BIT) ? 0 : 0x80,
 	       dmabuf->dmasize);
 
-	/*
-	 *	Now set up the ring 
-	 */
-
-	sg=&dmabuf->channel->sg[0];
 	fragsize = bufsize / SG_LEN;
-	
 	/*
-	 *	Load up 32 sg entries and take an interrupt at half
-	 *	way (we might want more interrupts later..) 
+	 *	Now set up the ring 
 	 */
+	if(dmabuf->read_channel)
+		c = dmabuf->read_channel;
+	else
+		c = dmabuf->write_channel;
+	while(c != NULL) {
+		sg=&c->sg[0];
+		/*
+		 *	Load up 32 sg entries and take an interrupt at half
+		 *	way (we might want more interrupts later..) 
+		 */
 	  
-	for(i=0;i<32;i++)
-	{
-		sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i);
-		sg->control=(fragsize>>1);
-		sg->control|=CON_IOC;
-		sg++;
-	}
+		for(i=0;i<32;i++)
+		{
+			sg->busaddr=virt_to_bus(dmabuf->rawbuf+fragsize*i);
+			sg->control=(fragsize>>sample_shift[dmabuf->fmt]);
+			sg->control|=CON_IOC;
+			sg++;
+		}
+		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(31, state->card->iobase+c->port+OFF_LVI);
+		outb(0, state->card->iobase+c->port+OFF_CIV);
 
-	spin_lock_irqsave(&state->card->lock, flags);
-	outb(2, state->card->iobase+dmabuf->channel->port+OFF_CR);   /* reset DMA machine */
-	outl(virt_to_bus(&dmabuf->channel->sg[0]), state->card->iobase+dmabuf->channel->port+OFF_BDBAR);
-	outb(16, state->card->iobase+dmabuf->channel->port+OFF_LVI);
-	outb(0, state->card->iobase+dmabuf->channel->port+OFF_CIV);
+		if (c == dmabuf->read_channel) {
+			i810_rec_setup(state);
+		} else {
+			i810_play_setup(state);
+		}
+		spin_unlock_irqrestore(&state->card->lock, flags);
 
-	if (rec) {
-		i810_rec_setup(state);
-	} else {
-		i810_play_setup(state);
+		if(c != dmabuf->write_channel)
+			c = dmabuf->write_channel;
+		else
+			c = NULL;
 	}
-	spin_unlock_irqrestore(&state->card->lock, flags);
-
+	
 	/* set the ready flag for the dma buffer */
 	dmabuf->ready = 1;
 
 #ifdef DEBUG
-	printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, "
+	printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, "
 	       "fragsize = %d dmasize = %d\n",
 	       dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
 	       dmabuf->fragsize, dmabuf->dmasize);
@@ -912,7 +933,6 @@
 {
 	int i;
 
-//	printk("CHANNEL IRQ .. ");	
 	for(i=0;i<NR_HW_CH;i++)
 	{
 		struct i810_state *state = card->states[i];
@@ -924,38 +944,35 @@
 			continue;
 		if(!state->dmabuf.ready)
 			continue;
-		c=state->dmabuf.channel;
+		if(state->dmabuf.enable & DAC_RUNNING)
+			c=state->dmabuf.write_channel;
+		else
+			c=state->dmabuf.read_channel;
 		
 		port+=c->port;
 		
-//		printk("PORT %lX (", port);
-		
 		status = inw(port + OFF_SR);
 		
-//		printk("ST%d ", status);
-		
-		if(status & DMA_INT_LVI)
-		{
-			/* Back to the start */
-//			printk("LVI - STOP");
-			outb((inb(port+OFF_CIV)-1)&31, port+OFF_LVI);
-			i810_update_ptr(state);
-			outb(0, port + OFF_CR);
-		}
 		if(status & DMA_INT_COMPLETE)
 		{
 			int x;
 			/* Keep the card chasing its tail */
 			outb(x=((inb(port+OFF_CIV)-1)&31), port+OFF_LVI);
 			i810_update_ptr(state);
-//			printk("COMP%d ",x);
 		}
-//		printk(")");
+		if(status & DMA_INT_LVI)
+		{
+			/* Back to the start */
+			i810_update_ptr(state);
+			outb(0, port + OFF_CR);
+		}
 		outw(status & DMA_INT_MASK, port + OFF_SR);
 	}
-//	printk("\n");
 }
 
+static u32 jiff = 0;
+static u32 jiff_count = 0;
+
 static void i810_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct i810_card *card = (struct i810_card *)dev_id;
@@ -964,13 +981,13 @@
 	spin_lock(&card->lock);
 
 	status = inl(card->iobase + GLOB_STA);
+
 	if(!(status & INT_MASK)) 
 	{
 		spin_unlock(&card->lock);
 		return;  /* not for us */
 	}
 
-//	printk("Interrupt %X: ", status);
 	if(status & (INT_PO|INT_PI|INT_MC))
 		i810_channel_interrupt(card);
 
@@ -1003,6 +1020,15 @@
 		return -ESPIPE;
 	if (dmabuf->mapped)
 		return -ENXIO;
+	if (dmabuf->enable & DAC_RUNNING)
+		return -ENODEV;
+	if (!dmabuf->read_channel) {
+		dmabuf->ready = 0;
+		dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
+		if (!dmabuf->read_channel) {
+			return -ENODEV;
+		}
+	}
 	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
@@ -1100,6 +1126,14 @@
 		return -ESPIPE;
 	if (dmabuf->mapped)
 		return -ENXIO;
+	if (dmabuf->enable & ADC_RUNNING)
+		return -ENODEV;
+	if (!dmabuf->write_channel) {
+		dmabuf->ready = 0;
+		dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
+		if(!dmabuf->write_channel)
+			return -ENODEV;
+	}
 	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
@@ -1132,8 +1166,8 @@
 				return ret;
 			}
 			/* Not strictly correct but works */
-			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
-			tmo >>= sample_shift[dmabuf->fmt];
+			tmo = dmabuf->rate << (sample_shift[dmabuf->fmt] + 1);
+			tmo = dmabuf->dmasize * HZ / tmo;
 			/* There are two situations when sleep_on_timeout returns, one is when
 			   the interrupt is serviced correctly and the process is waked up by
 			   ISR ON TIME. Another is when timeout is expired, which means that
@@ -1187,22 +1221,27 @@
 	unsigned int mask = 0;
 
 	if (file->f_mode & FMODE_WRITE) {
+		if (!dmabuf->write_channel)
+			return 0;
 		if (!dmabuf->ready && prog_dmabuf(state, 0))
 			return 0;
 		poll_wait(file, &dmabuf->wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
+	} else { 
+	// don't do both read and write paths or we won't get woke up properly
+	// when we have a file with both permissions
+		if (!dmabuf->read_channel)
+			return 0;
 		if (!dmabuf->ready && prog_dmabuf(state, 1))
 			return 0;
 		poll_wait(file, &dmabuf->wait, wait);
 	}
 	spin_lock_irqsave(&state->card->lock, flags);
 	i810_update_ptr(state);
-	if (file->f_mode & FMODE_READ) {
+	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
 		if (dmabuf->count >= (signed)dmabuf->fragsize)
 			mask |= POLLIN | POLLRDNORM;
 	}
-	if (file->f_mode & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING) {
 		if (dmabuf->mapped) {
 			if (dmabuf->count >= (signed)dmabuf->fragsize)
 				mask |= POLLOUT | POLLWRNORM;
@@ -1223,11 +1262,19 @@
 	int ret = -EINVAL;
 	unsigned long size;
 
+	/* 
+	 *	Until we figure out a few problems
+	 */
+	 
 	lock_kernel();
 	if (vma->vm_flags & VM_WRITE) {
+		if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL)
+			goto out;
 		if ((ret = prog_dmabuf(state, 0)) != 0)
 			goto out;
 	} else if (vma->vm_flags & VM_READ) {
+		if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL)
+			goto out;
 		if ((ret = prog_dmabuf(state, 1)) != 0)
 			goto out;
 	} else 
@@ -1245,6 +1292,9 @@
 		goto out;
 	dmabuf->mapped = 1;
 	ret = 0;
+#ifdef DEBUG
+	printk("i810_audio: mmap'ed %d bytes of data space\n", size);
+#endif
 out:
 	unlock_kernel();
 	return ret;
@@ -1277,14 +1327,14 @@
 			stop_dac(state);
 			synchronize_irq();
 			dmabuf->ready = 0;
-			resync_dma_ptrs(state);
+			resync_dma_ptrs(state, 0);
 			dmabuf->swptr = dmabuf->hwptr = 0;
 			dmabuf->count = dmabuf->total_bytes = 0;
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(state);
 			synchronize_irq();
-			resync_dma_ptrs(state);
+			resync_dma_ptrs(state, 1);
 			dmabuf->ready = 0;
 			dmabuf->swptr = dmabuf->hwptr = 0;
 			dmabuf->count = dmabuf->total_bytes = 0;
@@ -1325,23 +1375,23 @@
 		if (file->f_mode & FMODE_WRITE) {
 			stop_dac(state);
 			dmabuf->ready = 0;
-			dmabuf->fmt = I810_FMT_STEREO;
+			dmabuf->fmt |= I810_FMT_STEREO;
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(state);
 			dmabuf->ready = 0;
-			dmabuf->fmt = I810_FMT_STEREO;
+			dmabuf->fmt |= I810_FMT_STEREO;
 		}
 		return 0;
 
 	case SNDCTL_DSP_GETBLKSIZE:
 		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf(state, 0)))
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
 				return val;
 			return put_user(dmabuf->fragsize, (int *)arg);
 		}
 		if (file->f_mode & FMODE_READ) {
-			if ((val = prog_dmabuf(state, 1)))
+			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
 				return val;
 			return put_user(dmabuf->fragsize, (int *)arg);
 		}
@@ -1356,10 +1406,12 @@
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(state);
 				dmabuf->ready = 0;
+				dmabuf->fmt |= I810_FMT_16BIT;
 			}
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(state);
 				dmabuf->ready = 0;
+				dmabuf->fmt |= I810_FMT_16BIT;
 			}
 		}
 		return put_user(AFMT_S16_LE, (int *)arg);
@@ -1391,6 +1443,7 @@
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		dmabuf->subdivision = val;
+		dmabuf->ready = 0;
 		return 0;
 
 	case SNDCTL_DSP_SETFRAGMENT:
@@ -1405,13 +1458,14 @@
 			dmabuf->ossfragshift = 15;
 		if (dmabuf->ossmaxfrags < 4)
 			dmabuf->ossmaxfrags = 4;
+		dmabuf->ready = 0;
 
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
@@ -1425,7 +1479,7 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)
+		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
 			return val;
 		spin_lock_irqsave(&state->card->lock, flags);
 		i810_update_ptr(state);
@@ -1446,30 +1500,40 @@
 
 	case SNDCTL_DSP_GETTRIGGER:
 		val = 0;
-		if (file->f_mode & FMODE_READ && dmabuf->enable)
+		if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING)
 			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && dmabuf->enable)
+		if (file->f_mode & FMODE_WRITE && dmabuf->enable & DAC_RUNNING)
 			val |= PCM_ENABLE_OUTPUT;
 		return put_user(val, (int *)arg);
 
 	case SNDCTL_DSP_SETTRIGGER:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-					return ret;
-				start_adc(state);
-			} else
-				stop_adc(state);
+		if (file->f_mode & FMODE_READ && val & PCM_ENABLE_INPUT) {
+			if (dmabuf->enable & DAC_RUNNING)
+				return -ENODEV;
+			if (!dmabuf->read_channel) {
+				dmabuf->ready = 0;
+				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
+				if (!dmabuf->read_channel)
+					return -ENODEV;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
+				return ret;
+			start_adc(state);
 		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-					return ret;
-				start_dac(state);
-			} else
-				stop_dac(state);
+		if (file->f_mode & FMODE_WRITE && val & PCM_ENABLE_OUTPUT) {
+			if (dmabuf->enable & ADC_RUNNING)
+				return -ENODEV;
+			if (!dmabuf->write_channel) {
+				dmabuf->ready = 0;
+				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
+				if (!dmabuf->write_channel)
+					return -ENODEV;
+			}
+			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
+				return ret;
+			start_dac(state);
 		}
 		return 0;
 
@@ -1558,18 +1622,6 @@
 		return -ENODEV;
 
  found_virt:
-	/* found a free virtual channel, allocate hardware channels */
-	if(file->f_mode & FMODE_READ)
-		dmabuf->channel = card->alloc_rec_pcm_channel(card);
-	else
-		dmabuf->channel = card->alloc_pcm_channel(card);
-		
-	if (dmabuf->channel == NULL) {
-		kfree (card->states[i]);
-		card->states[i] = NULL;;
-		return -ENODEV;
-	}
-
 	/* initialize the virtual channel */
 	state->virt = i;
 	state->card = card;
@@ -1578,28 +1630,34 @@
 	init_MUTEX(&state->open_sem);
 	file->private_data = state;
 
+	/* allocate hardware channels */
+	if(file->f_mode & FMODE_READ) {
+		if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
+			kfree (card->states[i]);
+			card->states[i] = NULL;;
+			return -ENODEV;
+		}
+		i810_set_adc_rate(state, 48000);
+	}
+	if(file->f_mode & FMODE_WRITE) {
+		if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
+			kfree (card->states[i]);
+			card->states[i] = NULL;;
+			return -ENODEV;
+		}
+		i810_set_dac_rate(state, 48000);
+	}
+		
 	down(&state->open_sem);
 
 	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
 	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
 	   /dev/dspW will accept 16-bits sample */
-	if (file->f_mode & FMODE_WRITE) {
-		dmabuf->fmt &= ~I810_FMT_MASK;
-		dmabuf->fmt |= I810_FMT_16BIT;
-		dmabuf->ossfragshift = 0;
-		dmabuf->ossmaxfrags  = 0;
-		dmabuf->subdivision  = 0;
-		i810_set_dac_rate(state, 48000);
-	}
-
-	if (file->f_mode & FMODE_READ) {
-		dmabuf->fmt &= ~I810_FMT_MASK;
-		dmabuf->fmt |= I810_FMT_16BIT;
-		dmabuf->ossfragshift = 0;
-		dmabuf->ossmaxfrags  = 0;
-		dmabuf->subdivision  = 0;
-		i810_set_adc_rate(state, 48000);
-	}
+	dmabuf->fmt &= ~I810_FMT_MASK;
+	dmabuf->fmt |= I810_FMT_16BIT;
+	dmabuf->ossfragshift = 0;
+	dmabuf->ossmaxfrags  = 0;
+	dmabuf->subdivision  = 0;
 
 	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&state->open_sem);
@@ -1614,29 +1672,33 @@
 
 	lock_kernel();
 	if (file->f_mode & FMODE_WRITE) {
-		i810_clear_tail(state);
-		drain_dac(state, file->f_flags & O_NONBLOCK);
 	}
 
 	/* stop DMA state machine and free DMA buffers/channels */
 	down(&state->open_sem);
 
-	if (file->f_mode & FMODE_WRITE) {
+	if (dmabuf->enable & DAC_RUNNING) {
+		i810_clear_tail(state);
+		drain_dac(state, file->f_flags & O_NONBLOCK);
 		stop_dac(state);
 		dealloc_dmabuf(state);
-		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
 	}
-	if (file->f_mode & FMODE_READ) {
+	if(dmabuf->enable & ADC_RUNNING) {
 		stop_adc(state);
 		dealloc_dmabuf(state);
-		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		state->card->free_pcm_channel(state->card, dmabuf->write_channel->num);
+	}
+	if (file->f_mode & FMODE_READ) {
+		state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
 	}
 
 	/* we're covered by the open_sem */
 	up(&state->open_sem);
 	
-	kfree(state->card->states[state->virt]);
 	state->card->states[state->virt] = NULL;
+	kfree(state);
 	unlock_kernel();
 
 	return 0;
@@ -1688,16 +1750,11 @@
 	for (card = devs; card != NULL; card = card->next)
 		for (i = 0; i < NR_AC97; i++)
 			if (card->ac97_codec[i] != NULL &&
-			    card->ac97_codec[i]->dev_mixer == minor)
-				goto match;
-
-	if (!card)
-		return -ENODEV;
-
- match:
-	file->private_data = card->ac97_codec[i];
-
-	return 0;
+			    card->ac97_codec[i]->dev_mixer == minor) {
+				file->private_data = card->ac97_codec[i];
+				return 0;
+			}
+	return -ENODEV;
 }
 
 static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
@@ -1788,10 +1845,6 @@
 			printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n");
 		else
 		{
-			/* Enable variable rate mode */
-			i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
-			i810_ac97_set(codec,AC97_EXTENDED_STATUS,
-				i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);
 			/* power up everything, modify this when implementing power saving */
 			i810_ac97_set(codec, AC97_POWER_CONTROL,
 				i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
@@ -1804,6 +1857,11 @@
 				schedule_timeout(HZ/20);
 			}
 
+			/* Enable variable rate mode */
+			i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
+			i810_ac97_set(codec,AC97_EXTENDED_STATUS,
+				i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800);
+
 			if(!(i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1))
 			{
 				printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n");
@@ -1865,7 +1923,17 @@
 
 	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;
 
 	/* claim our iospace and irq */
 	request_region(card->iobase, 64, card_names[pci_id->driver_data]);
@@ -1938,20 +2006,86 @@
 	remove:		i810_remove,
 };
 
+static void __init i810_configure_clocking (void)
+{
+	struct i810_card *card;
+	struct i810_state *state;
+	struct dmabuf *dmabuf;
+	unsigned int i, offset, new_offset;
+	unsigned long flags;
+
+	card = devs;
+	/* We could try to set the clocking for multiple cards, but can you even have
+	 * more than one i810 in a machine?  Besides, clocking is global, so unless
+	 * someone actually thinks more than one i810 in a machine is possible and
+	 * decides to rewrite that little bit, setting the rate for more than one card
+	 * is a waste of time.
+	 */
+	if(card != NULL) {
+		state = card->states[0] = (struct i810_state *)
+					kmalloc(sizeof(struct i810_state), GFP_KERNEL);
+		if (state == NULL)
+			return;
+		memset(state, 0, sizeof(struct i810_state));
+		dmabuf = &state->dmabuf;
+
+		dmabuf->write_channel = card->alloc_pcm_channel(card);
+		state->virt = 0;
+		state->card = card;
+		state->magic = I810_STATE_MAGIC;
+		init_waitqueue_head(&dmabuf->wait);
+		init_MUTEX(&state->open_sem);
+		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
+		i810_set_dac_rate(state, 48000);
+		if(prog_dmabuf(state, 0) != 0) {
+			goto config_out_nodmabuf;
+		}
+		if(dmabuf->dmasize < 16384) {
+			goto config_out;
+		}
+		dmabuf->count = dmabuf->dmasize;
+		save_flags(flags);
+		cli();
+		start_dac(state);
+		offset = i810_get_dma_addr(state);
+		mdelay(50);
+		new_offset = i810_get_dma_addr(state);
+		stop_dac(state);
+		outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR);
+		restore_flags(flags);
+		i = new_offset - offset;
+		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
+		i = i / 4 * 20;
+		if (i > 48500 || i < 47500) {
+			clocking = clocking * clocking / i;
+			printk("i810_audio: setting clocking to %d to compensate\n", clocking);
+		}
+config_out_nodmabuf:
+		dealloc_dmabuf(state);
+config_out:
+		state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num);
+		kfree(state);
+		card->states[0] = NULL;
+	}
+}
+
 static int __init i810_init_module (void)
 {
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
 
-	if(ftsodell==1)
-		clocking=41194;
-		
 	printk(KERN_INFO "Intel 810 + AC97 Audio, version "
 	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
 	if (!pci_register_driver(&i810_pci_driver)) {
 		pci_unregister_driver(&i810_pci_driver);
                 return -ENODEV;
+	}
+	if(ftsodell != 0) {
+		printk("i810_audio: ftsodell is now a deprecated option.\n");
+	}
+	if(clocking == 48000) {
+		i810_configure_clocking();
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.4.2/linux/drivers/sound/maestro.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/maestro.c	Fri Mar  2 11:12:11 2001
@@ -1427,7 +1427,7 @@
 			apu_set_register(ess, channel, 10, 0x8F08);
 	}
 	
-	/* clear WP interupts */
+	/* clear WP interrupts */
 	outw(1, ess->card->iobase+0x04);
 	/* enable WP ints */
 	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
@@ -1559,7 +1559,7 @@
 		apu_set_register(ess, channel, 11, route);
 	}
 	
-	/* clear WP interupts */
+	/* clear WP interrupts */
 	outw(1, ess->card->iobase+0x04);
 	/* enable WP ints */
 	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
@@ -3446,10 +3446,10 @@
 		printk(KERN_INFO "maestro: not attempting power management.\n");
 	else {
 		if(!parse_power(card,pcidev)) 
-			printk(KERN_INFO "maestro: no PCI power managment interface found.\n");
+			printk(KERN_INFO "maestro: no PCI power management interface found.\n");
 		else {
 			pci_read_config_dword(pcidev, card->power_regs, &n);
-			printk(KERN_INFO "maestro: PCI power managment capability: 0x%x\n",n>>16);
+			printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16);
 		}	
 	}
 
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- v2.4.2/linux/drivers/sound/maestro3.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/maestro3.c	Fri Mar  2 18:38:39 2001
@@ -28,6 +28,9 @@
  * Shouts go out to Mike "DJ XPCom" Ang.
  *
  * History
+ *  v1.22 - Feb 28 2001 - Zach Brown <zab@zabbo.net>
+ *   allocate mem at insmod/setup, rather than open
+ *   limit pci dma addresses to 28bit, thanks guys.
  *  v1.21 - Feb 04 2001 - Zach Brown <zab@zabbo.net>
  *   fix up really dumb notifier -> suspend oops
  *  v1.20 - Jan 30 2001 - Zach Brown <zab@zabbo.net>
@@ -150,7 +153,7 @@
 
 #define M_DEBUG 1
 
-#define DRIVER_VERSION      "1.21"
+#define DRIVER_VERSION      "1.22"
 #define M3_MODULE_NAME      "maestro3"
 #define PFX                 M3_MODULE_NAME ": "
 
@@ -330,6 +333,12 @@
 
 MODULE_DEVICE_TABLE (pci, m3_id_table);
 
+/*
+ * reports seem to indicate that the m3 is limited
+ * to 28bit bus addresses.  aaaargggh...
+ */
+#define M3_PCI_DMA_MASK 0x0fffffff
+
 static unsigned 
 ld2(unsigned int x)
 {
@@ -1943,6 +1952,9 @@
 static void
 free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
 {
+    if(db->rawbuf == NULL)
+        return;
+
     DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
 
     {
@@ -1967,7 +1979,7 @@
     int minor = MINOR(inode->i_rdev);
     struct m3_card *c;
     struct m3_state *s = NULL;
-    int i, ret = 0;
+    int i;
     unsigned char fmtm = ~0, fmts = 0;
     unsigned long flags;
 
@@ -2013,10 +2025,6 @@
     spin_lock_irqsave(&s->lock, flags);
 
     if (file->f_mode & FMODE_READ) {
-        if(allocate_dmabuf(s->card->pcidev, &(s->dma_adc)))  {
-            ret = -ENOMEM;
-            goto out;
-        }
         fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
         if ((minor & 0xf) == SND_DEV_DSP16)
             fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; 
@@ -2025,10 +2033,6 @@
         set_adc_rate(s, 8000);
     }
     if (file->f_mode & FMODE_WRITE) {
-        if(allocate_dmabuf(s->card->pcidev, &(s->dma_dac)))  {
-            ret = -ENOMEM;
-            goto out;
-        }
         fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
         if ((minor & 0xf) == SND_DEV_DSP16)
             fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
@@ -2040,7 +2044,6 @@
     s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 
     MOD_INC_USE_COUNT;
-out:
     up(&s->open_sem);
     spin_unlock_irqrestore(&s->lock, flags);
     return 0;
@@ -2064,7 +2067,6 @@
             m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
             nuke_lists(s->card, &(s->dma_dac));
         }
-        free_dmabuf(s->card->pcidev, &(s->dma_dac));
     }
     if (file->f_mode & FMODE_READ) {
         stop_adc(s);
@@ -2072,7 +2074,6 @@
             m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
             nuke_lists(s->card, &(s->dma_adc));
         }
-        free_dmabuf(s->card->pcidev, &(s->dma_adc));
     }
         
     s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
@@ -2594,8 +2595,8 @@
 
     DPRINTK(DPMOD, "in maestro_install\n");
 
-    if (!pci_dma_supported(pci_dev, 0xffffffff)) {
-        printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n");
+    if (!pci_dma_supported(pci_dev, M3_PCI_DMA_MASK)) {
+        printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n");
         return -ENODEV;
     }
         
@@ -2604,6 +2605,8 @@
 
     pci_set_master(pci_dev);
 
+    pci_dev->dma_mask = M3_PCI_DMA_MASK;
+
     if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) {
         printk(KERN_WARNING PFX "out of memory\n");
         return -ENOMEM;
@@ -2681,6 +2684,12 @@
         if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) {
             break;
         }
+
+        if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) ||
+                allocate_dmabuf(card->pcidev, &(s->dma_dac)))  { 
+            ret = -ENOMEM;
+            goto out;
+        }
     }
     
     if(request_irq(card->irq, m3_interrupt, SA_SHIRQ, card_names[card->card_type], card)) {
@@ -2734,8 +2743,12 @@
         for(i=0;i<NR_DSPS;i++)
         {
             struct m3_state *s = &card->channels[i];
-            if(s->dev_audio != -1)
-                unregister_sound_dsp(s->dev_audio);
+            if(s->dev_audio < 0)
+                continue;
+
+            unregister_sound_dsp(s->dev_audio);
+            free_dmabuf(card->pcidev, &s->dma_adc);
+            free_dmabuf(card->pcidev, &s->dma_dac);
         }
 
         release_region(card->iobase, 256);
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c
--- v2.4.2/linux/drivers/sound/msnd_pinnacle.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/msnd_pinnacle.c	Tue Mar  6 19:44:37 2001
@@ -47,7 +47,9 @@
 #include "sound_config.h"
 #include "sound_firmware.h"
 #ifdef MSND_CLASSIC
+# ifndef __alpha__
 #  define SLOWIO
+# endif
 #endif
 #include "msnd.h"
 #ifdef MSND_CLASSIC
@@ -1403,7 +1405,6 @@
 	return 0;
 }
 
-#ifdef MODULE
 static void __exit unload_multisound(void)
 {
 	release_region(dev.io, dev.numio);
@@ -1412,7 +1413,6 @@
 	unregister_sound_dsp(dev.dsp_minor);
 	msnd_unregister(&dev);
 }
-#endif
 
 #ifndef MSND_CLASSIC
 
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c
--- v2.4.2/linux/drivers/sound/opl3sa2.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/opl3sa2.c	Fri Mar  2 18:38:39 2001
@@ -806,6 +806,16 @@
 
 
 #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
+
+struct isapnp_device_id isapnp_opl3sa2_list[] __initdata = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021),
+		NULL },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, isapnp_opl3sa2_list);
+
 static int __init opl3sa2_isapnp_probe(struct address_info* hw_cfg,
 				       struct address_info* mss_cfg,
 				       struct address_info* mpu_cfg,
@@ -908,13 +918,17 @@
 						  &cfg_mpu[card],
 						  card) < 0) {
 			if(!opl3sa2_cards_num)
-				printk(KERN_NOTICE "opl3sa2: No cards found\n");
-			break;
+				printk(KERN_INFO "opl3sa2: No PnP cards found\n");
+			if(io == -1)
+				break;
+			isapnp=0;
+			printk(KERN_INFO "opl3sa2: Search for a card at 0x%d.\n", io);
+			/* Fall through */
 		}
 #endif
 		/* If a user wants an I/O then assume they meant it */
 		
-		if(!isapnp && io == -1 ) {
+		if(!isapnp) {
 			if(io == -1 || irq == -1 || dma == -1 ||
 			   dma2 == -1 || mss_io == -1) {
 				printk(KERN_ERR
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/skeleton.c linux/drivers/sound/skeleton.c
--- v2.4.2/linux/drivers/sound/skeleton.c	Fri Aug 11 08:26:44 2000
+++ linux/drivers/sound/skeleton.c	Fri Mar  2 18:38:39 2001
@@ -4,7 +4,7 @@
  *	(c) 1998 Red Hat Software
  *
  *	This software may be used and distributed according to the 
- *	terms of the GNU Public License, incorporated herein by 
+ *	terms of the GNU General Public License, incorporated herein by 
  *	reference.
  *
  *	This example is designed to be built in the linux/drivers/sound
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.4.2/linux/drivers/sound/sonicvibes.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/sonicvibes.c	Tue Mar 20 12:04:59 2001
@@ -2478,7 +2478,7 @@
 		return -1;
 	if (pcidev->irq == 0)
 		return -1;
-	if (!pci_dma_supported(pcidev, 0x00ffffff)) {
+	if (pci_set_dma_mask(pcidev, 0x00ffffff)) {
 		printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
 		return -1;
 	}
@@ -2602,7 +2602,6 @@
 	set_fs(fs);
        /* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
-	pcidev->dma_mask = 0x00ffffff;
 	/* put it into driver list */
 	list_add_tail(&s->devs, &devs);
 	/* increment devindex */
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.4.2/linux/drivers/sound/trident.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/trident.c	Tue Mar 20 12:04:59 2001
@@ -13,6 +13,7 @@
  *	Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
  *	Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
  *	Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support 
+ *	Matt Wu <mattwu@acersoftech.com.cn> ALi 5451 Audio Core Support
  *
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -30,6 +31,12 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.14.7
+ *	Feb 06 2001 Matt Wu
+ *	Fix ac97 initialization
+ *	Fix bug: an extra tail will be played when playing
+ *	Jan 05 2001 Matt Wu
+ *	Implement multi-channels and S/PDIF in support for ALi 1535+
  *  v0.14.6 
  *	Nov 1 2000 Ching-Ling Lee
  *	Fix the bug of memory leak when swithing 5.1-channels to 2 channels.
@@ -140,12 +147,12 @@
 
 /* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
    have 2 SDATA_IN lines (currently) */
-#define NR_AC97		2
+#define NR_AC97		2	
 
 /* minor number of /dev/swmodem (temporary, experimental) */
 #define SND_DEV_SWMODEM	7
 
-static const unsigned ali_multi_channels_5_1[] = { ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL};
+static const unsigned ali_multi_channels_5_1[] = { /*ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL,*/ ALI_CENTER_CHANNEL, ALI_LEF_CHANNEL, ALI_SURR_LEFT_CHANNEL, ALI_SURR_RIGHT_CHANNEL};
 
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
@@ -312,6 +319,10 @@
 	struct trident_channel *(*alloc_rec_pcm_channel)(struct trident_card *);
 	void (*free_pcm_channel)(struct trident_card *, unsigned int chan);
 	void (*address_interrupt)(struct trident_card *);
+	
+	/* Add by Matt Wu 01-05-2001 for spdif in */
+	int multi_channel_use_count;
+	int rec_channel_use_count;
 };
 
 /* table to map from CHANNELMASK to channel attribute for SiS 7018 */
@@ -327,6 +338,11 @@
 	DSP_BIND_I2S, DSP_BIND_CENTER_LFE, DSP_BIND_SURR, DSP_BIND_SPDIF
 };
 
+/* Add by Matt Wu 01-05-2001 for spdif in */
+static int ali_close_multi_channels(void);
+static void ali_delay(struct trident_card *card,int interval);
+static void ali_detect_spdif_rate(struct trident_card *card);
+
 static struct trident_card *devs;
 
 static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
@@ -760,6 +776,8 @@
 static void trident_rec_setup(struct trident_state *state)
 {
 	u16 w;
+	u8  bval;
+
 	struct trident_card *card = state->card;
 	struct dmabuf *dmabuf = &state->dmabuf;
 	struct trident_channel *channel = dmabuf->channel;
@@ -794,6 +812,18 @@
 	channel->delta = compute_rate_rec(dmabuf->rate);
 	if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) && (channel->num == ALI_SPDIF_IN_CHANNEL)) {
 		rate = ali_get_spdif_in_rate(card);
+		if (rate == 0)
+		{
+			printk(KERN_WARNING "trident: ALi 5451 S/PDIF input setup error!\n");
+			rate = 48000;
+		}
+		bval = inb(TRID_REG(card,ALI_SPDIF_CTRL));
+		if (bval & 0x10)
+		{
+			outb(bval,TRID_REG(card,ALI_SPDIF_CTRL));
+			printk(KERN_WARNING "trident: cleared ALi 5451 S/PDIF parity error flag.\n");
+		}
+
 		if (rate != 48000)
 			channel->delta = ((rate << 12) / dmabuf->rate) & 0x0000ffff;
 	}
@@ -959,7 +989,7 @@
 static int alloc_dmabuf(struct trident_state *state)
 {
 	struct dmabuf *dmabuf = &state->dmabuf;
-	void *rawbuf;
+	void *rawbuf=NULL;
 	int order;
 	struct page *page, *pend;
 
@@ -1138,11 +1168,13 @@
 		len = dmabuf->dmasize - swptr;
 
 	memset(dmabuf->rawbuf + swptr, silence, len);
-
-	spin_lock_irqsave(&state->card->lock, flags);
-	dmabuf->swptr += len;
-	dmabuf->count += len;
-	spin_unlock_irqrestore(&state->card->lock, flags);
+	if(state->card->pci_id != PCI_DEVICE_ID_ALI_5451)
+	{
+		spin_lock_irqsave(&state->card->lock, flags);
+		dmabuf->swptr += len;
+		dmabuf->count += len;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+	}
 
 	/* restart the dma machine in case it is halted */
 	start_dac(state);
@@ -1155,6 +1187,7 @@
 	unsigned long flags;
 	unsigned long tmo;
 	int count;
+	unsigned long diff = 0;
 
 	if (dmabuf->mapped || !dmabuf->ready)
 		return 0;
@@ -1183,10 +1216,19 @@
 
 		/* No matter how much data left in the buffer, we have to wait untill
 		   CSO == ESO/2 or CSO == ESO when address engine interrupts */
-		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
+	 	if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)
+		{	
+			diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize ;
+			diff = diff % (dmabuf->dmasize);
+			tmo  = (diff * HZ) / dmabuf->rate;
+		}
+		else
+		{
+			tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
+		}
 		tmo >>= sample_shift[dmabuf->fmt];
+//		printk("trident: diff=%d count= %d/%d total=%d tmo=%d hwptr=%d swptr=%d curptr=%d\n",diff,dmabuf->count,dmabuf->dmasize,dmabuf->total_bytes,tmo,dmabuf->hwptr,dmabuf->swptr,trident_get_dma_addr(state));
 		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
-			printk(KERN_ERR "trident: drain_dac, dma timeout?\n");
 			break;
 		}
 	}
@@ -1412,7 +1454,7 @@
 				if (!ret) ret = -EAGAIN;
 				return ret;
 			}
-			/* No matter how much space left in the buffer, we have to wait untill
+			/* No matter how much space left in the buffer, we have to wait until
 			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
 			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
 			tmo >>= sample_shift[dmabuf->fmt];
@@ -1430,7 +1472,7 @@
 				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
 				       dmabuf->hwptr, dmabuf->swptr);
 #endif
-				/* a buffer overrun, we delay the recovery untill next time the
+				/* a buffer overrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have space to record */
 			}
 			if (signal_pending(current)) {
@@ -1512,7 +1554,7 @@
 				if (!ret) ret = -EAGAIN;
 				return ret;
 			}
-			/* No matter how much data left in the buffer, we have to wait untill
+			/* No matter how much data left in the buffer, we have to wait until
 			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
 			lock_set_fmt(state);
 			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
@@ -1532,7 +1574,7 @@
 				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
 				       dmabuf->hwptr, dmabuf->swptr);
 #endif
-				/* a buffer underrun, we delay the recovery untill next time the
+				/* a buffer underrun, we delay the recovery until next time the
 				   while loop begin and we REALLY have data to play */
 			}
 			if (signal_pending(current)) {
@@ -1671,6 +1713,8 @@
 	count_info cinfo;
 	int val, mapped, ret;
 
+	struct trident_card *card = state->card;
+
 	VALIDATE_STATE(state);
 	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||
 		((file->f_mode & FMODE_READ) && dmabuf->mapped);
@@ -1807,17 +1851,32 @@
 					state->chans_num = 1;
 				}
 				
-				if (val >= 2) {
+				if (val >= 2)
+				{
+
 					dmabuf->fmt |= TRIDENT_FMT_STEREO;
 					if ((val == 6) && (state->card->pci_id == PCI_DEVICE_ID_ALI_5451)) {
-						ali_setup_multi_channels(state->card, 6);
+
+						if( card->rec_channel_use_count > 0 )
+						{
+							printk("Err: Record is working on the card!\n");
+							return -EBUSY;
+						}
+
+						ret = ali_setup_multi_channels(state->card, 6);
+						if (ret < 0) {
+							unlock_set_fmt(state);
+							return ret;
+						}
 						down(&state->card->open_sem);
 						ret = ali_allocate_other_states_resources(state, 6);
-						up(&state->card->open_sem);
 						if (ret < 0) {
+							up(&state->card->open_sem);
 							unlock_set_fmt(state);
 							return ret;
 						}
+						state->card->multi_channel_use_count ++;
+						up(&state->card->open_sem);
 					}
 					else val = 2;	/*yield to 2-channels*/
 				}
@@ -2031,10 +2090,20 @@
 	struct trident_card *card = devs;
 	struct trident_state *state = NULL;
 	struct dmabuf *dmabuf = NULL;
-
+	
 	/* find an avaiable virtual channel (instance of /dev/dsp) */
 	while (card != NULL) {
 		down(&card->open_sem);
+		if(file->f_mode & FMODE_READ)
+		{
+			/* Skip opens on cards that are in 6 channel mode */
+			if (card->multi_channel_use_count > 0)
+			{
+				up(&card->open_sem);
+				card = card->next;
+				continue;
+			}
+		}
 		for (i = 0; i < NR_HW_CH; i++) {
 			if (card->states[i] == NULL) {
 				state = card->states[i] = (struct trident_state *)
@@ -2107,6 +2176,7 @@
 				(CHANNEL_REC|PCM_LR|MONO_MIX);
 		}
 		trident_set_adc_rate(state, 8000);
+		card->rec_channel_use_count ++;
 	}
 
 	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
@@ -2143,16 +2213,29 @@
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(state);
 		lock_set_fmt(state);
-		if (state->chans_num > 2)
-			ali_free_other_states_resources(state);
+
 		unlock_set_fmt(state);
 		dealloc_dmabuf(state);
 		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+
+		if (state->chans_num > 2)
+		{
+			if( card->multi_channel_use_count-- < 0 )
+				card->multi_channel_use_count = 0;
+
+			if (card->multi_channel_use_count == 0)
+				ali_close_multi_channels();
+
+			ali_free_other_states_resources(state);
+		}
 	}
 	if (file->f_mode & FMODE_READ) {
 		stop_adc(state);
 		dealloc_dmabuf(state);
 		state->card->free_pcm_channel(state->card, dmabuf->channel->num);
+
+		if( card->rec_channel_use_count-- < 0 )
+			card->rec_channel_use_count = 0;
 	}
 
 	card->states[state->virt] = NULL;
@@ -2295,6 +2378,9 @@
 
 	data = ((u32) val) << 16;
 
+	if(!card)
+		BUG();
+		
 	address = ALI_AC97_WRITE;
 	mask = ALI_AC97_WRITE_ACTION | ALI_AC97_AUDIO_BUSY;
 	if (codec->id)
@@ -2391,11 +2477,29 @@
 flag:	ALI_SPDIF_OUT_TO_SPDIF_OUT
 	ALI_PCM_TO_SPDIF_OUT
 */
+
 static void ali_setup_spdif_out(struct trident_card *card, int flag)
 {
 	unsigned long spdif;
 	unsigned char ch;
 
+        char temp;
+        struct pci_dev *pci_dev = NULL;
+
+        pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev);
+        if (pci_dev == NULL)
+                return;
+        pci_read_config_byte(pci_dev, 0x61, &temp);
+        temp |= 0x40;
+        pci_write_config_byte(pci_dev, 0x61, temp);
+        pci_read_config_byte(pci_dev, 0x7d, &temp);
+        temp |= 0x01;
+        pci_write_config_byte(pci_dev, 0x7d, temp);
+        pci_read_config_byte(pci_dev, 0x7e, &temp);
+        temp &= (~0x20);
+        temp |= 0x10;
+        pci_write_config_byte(pci_dev, 0x7e, temp);
+
 	ch = inb(TRID_REG(card, ALI_SCTRL));
 	outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL));
 	ch = inb(TRID_REG(card, ALI_SPDIF_CTRL));
@@ -2448,112 +2552,207 @@
 	spdif |= ALI_SPDIF_IN_SUPPORT;
 	outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
 
-	spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL));
-	spdif |= ALI_SPDIF_IN_CH_STATUS;
-	outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL));
-
 	//Set SPDIF IN Rec
 	spdif = inl(TRID_REG(card, ALI_GLOBAL_CONTROL));
 	spdif |= ALI_SPDIF_IN_CH_ENABLE;
 	outl(spdif, TRID_REG(card, ALI_GLOBAL_CONTROL));
 
 	spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL));
+	spdif |= ALI_SPDIF_IN_CH_STATUS;
+	outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL));
+/*
+	spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL));
 	spdif |= ALI_SPDIF_IN_FUNC_ENABLE;
 	outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL));
+*/
 }
 
-static unsigned int ali_get_spdif_in_rate(struct trident_card *card)
+static void ali_delay(struct trident_card *card,int interval)
+{
+	unsigned long  begintimer,currenttimer;
+
+	begintimer   = inl(TRID_REG(card,  ALI_STIMER));
+	currenttimer = inl(TRID_REG(card,  ALI_STIMER));
+
+	while (currenttimer < begintimer + interval)
+		currenttimer = inl(TRID_REG(card,  ALI_STIMER));
+}
+
+static void ali_detect_spdif_rate(struct trident_card *card)
 {
-	unsigned long spdif, time1, time2;
-	unsigned count1, count2, count3;
-	unsigned char R1, R2 = 0;	
-	
-	outb(0xAA, TRID_REG(card, ALI_SPDIF_CTRL + 1));
-	count1 = 0xFFFF;
-	while(--count1)
+	u16 wval  = 0;
+	u16 count = 0;
+	u8  bval = 0, R1 = 0, R2 = 0;
+
+	bval  = inb(TRID_REG(card,ALI_SPDIF_CTRL));
+	bval |= 0x02;
+	outb(bval,TRID_REG(card,ALI_SPDIF_CTRL));
+
+	bval  = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1));
+	bval |= 0x1F;
+	outb(bval,TRID_REG(card,ALI_SPDIF_CTRL + 1));
+
+	while (((R1 < 0x0B )||(R1 > 0x0E)) && (R1 != 0x12) && count <= 50000)
 	{
-		count2 = 0xffff;
-		do{
-			count3 = 0xffff;
-			time1 = inl(TRID_REG(card, ALI_STIMER));
-
-			do{
-				time2 = inl(TRID_REG(card, ALI_STIMER));
-			}while((count3--) && (time2 <= (time1 + 5)));
-			if (!count3) {
-				printk("ali: STimer is stopped! Error!\n");
-				return FALSE;
-			}			
-			R1 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1));
-		}while((count2--) && (!((R1 == 0x0B)||(R1 == 0x0C)||(R1 == 0x0D)||(R1 == 0x0E)||(R1 == 0x12))));
-		if (!count2)
-			continue;
+		count ++;
 
-		count2 = 0xffff;
-		time1 = inl(TRID_REG(card, ALI_STIMER));
-		do{
-			time2 = inl(TRID_REG(card, ALI_STIMER));
-		}while((count2--) && (time2 <= (time1 + 5)));
-		if (!count2)
-			continue;
+		ali_delay(card, 6);
 
-		R2 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1));
-		count2 = 0xffff;
-		while((--count2) && (R2 != R1))
-		{
+		bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1));
+		R1 = bval & 0x1F;
+	}
+
+	if (count > 50000)
+	{
+		printk(KERN_WARNING "trident: Error in ali_detect_spdif_rate!\n");
+		return;
+	}
+
+	count = 0;
+
+	while (count <= 50000)
+	{
+		count ++;
+
+		ali_delay(card, 6);
+
+		bval = inb(TRID_REG(card,ALI_SPDIF_CTRL + 1));
+		R2 = bval & 0x1F;
+
+		if(R2 != R1)
 			R1 = R2;
-			count3 = 0xffff;
-			time1 = inl(TRID_REG(card, ALI_STIMER));
-			do{
-				time2 = inl(TRID_REG(card, ALI_STIMER));
-			}while((count3--) && (time2 <= (time1 + 5)));
-			if (!count3) {
-				printk("ali: STimer is stopped! Error!\n");
-				return FALSE;
-			}
-			R2 = inb(TRID_REG(card, ALI_SPDIF_CTRL + 1));
-		}
-		if(R2 == R1)
+		else
 			break;
 	}
 
-	if(!count1) {
-		printk("ali: Can not Detect the sample rate from SPDIF IN!\n");
-		return FALSE;
+	if (count > 50000)
+	{
+		printk(KERN_WARNING "trident: Error in ali_detect_spdif_rate!\n");
+		return;
 	}
 
-	spdif = inb(TRID_REG(card, ALI_SPDIF_CTRL)) | ALI_SPDIF_IN_CH_STATUS;
-	outb(spdif, TRID_REG(card, ALI_SPDIF_CTRL));
+	switch (R2)
+	{
+	case 0x0b:
+	case 0x0c:
+	case 0x0d:
+	case 0x0e:
+		wval  = inw(TRID_REG(card,ALI_SPDIF_CTRL + 2));
+		wval &= 0xE0F0;
+		wval |= (u16)0x09 << 8 | (u16)0x05;
+		outw(wval,TRID_REG(card,ALI_SPDIF_CTRL + 2));
+
+		bval  = inb(TRID_REG(card,ALI_SPDIF_CS +3)) & 0xF0;
+		outb(bval|0x02,TRID_REG(card,ALI_SPDIF_CS + 3));
+		break;
 
-	/* SPDIF only supprts 48k, 44.1k, 32k */
-	switch(R2) {
 	case 0x12:
-		outw(0x0E08, TRID_REG(card, ALI_SPDIF_CTRL + 2));
-		return 32000;
-	case 0x0B:
-	case 0x0C:
-	case 0x0D:
-	case 0x0E:
+		wval  = inw(TRID_REG(card,ALI_SPDIF_CTRL + 2));
+		wval &= 0xE0F0;
+		wval |= (u16)0x0E << 8 | (u16)0x08;
+		outw(wval,TRID_REG(card,ALI_SPDIF_CTRL + 2));
+
+		bval  = inb(TRID_REG(card,ALI_SPDIF_CS +3)) & 0xF0;
+		outb(bval|0x03,TRID_REG(card,ALI_SPDIF_CS + 3));
+		break;
+
 	default:
-		outw(0x0905, TRID_REG(card, ALI_SPDIF_CTRL + 2));
 		break;
 	}
+
+}
+
+static unsigned int ali_get_spdif_in_rate(struct trident_card *card)
+{
+	u32	dwRate = 0;
+	u8	bval = 0;
+
+	ali_detect_spdif_rate(card);
+
+	bval  = inb(TRID_REG(card,ALI_SPDIF_CTRL));
+	bval &= 0x7F;
+	bval |= 0x40;
+	outb(bval,TRID_REG(card,ALI_SPDIF_CTRL));
+
+	bval  = inb(TRID_REG(card,ALI_SPDIF_CS + 3));
+	bval &= 0x0F;
+
+	switch (bval)
+	{
+	case 0:
+		dwRate = 44100;
+		break;
+	case 1:
+		dwRate = 48000;
+		break;
+	case 2:
+		dwRate = 32000;
+		break;
+	default:
+		// Error occurs
+		break;
+	}
+
+	return dwRate;
 	
-	spdif = inb(TRID_REG(card, ALI_SPDIF_CS + 3)) & 0xf;
-	if (spdif == 0)
-		return 44100;
-	else	return 48000;
+}
+
+static int ali_close_multi_channels(void)
+{
+	char temp = 0;
+	struct pci_dev *pci_dev = NULL;
+
+        pci_dev = pci_find_device(PCI_VENDOR_ID_AL,PCI_DEVICE_ID_AL_M1533, pci_dev);
+        if (pci_dev == NULL)
+                return -1;
+	temp = 0x80;
+	pci_write_config_byte(pci_dev, 0x59, ~temp);
+	
+	pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev);
+	if (pci_dev == NULL)
+                return -1;
+
+	temp = 0x20;
+	pci_write_config_byte(pci_dev, 0xB8, ~temp);
+
+	return 0;
 }
 
 static int ali_setup_multi_channels(struct trident_card *card, int chan_nums)
 {
 	unsigned long dwValue;
-	
+	char temp = 0;
+	struct pci_dev *pci_dev = NULL;
+
+	pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pci_dev);
+	if (pci_dev == NULL)
+                return -1;
+	temp = 0x80;
+	pci_write_config_byte(pci_dev, 0x59, temp);
+	
+	pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, pci_dev);
+ 	if (pci_dev == NULL)
+                return -1;
+	temp = 0x20;
+	pci_write_config_byte(pci_dev, (int)0xB8,(u8) temp);
 	if (chan_nums == 6) {
 		dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000;
 		outl(dwValue, TRID_REG(card, ALI_SCTRL));
+		mdelay(4);
+		dwValue = inl(TRID_REG(card, ALI_SCTRL));
+		if (dwValue & 0x2000000) {
+			ali_ac97_set(card->ac97_codec[0], 0x02, 8080);
+			ali_ac97_set(card->ac97_codec[0], 0x36, 0);
+			ali_ac97_set(card->ac97_codec[0], 0x38, 0);
+			ali_ac97_set(card->ac97_codec[1], 0x36, 0);
+			ali_ac97_set(card->ac97_codec[1], 0x38, 0);
+			ali_ac97_set(card->ac97_codec[1], 0x02, 0);
+			ali_ac97_set(card->ac97_codec[1], 0x18, 0x0808);
+			ali_ac97_set(card->ac97_codec[1], 0x74, 0x3);
+			return 1;
+		}
 	}
-	return 1;
+	return -EINVAL;
 }
 
 static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel)
@@ -2746,7 +2945,7 @@
 	}
 
 	/* no more free channels avaliable */
-	printk(KERN_ERR "ali: no more channels available on Bank A.\n");
+//	printk(KERN_ERR "ali: no more channels available on Bank A.\n");
 	return NULL;
 }
 
@@ -2769,7 +2968,7 @@
 	}
 	
 	/* no free recordable channels avaliable */
-	printk(KERN_ERR "ali: no recordable channels available on Bank A.\n");
+//	printk(KERN_ERR "ali: no recordable channels available on Bank A.\n");
 	return NULL;
 }
 
@@ -2778,9 +2977,6 @@
 	unsigned char ch_st_sel;
 	unsigned short status_rate;
 	
-#ifdef DEBUG
-	printk("ali: spdif out rate =%d\n", rate);
-#endif
 	switch(rate) {
 	case 44100:
 		status_rate = 0;
@@ -2803,9 +2999,6 @@
 	ch_st_sel &= (~0x80);	//select left
 	outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL));
 	outw(status_rate | 0x10, TRID_REG(card, ALI_SPDIF_CS + 2));
-#ifdef DEBUG
-	printk("ali: SPDIF_CS=%lxh\n", inl(TRID_REG(card, ALI_SPDIF_CS)));
-#endif
 }
 
 static void ali_address_interrupt(struct trident_card *card)
@@ -2822,6 +3015,7 @@
 		if ((channel_mask = 1 << channel) & mask) {
 			mask &= ~channel_mask;
 			trident_ack_channel_interrupt(card, channel);
+			udelay(100);
 			state->dmabuf.update_flag |= ALI_ADDRESS_INT_UPDATE;
 			trident_update_ptr(state);
 		}
@@ -2986,7 +3180,7 @@
 /* OSS /dev/mixer file operation methods */
 static int trident_open_mixdev(struct inode *inode, struct file *file)
 {
-	int i;
+	int i = 0;
 	int minor = MINOR(inode->i_rdev);
 	struct trident_card *card = devs;
 
@@ -3033,10 +3227,17 @@
 	switch (card->pci_id)
 	{
 	case PCI_DEVICE_ID_ALI_5451:
+		outl(0x80000000,TRID_REG(card, ALI_GLOBAL_CONTROL));
+		outl(0x00000000,TRID_REG(card, 0xa4));
+		outl(0xffffffff,TRID_REG(card, 0x98));
+		outl(0x00000000,TRID_REG(card, 0xa8));
+		outb(0x10, 	TRID_REG(card, 0x22));
 		ready_2nd = inl(TRID_REG(card, ALI_SCTRL));
-		outl(ready_2nd | PCMOUT | SECONDARY_ID, TRID_REG(card, ALI_SCTRL));
+		ready_2nd &= 0x3fff;
+		outl(ready_2nd | PCMOUT | 0x8000, TRID_REG(card, ALI_SCTRL));
 		ready_2nd = inl(TRID_REG(card, ALI_SCTRL)); 
 		ready_2nd &= SI_AC97_SECONDARY_READY;
+//		printk("codec 2 ready flag= %lx\n", ready_2nd);
 		break;
 	case PCI_DEVICE_ID_SI_7018:
 		/* disable AC97 GPIO interrupt */
@@ -3097,18 +3298,18 @@
 			return num_ac97+1;
 	}
 
-	return num_ac97;
+	return 1/*num_ac97*/;
 }
 
 /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   untill "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
+   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
 static int __init trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
 	unsigned long iobase;
 	struct trident_card *card;
 	u8 revision;
 
-	if (!pci_dma_supported(pci_dev, TRIDENT_DMA_MASK)) {
+	if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) {
 		printk(KERN_ERR "trident: architecture does not support"
 		       " 30bit PCI busmaster DMA\n");
 		return -ENODEV;
@@ -3167,6 +3368,10 @@
 		
 		card->address_interrupt = ali_address_interrupt;
 
+		/* Added by Matt Wu 01-05-2001 for spdif in */
+		card->multi_channel_use_count = 0;
+		card->rec_channel_use_count = 0;
+
 		/* ALi SPDIF OUT function */
 		if(card->revision == ALI_5451_V02) {
 			ali_setup_spdif_out(card, ALI_PCM_TO_SPDIF_OUT);		
@@ -3203,7 +3408,7 @@
 		kfree(card);
 		return -ENODEV;
 	}
-	/* initilize AC97 codec and register /dev/mixer */
+	/* initialize AC97 codec and register /dev/mixer */
 	if (trident_ac97_init(card) <= 0) {
 		unregister_sound_dsp(card->dev_audio);
 		release_region(iobase, 256);
@@ -3224,7 +3429,6 @@
 	}
 
 	pci_set_drvdata(pci_dev, card);
-	pci_dev->dma_mask = TRIDENT_DMA_MASK;
 
 	/* Enable Address Engine Interrupts */
 	trident_enable_loop_interrupts(card);
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.4.2/linux/drivers/sound/via82cxxx_audio.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Fri Mar  2 11:02:15 2001
@@ -15,7 +15,7 @@
  */
 
 
-#define VIA_VERSION	"1.1.14a"
+#define VIA_VERSION	"1.1.14b"
 
 
 #include <linux/config.h>
@@ -282,6 +282,8 @@
 
 	unsigned rev_h : 1;
 
+	int locked_rate : 1;
+
 	struct semaphore syscall_sem;
 	struct semaphore open_sem;
 
@@ -508,10 +510,16 @@
 static int via_set_rate (struct ac97_codec *ac97,
 			 struct via_channel *chan, unsigned rate)
 {
+	struct via_info *card = ac97->private_data;
 	int rate_reg;
 
 	DPRINTK ("ENTER, rate = %d\n", rate);
 
+	if (card->locked_rate) {
+		chan->rate = 48000;
+		goto out;
+	}
+
 	if (rate > 48000)		rate = 48000;
 	if (rate < 4000) 		rate = 4000;
 
@@ -535,6 +543,13 @@
 	 */
 	chan->rate = via_ac97_read_reg (ac97, rate_reg);
 
+	if (chan->rate == 0) {
+		card->locked_rate = 1;
+		chan->rate = 48000;
+		printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
+	}
+
+out:
 	DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate);
 	return chan->rate;
 }
@@ -1421,15 +1436,19 @@
 	/* WARNING: this line is magic.  Remove this
 	 * and things break. */
 	/* enable variable rate, variable rate MIC ADC */
-	tmp16 = via_ac97_read_reg (&card->ac97, 0x2A);
-	via_ac97_write_reg (&card->ac97, 0x2A, tmp16 | (1<<0));
-
-	pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8);
-	if ((tmp8 & (VIA_CR41_AC97_ENABLE | VIA_CR41_AC97_RESET)) == 0) {
-		printk (KERN_ERR PFX "cannot enable AC97 controller, aborting\n");
-		DPRINTK ("EXIT, tmp8=%X, returning -ENODEV\n", tmp8);
-		return -ENODEV;
-	}
+ 	/*
+ 	 * If we cannot enable VRA, we have a locked-rate codec.
+ 	 * We try again to enable VRA before assuming so, however.
+ 	 */
+ 	tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
+ 	if ((tmp16 & 1) == 0) {
+ 		via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
+ 		tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
+ 		if ((tmp16 & 1) == 0) {
+ 			card->locked_rate = 1;
+ 			printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n");
+ 		}
+ 	}
 
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
@@ -1478,8 +1497,8 @@
 	}
 
 	/* enable variable rate, variable rate MIC ADC */
-	tmp16 = via_ac97_read_reg (&card->ac97, 0x2A);
-	via_ac97_write_reg (&card->ac97, 0x2A, tmp16 | (1<<0));
+	tmp16 = via_ac97_read_reg (&card->ac97, AC97_EXTENDED_STATUS);
+	via_ac97_write_reg (&card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1);
 
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c
--- v2.4.2/linux/drivers/sound/wavfront.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/wavfront.c	Fri Mar  2 11:12:11 2001
@@ -94,7 +94,7 @@
 #ifdef CONFIG_SMP
 #define LOOPS_PER_TICK cpu_data[smp_processor_id()].loops_per_jiffy
 #else
-#define LOOPS_PER_TICK	loops_per_sec
+#define LOOPS_PER_TICK	loops_per_jiffy
 #endif
 #endif
 
@@ -693,7 +693,7 @@
 /***********************************************************************
 WaveFront: data munging   
 
-Things here are wierd. All data written to the board cannot 
+Things here are weird. All data written to the board cannot 
 have its most significant bit set. Any data item with values 
 potentially > 0x7F (127) must be split across multiple bytes.
 
@@ -702,7 +702,7 @@
 that is represented on the x86 side as an array of bytes. The most
 efficient approach to handling both cases seems to be to use 2
 different functions for munging and 2 for de-munging. This avoids
-wierd casting and worrying about bit-level offsets.
+weird casting and worrying about bit-level offsets.
 
 **********************************************************************/
 
@@ -1213,7 +1213,7 @@
 	shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
 			     shptr, 4);
 	
-	/* This one is truly wierd. What kind of wierdo decided that in
+	/* This one is truly weird. What kind of weirdo decided that in
 	   a system dominated by 16 and 32 bit integers, they would use
 	   a just 12 bits ?
 	*/
@@ -3069,7 +3069,7 @@
    This code was developed using DOSEMU. The Turtle Beach SETUPSND
    utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
    of the port I/O done, using the Yamaha faxback document as a guide
-   to add more logic to the code. Its really pretty wierd.
+   to add more logic to the code. Its really pretty weird.
 
    There was an alternative approach of just dumping the whole I/O
    sequence as a series of port/value pairs and a simple loop
diff -u --recursive --new-file v2.4.2/linux/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- v2.4.2/linux/drivers/sound/ymfpci.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/sound/ymfpci.c	Tue Mar 20 11:29:01 2001
@@ -95,34 +95,6 @@
 MODULE_DEVICE_TABLE(pci, ymf_id_tbl);
 
 /*
- * Mindlessly copied from cs46xx XXX
- */
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/*
  *  common I/O routines
  */
 
@@ -347,7 +319,6 @@
 {
 	struct ymf_dmabuf *dmabuf;
 	int w_16;
-	unsigned bytepersec;
 	unsigned bufsize;
 	unsigned long flags;
 	int redzone;
@@ -367,20 +338,16 @@
 		if ((ret = alloc_dmabuf(dmabuf)))
 			return ret;
 
-	bytepersec = state->format.rate << state->format.shift;
-
 	/*
 	 * Create fake fragment sizes and numbers for OSS ioctls.
+	 * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
 	 */
 	bufsize = PAGE_SIZE << dmabuf->buforder;
-	if (dmabuf->ossfragshift) {
-		if ((1000 << dmabuf->ossfragshift) < bytepersec)
-			dmabuf->fragshift = ld2(bytepersec/1000);
-		else
-			dmabuf->fragshift = dmabuf->ossfragshift;
-	} else {
-		/* lets hand out reasonable big ass buffers by default */
-		dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+	/* lets hand out reasonable big ass buffers by default */
+	dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
+	if (dmabuf->ossfragshift > 3 &&
+	    dmabuf->ossfragshift < dmabuf->fragshift) {
+		dmabuf->fragshift = dmabuf->ossfragshift;
 	}
 	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
 	while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
@@ -390,9 +357,6 @@
 	dmabuf->fragsize = 1 << dmabuf->fragshift;
 	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
 
-	/*
-	 * Import what Doom might have set with SNDCTL_DSD_SETFRAGMENT.
-	 */
 	if (dmabuf->ossmaxfrags >= 2 && dmabuf->ossmaxfrags < dmabuf->numfrag) {
 		dmabuf->numfrag = dmabuf->ossmaxfrags;
 		dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
@@ -1726,8 +1690,6 @@
 			dmabuf->ossfragshift = 4;
 		if (dmabuf->ossfragshift > 15)
 			dmabuf->ossfragshift = 15;
-		if (dmabuf->ossmaxfrags < 4)
-			dmabuf->ossmaxfrags = 4;
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
@@ -1879,7 +1841,7 @@
 static int ymf_open(struct inode *inode, struct file *file)
 {
 	struct list_head *list;
-	ymfpci_t *unit;
+	ymfpci_t *unit = NULL;
 	int minor;
 	struct ymf_state *state;
 	int err;
@@ -2370,9 +2332,9 @@
 
 	int err;
 
-	if (pci_enable_device(pcidev) < 0) {
+	if ((err = pci_enable_device(pcidev)) != 0) {
 		printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
-		return -ENODEV;
+		return err;
 	}
 
 	if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
diff -u --recursive --new-file v2.4.2/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- v2.4.2/linux/drivers/telephony/ixj.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/telephony/ixj.c	Fri Mar  2 18:38:39 2001
@@ -6300,6 +6300,7 @@
 {
 	return 0;
 }
+#endif /* CONFIG_PCMCIA */
 
 #if defined(CONFIG_ISAPNP)
 extern __inline__ int ixj_probe_isa(int *cnt)
@@ -6448,7 +6449,6 @@
 	return 0;
 }
 #endif /* CONFIG_ISAPNP */
-#endif /* CONFIG_PCMCIA */
 
 #if defined(CONFIG_PCI)
 int __init ixj_probe_pci(int *cnt)
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- v2.4.2/linux/drivers/usb/bluetooth.c	Wed Feb 21 18:20:35 2001
+++ linux/drivers/usb/bluetooth.c	Mon Mar 19 17:21:54 2001
@@ -1,11 +1,17 @@
 /*
- * bluetooth.c   Version 0.7
+ * bluetooth.c   Version 0.8
  *
  * Copyright (c) 2000 Greg Kroah-Hartman	<greg@kroah.com>
  * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  *
+ * (2001/03/10) Version 0.8 gkh
+ *	Fixed problem with not unlinking interrupt urb on device close
+ *	and resubmitting the read urb on error with bluetooth struct.
+ *	Thanks to Narayan Mohanram <narayan@RovingNetworks.com> for the
+ *	fixes.
+ *
  * (11/29/2000) Version 0.7 gkh
  *	Fixed problem with overrunning the tty flip buffer.
  *	Removed unneeded NULL pointer initialization.
@@ -379,6 +385,7 @@
 	for (i = 0; i < NUM_BULK_URBS; ++i)
 		usb_unlink_urb (bluetooth->write_urb_pool[i]);
 	usb_unlink_urb (bluetooth->read_urb);
+	usb_unlink_urb (bluetooth->interrupt_in_urb);
 
 	bluetooth->active = 0;
 }
@@ -852,7 +859,7 @@
 
 	if (!bluetooth) {
 		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
-		goto exit;
+		return;
 	}
 
 	if (urb->status) {
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.4.2/linux/drivers/usb/devio.c	Sun Nov 12 20:45:19 2000
+++ linux/drivers/usb/devio.c	Fri Mar 23 11:50:01 2001
@@ -838,7 +838,7 @@
 		}
 		if (totlen > 32768) {
 			kfree(isopkt);
-			return -ENOMEM;
+			return -EINVAL;
 		}
 		uurb.buffer_length = totlen;
 		break;
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.4.2/linux/drivers/usb/hub.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/hub.c	Fri Mar 23 11:50:01 2001
@@ -291,6 +291,7 @@
 
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->dev = dev;
+	init_MUTEX(&hub->khubd_sem);
 
 	/* Record the new hub's existence */
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -334,6 +335,9 @@
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
+	down(&hub->khubd_sem); /* Wait for khubd to leave this hub alone. */
+	up(&hub->khubd_sem);
+
 	if (hub->urb) {
 		usb_unlink_urb(hub->urb);
 		usb_free_urb(hub->urb);
@@ -545,6 +549,13 @@
 		return;
 	}
 
+	/* Some low speed devices have problems with the quick delay, so */
+	/*  be a bit pessimistic with those devices. RHbug #23670 */
+	if (portstatus & USB_PORT_STAT_LOW_SPEED) {
+		wait_ms(400);
+		delay = HUB_LONG_RESET_TIME;
+	}
+
 	down(&usb_address0_sem);
 
 	tempstr = kmalloc(1024, GFP_KERNEL);
@@ -639,7 +650,7 @@
 		spin_lock_irqsave(&hub_event_lock, flags);
 
 		if (list_empty(&hub_event_list))
-			goto he_unlock;
+			break;
 
 		/* Grab the next entry from the beginning of the list */
 		tmp = hub_event_list.next;
@@ -650,6 +661,7 @@
 		list_del(tmp);
 		INIT_LIST_HEAD(tmp);
 
+		down(&hub->khubd_sem); /* never blocks, we were on list */
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
@@ -658,6 +670,7 @@
 			if (usb_hub_reset(hub)) {
 				err("error resetting hub %d - disconnecting", dev->devnum);
 				usb_hub_disconnect(dev);
+				up(&hub->khubd_sem);
 				continue;
 			}
 
@@ -733,9 +746,9 @@
                         	usb_hub_power_on(hub);
 			}
 		}
+		up(&hub->khubd_sem);
         } /* end while (1) */
 
-he_unlock:
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/hub.h linux/drivers/usb/hub.h
--- v2.4.2/linux/drivers/usb/hub.h	Thu Dec  7 16:13:38 2000
+++ linux/drivers/usb/hub.h	Fri Mar 23 11:50:01 2001
@@ -108,6 +108,8 @@
 	int nports;
 
 	struct usb_hub_descriptor *descriptor;
+
+	struct semaphore khubd_sem;
 };
 
 #endif
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.4.2/linux/drivers/usb/inode.c	Thu Sep  7 08:38:06 2000
+++ linux/drivers/usb/inode.c	Fri Mar  2 13:47:21 2001
@@ -596,7 +596,7 @@
 	return NULL;
 }
 
-static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, 0);
+static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE);
 
 /* --------------------------------------------------------------------- */
 
@@ -691,6 +691,7 @@
 		return ret;
 	if ((ret = register_filesystem(&usbdevice_fs_type)))
 		usb_deregister(&usbdevfs_driver);
+	kern_mount(&usbdevice_fs_type);
 #ifdef CONFIG_PROC_FS		
 	/* create mount point for usbdevfs */
 	usbdir = proc_mkdir("usb", proc_bus);
@@ -702,6 +703,7 @@
 {
 	usb_deregister(&usbdevfs_driver);
 	unregister_filesystem(&usbdevice_fs_type);
+	kern_umount(usbdevice_fs_type.kern_mnt);
 #ifdef CONFIG_PROC_FS	
         if (usbdir)
                 remove_proc_entry("usb", proc_bus);
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- v2.4.2/linux/drivers/usb/microtek.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/microtek.c	Fri Mar 23 11:50:01 2001
@@ -9,7 +9,7 @@
  * This driver implements a SCSI host controller driver and a USB
  * device driver. To avoid confusion, all the USB related stuff is
  * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_.
- * 
+ *
  * Microtek (www.microtek.com) did not release the specifications for
  * their USB protocol to us, so we had to reverse engineer them. We
  * don't know for which models they are valid.
@@ -52,7 +52,7 @@
  * you want it, just send mail.
  *
  * Status:
- *	
+ *
  *	Untested with multiple scanners.
  *	Untested on SMP.
  *	Untested on a bigendian machine.
@@ -104,6 +104,17 @@
  *	20000822 Version 0.2.3
  *	20000913 Reduced module size if debugging is off
  *	20000913 Version 0.2.4
+ *      20010210 New abort logic
+ *      20010210 Version 0.3.0
+ *	20010217 Merged scatter/gather
+ *	20010218 Version 0.4.0
+ *	20010218 Cosmetic fixes
+ *	20010218 Version 0.4.1
+ *      20010306 Abort while using scatter/gather
+ *      20010306 Version 0.4.2
+ *      20010311 Remove all timeouts and tidy up generally (john)
+ *	20010320 check return value of scsi_register()
+ *	20010320 Version 0.4.3
  */
 
 #include <linux/module.h>
@@ -128,15 +139,9 @@
 
 #include "microtek.h"
 
-/* Constants */
-
-#define MTS_ABORT_TIMEOUT HZ /*jiffies*/
-
-
 /* Should we do debugging? */
 
-// #define MTS_DO_DEBUG
-
+//#define MTS_DO_DEBUG
 
 /* USB layer driver interface */
 
@@ -147,7 +152,7 @@
 static struct usb_device_id mts_usb_ids [];
 
 static struct usb_driver mts_usb_driver = {
-	name:		"microtek",
+	name:		"microtekX6",
 	probe:		mts_usb_probe,
 	disconnect:	mts_usb_disconnect,
 	id_table:	mts_usb_ids,
@@ -156,7 +161,7 @@
 
 /* Internal driver stuff */
 
-#define MTS_VERSION	"0.2.4"
+#define MTS_VERSION	"0.4.3"
 #define MTS_NAME	"microtek usb (rev " MTS_VERSION "): "
 
 #define MTS_WARNING(x...) \
@@ -177,8 +182,8 @@
 	MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ )
 #define MTS_DEBUG_INT() \
 	do { MTS_DEBUG_GOT_HERE(); \
-	     MTS_DEBUG("transfer = %x context = %x\n",(int)transfer,(int)context ); \
-	     MTS_DEBUG("status = %x data-length = %x sent = %x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+	     MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
+	     MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
              mts_debug_dump(context->instance);\
 	   } while(0)
 #else
@@ -190,23 +195,17 @@
 #define MTS_DEBUG_INT() MTS_NUL_STATEMENT
 
 #endif
-	
+
 
 
 #define MTS_INT_INIT()\
-	do {\
-	context = (struct mts_transfer_context*)transfer->context; \
-	if (atomic_read(&context->do_abort)) {\
-		mts_transfer_cleanup(transfer);\
-		return;\
-	}\
+	struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; \
 	MTS_DEBUG_INT();\
-	} while (0)
 
 #ifdef MTS_DO_DEBUG
 
 static inline void mts_debug_dump(struct mts_desc* desc) {
-	MTS_DEBUG("desc at 0x%x: halted = %x%x, toggle = %x%x\n",
+	MTS_DEBUG("desc at 0x%x: halted = %02x%02x, toggle = %02x%02x\n",
 		  (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0],
 		  (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0]
 		);
@@ -296,60 +295,34 @@
 
  out:
 	MTS_DEBUG( "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], 
+	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5],
 	       srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
 }
 
 #else
 
-static inline void mts_show_command(Scsi_Cmnd *srb)
+static inline void mts_show_command(Scsi_Cmnd * dummy)
 {
-	while (0) {}
 }
 
-static inline void mts_debug_dump(struct mts_desc* desc)
+static inline void mts_debug_dump(struct mts_desc* dummy)
 {
-	while (0) {}
 }
 
 #endif
 
 
-
-
-static inline int mts_is_aborting(struct mts_desc* desc) {
+/* static inline int mts_is_aborting(struct mts_desc* desc) {
 	return (atomic_read(&desc->context.do_abort));
-}
-
-static inline void mts_request_abort(struct mts_desc* desc) {
-	MTS_DEBUG_GOT_HERE();
-	mts_debug_dump(desc);
-	atomic_set(&desc->context.do_abort,1);
-}
+}  */
 
 static inline void mts_urb_abort(struct mts_desc* desc) {
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
-	if ( desc->urb.status == USB_ST_URB_PENDING ) {
-		usb_unlink_urb( &desc->urb );
-	}
-}
-
-static inline void mts_wait_abort(struct mts_desc* desc)
-{
-	mts_request_abort(desc);
-
-	while( !atomic_read(&desc->lock.count) ) {
-/* Is there a function to check if the semaphore is locked? */
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout( MTS_ABORT_TIMEOUT ); 
-		MTS_DEBUG_GOT_HERE();
-		mts_urb_abort(desc);
-	}
 
+	usb_unlink_urb( &desc->urb );
 }
 
-
 static struct mts_desc * mts_list; /* list of active scanners */
 struct semaphore mts_list_semaphore;
 
@@ -362,10 +335,10 @@
 		   (int)to_remove );
 
 	lock_kernel();
-	mts_wait_abort(to_remove);
+	mts_urb_abort(to_remove);
 
 	MTS_DEBUG_GOT_HERE();
-	
+
 	if ( to_remove != mts_list ) {
 		MTS_DEBUG_GOT_HERE();
 		if (to_remove->prev && to_remove->next)
@@ -378,7 +351,7 @@
 			mts_list->prev = 0;
 		}
 	}
-		
+
 	if ( to_remove->next ) {
 		MTS_DEBUG_GOT_HERE();
 		to_remove->next->prev = to_remove->prev;
@@ -387,7 +360,7 @@
 	MTS_DEBUG_GOT_HERE();
 	scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl));
 	unlock_kernel();
-	
+
 	kfree( to_remove );
 }
 
@@ -395,16 +368,16 @@
 void mts_add_nolock( struct mts_desc* to_add )
 {
 	MTS_DEBUG( "adding 0x%x to list\n", (int)to_add );
-	
+
 	to_add->prev = 0;
 	to_add->next = mts_list;
 	if ( mts_list ) {
 		mts_list->prev = to_add;
 	}
-			
+
 	mts_list = to_add;
 }
-		
+
 
 
 
@@ -415,20 +388,18 @@
 static int mts_scsi_release(struct Scsi_Host *psh)
 {
 	MTS_DEBUG_GOT_HERE();
-	
+
 	return 0;
 }
 
 static int mts_scsi_abort (Scsi_Cmnd *srb)
-/* interrupt context (!) */ /* FIXME this is about to become task context */
 {
 	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
 
 	MTS_DEBUG_GOT_HERE();
-	
-	mts_request_abort(desc);
+
 	mts_urb_abort(desc);
-	
+
 	return SCSI_ABORT_PENDING;
 }
 
@@ -450,10 +421,10 @@
 static int mts_scsi_detect (struct SHT * sht)
 {
 	/* Whole function stolen from usb-storage */
-	
+
 	struct mts_desc * desc = (struct mts_desc *)sht->proc_dir;
 	/* What a hideous hack! */
-	  
+
 	char local_name[48];
 
 	MTS_DEBUG_GOT_HERE();
@@ -467,15 +438,20 @@
 		MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
 		return 0;
 	}
-	
+
 	strcpy(sht->proc_name, local_name);
 
  	sht->proc_dir = NULL;
 
 	/* In host->hostdata we store a pointer to desc */
 	desc->host = scsi_register(sht, sizeof(desc));
+	if (desc->host == NULL) {
+		MTS_ERROR("Cannot register due to low memory");
+		kfree(sht->proc_name);
+		return 0;
+	}
 	desc->host->hostdata[0] = (unsigned long)desc;
-/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */ 
+/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */
 
 	return 1;
 }
@@ -490,6 +466,7 @@
 int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
 
 static void mts_transfer_cleanup( struct urb *transfer );
+static void mts_do_sg(struct urb * transfer);
 
 
 inline static
@@ -503,10 +480,9 @@
 /* Holding transfer->context->lock! */
 {
 	int res;
-	struct mts_transfer_context* context;
-	
+
 	MTS_INT_INIT();
-	
+
 	FILL_BULK_URB(transfer,
 		      context->instance->usb_dev,
 		      pipe,
@@ -516,16 +492,13 @@
 		      context
 		);
 
-/*	transfer->transfer_flags = USB_DISABLE_SPD;*/
 	transfer->transfer_flags = USB_ASYNC_UNLINK;
 	transfer->status = 0;
-	transfer->timeout = 100;
 
 	res = usb_submit_urb( transfer );
 	if ( res ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
 		context->srb->result = DID_ERROR << 16;
-		context->state = mts_con_error;
 		mts_transfer_cleanup(transfer);
 	}
 	return;
@@ -535,8 +508,8 @@
 static void mts_transfer_cleanup( struct urb *transfer )
 /* Interrupt context! */
 {
-	struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context;
-	
+	MTS_INT_INIT();
+
 	if ( context->final_callback )
 		context->final_callback(context->srb);
 	up( &context->instance->lock );
@@ -545,8 +518,6 @@
 
 static void mts_transfer_done( struct urb *transfer )
 {
-	struct mts_transfer_context* context;
-
 	MTS_INT_INIT();
 
 	context->srb->result &= MTS_SCSI_ERR_MASK;
@@ -561,34 +532,25 @@
 static void mts_get_status( struct urb *transfer )
 /* Interrupt context! */
 {
-	struct mts_transfer_context* context;
-
 	MTS_INT_INIT();
 
-	context->state = mts_con_status;
-	
 	mts_int_submit_urb(transfer,
 			   usb_rcvbulkpipe(context->instance->usb_dev,
 					   context->instance->ep_response),
 			   &context->status,
 			   1,
 			   mts_transfer_done );
-	
-	
-	return;
 }
 
 static void mts_data_done( struct urb* transfer )
 /* Interrupt context! */
 {
-	struct mts_transfer_context* context;
-
 	MTS_INT_INIT();
 
 	if ( context->data_length != transfer->actual_length ) {
 		context->srb->resid = context->data_length - transfer->actual_length;
 	} else if ( transfer->status ) {
-		context->srb->result = DID_ERROR<<16;
+		context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 	}
 
 	mts_get_status(transfer);
@@ -600,39 +562,65 @@
 static void mts_command_done( struct urb *transfer )
 /* Interrupt context! */
 {
-	struct mts_transfer_context* context;
-
 	MTS_INT_INIT();
 
 	if ( transfer->status ) {
-		context->srb->result = DID_ERROR<<16;
+	        if (transfer->status == -ENOENT) {
+		        /* We are being killed */
+			MTS_DEBUG_GOT_HERE();
+			context->srb->result = DID_ABORT<<16;
+                } else {
+		        /* A genuine error has occured */
+			MTS_DEBUG_GOT_HERE();
+
+		        context->srb->result = DID_ERROR<<16;
+                }
 		mts_transfer_cleanup(transfer);
-		
+
 		return;
 	}
-	
+
 	if ( context->data ) {
-		context->state = mts_con_data;
 		mts_int_submit_urb(transfer,
 				   context->data_pipe,
 				   context->data,
 				   context->data_length,
-				   mts_data_done);
+				   context->srb->use_sg ? mts_do_sg : mts_data_done);
 	} else mts_get_status(transfer);
-	
+
 	return;
 }
 
+static void mts_do_sg (struct urb* transfer)
+{
+	struct scatterlist * sg;
+	MTS_INT_INIT();
+	
+	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
+
+	if (transfer->status) {
+                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+		mts_transfer_cleanup(transfer);
+        }
 
+	sg = context->srb->buffer;
+	context->fragment++;
+	mts_int_submit_urb(transfer,
+			context->data_pipe,
+			sg[context->fragment].address,
+			sg[context->fragment].length,
+			context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg);
+	return;
+}
 
-	static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };
-	static const u8 mts_read_image_sig_len = 4;
-	static const unsigned char mts_direction[256/8] = {
-		0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
-		0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
+static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };
+static const u8 mts_read_image_sig_len = 4;
+static const unsigned char mts_direction[256/8] = {
+	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
+	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
 
 
 #define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
@@ -640,26 +628,34 @@
 static void
 mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
 {
-
 	int pipe;
-
-
+	struct scatterlist * sg;
+	
 	MTS_DEBUG_GOT_HERE();
 
 	desc->context.instance = desc;
 	desc->context.srb = srb;
-	desc->context.state = mts_con_command;
-	atomic_set(&desc->context.do_abort,0);
-	
-	if ( !srb->bufflen ){
-		desc->context.data = 0;
-		desc->context.data_length = 0;
-		return;
+	desc->context.fragment = 0;
+
+	if (!srb->use_sg) {
+		if ( !srb->bufflen ){
+			desc->context.data = 0;
+			desc->context.data_length = 0;
+			return;
+		} else {
+			desc->context.data = srb->buffer;
+			desc->context.data_length = srb->bufflen;
+			MTS_DEBUG("length = %d or %d\n",
+				  srb->request_bufflen, srb->bufflen);
+		}
 	} else {
-		desc->context.data = srb->buffer;
-		desc->context.data_length = srb->bufflen;
+		MTS_DEBUG("Using scatter/gather\n");
+		sg = srb->buffer;
+		desc->context.data = sg[0].address;
+		desc->context.data_length = sg[0].length;
 	}
-	
+
+
 	/* can't rely on srb->sc_data_direction */
 
 	/* Brutally ripped from usb-storage */
@@ -691,11 +687,11 @@
 	MTS_DEBUG_GOT_HERE();
 	mts_show_command(srb);
 	mts_debug_dump(desc);
-	
+
 	if ( srb->device->lun || srb->device->id || srb->device->channel ) {
 
 		MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel );
-		
+
 		MTS_DEBUG("this device doesn't exist\n");
 
 		srb->result = DID_BAD_TARGET << 16;
@@ -704,14 +700,10 @@
 			callback(srb);
 
 		goto out;
-	}	
+	}
 
 	down(&desc->lock);
-
-	MTS_DEBUG_GOT_HERE();
-	mts_show_command(srb);
 	
-
 	FILL_BULK_URB(&desc->urb,
 		      desc->usb_dev,
 		      usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
@@ -720,31 +712,24 @@
 		      mts_command_done,
 		      &desc->context
 		      );
-	
-		
+
+
 	mts_build_transfer_context( srb, desc );
 	desc->context.final_callback = callback;
-	desc->urb.timeout = 100;
-	desc->urb.transfer_flags = USB_ASYNC_UNLINK;
 	
-/*	desc->urb.transfer_flags = USB_DISABLE_SPD;*/
-
 	res=usb_submit_urb(&desc->urb);
-	
+
 	if(res){
 		MTS_ERROR("error %d submitting URB\n",(int)res);
 		srb->result = DID_ERROR << 16;
 
 		if(callback)
 			callback(srb);
-	up(&desc->lock); /* no further cleanup is done */
+	        up(&desc->lock);
 
-		goto out;
-	}	
-	
-	MTS_DEBUG_GOT_HERE();
+	}
 
- out:
+out:
 	return err;
 }
 /*
@@ -755,23 +740,21 @@
 
 
 static Scsi_Host_Template mts_scsi_host_template = {
-	name:           "microtek",
+	name:           "microtekX6",
 	detect:		mts_scsi_detect,
 	release:	mts_scsi_release,
-	command:	0,
 	queuecommand:	mts_scsi_queuecommand,
 
 	eh_abort_handler:	mts_scsi_abort,
-	eh_device_reset_handler:0,
-	eh_bus_reset_handler:	0,
 	eh_host_reset_handler:	mts_scsi_host_reset,
 
+	sg_tablesize:		SG_ALL,
 	can_queue:		1,
 	this_id:		-1,
 	cmd_per_lun:		1,
 	present:		0,
 	unchecked_isa_dma:	FALSE,
-	use_clustering:		FALSE,
+	use_clustering:		TRUE,
 	use_new_eh_code:	TRUE,
 	emulated:		TRUE
 };
@@ -782,7 +765,7 @@
 static void mts_usb_disconnect (struct usb_device *dev, void *ptr)
 {
 	struct mts_desc* to_remove = (struct mts_desc*)ptr;
-	
+
 	MTS_DEBUG_GOT_HERE();
 
 	/* leave the list - lock it */
@@ -847,7 +830,7 @@
 	int ep_in_set[3]; /* this will break if we have more than three endpoints
 			   which is why we check */
 	int *ep_in_current = ep_in_set;
-	
+
 	struct mts_desc * new_desc;
 	struct vendor_product const* p;
 
@@ -856,7 +839,7 @@
 
 	MTS_DEBUG_GOT_HERE();
 	MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev );
-	
+
 	MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n",
 		   (int)dev->descriptor.idProduct,
 		   (int)dev->descriptor.idVendor );
@@ -871,12 +854,12 @@
 	if ( p->support_status != mts_sup_full )
 		MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
 			     p->name );
-	
+
 	/* the altsettting 0 on the interface we're probing */
 	altsetting =
-		&(dev->actconfig->interface[interface].altsetting[0]);	
+		&(dev->actconfig->interface[interface].altsetting[0]);
+
 
-	
 	/* Check if the config is sane */
 
 	if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) {
@@ -886,13 +869,13 @@
 	}
 
 	for( i = 0; i < altsetting->bNumEndpoints; i++ ) {
-		if ((altsetting->endpoint[i].bmAttributes & 
+		if ((altsetting->endpoint[i].bmAttributes &
 		     USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
-			
+
 			MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n",
 			     (int)altsetting->endpoint[i].bEndpointAddress );
 		} else {
-			if (altsetting->endpoint[i].bEndpointAddress & 
+			if (altsetting->endpoint[i].bEndpointAddress &
 			    USB_DIR_IN)
 				*ep_in_current++
 					= altsetting->endpoint[i].bEndpointAddress &
@@ -902,26 +885,26 @@
 					MTS_WARNING( "can only deal with one output endpoints. Bailing out." );
 					return NULL;
 				}
-		
+
 				ep_out = altsetting->endpoint[i].bEndpointAddress &
 					USB_ENDPOINT_NUMBER_MASK;
 			}
 		}
-		
+
 	}
-	
+
 
 	if ( ep_out == -1 ) {
 		MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
 		return NULL;
 	}
-	
-	
+
+
 	/* I don't understand the following fully (it's from usb-storage) -- John */
 
 	/* set the interface -- STALL is an acceptable response here */
 	result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
-	
+
 	MTS_DEBUG("usb_set_interface returned %d.\n",result);
 	switch( result )
 	{
@@ -970,7 +953,7 @@
 	new_desc->ep_out = ep_out;
 	new_desc->ep_response = ep_in_set[0];
 	new_desc->ep_image = ep_in_set[1];
-	
+
 
 	if ( new_desc->ep_out != MTS_EP_OUT )
 		MTS_WARNING( "will this work? Command EP is not usually %d\n",
@@ -984,16 +967,16 @@
 		MTS_WARNING( "will this work? Image data EP is not usually %d\n",
 			     (int)new_desc->ep_image );
 
-	
+
 	/* Initialize the host template based on the default one */
-	memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); 	
+	memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template));
 	/* HACK from usb-storage - this is needed for scsi detection */
 	(struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */
-	
+
 	MTS_DEBUG("registering SCSI module\n");
-	
+
 	new_desc->ctempl.module = THIS_MODULE;
-	result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl));	
+	result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl));
 	/* Will get hit back in microtek_detect by this func */
 	if ( result )
 	{
@@ -1011,12 +994,12 @@
 	down(&mts_list_semaphore);
 
 	mts_add_nolock( new_desc );
-	
+
 	up(&mts_list_semaphore);
-	
-	
+
+
 	MTS_DEBUG("completed probe and exiting happily\n");
-	
+
 	return (void *)new_desc;
 }
 
@@ -1027,7 +1010,7 @@
 int __init microtek_drv_init(void)
 {
 	int result;
-	
+
 	MTS_DEBUG_GOT_HERE();
 	init_MUTEX(&mts_list_semaphore);
 
@@ -1037,14 +1020,14 @@
 	} else {
 		MTS_DEBUG("driver registered.\n");
 	}
-	
+
 	return 0;
 }
 
 void __exit microtek_drv_exit(void)
 {
 	struct mts_desc* next;
-	
+
 	MTS_DEBUG_GOT_HERE();
 
 	usb_deregister(&mts_usb_driver);
@@ -1060,7 +1043,7 @@
 		/* advance the list pointer */
 		mts_list = next;
 	}
-	
+
 	up(&mts_list_semaphore);
 }
 
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/microtek.h linux/drivers/usb/microtek.h
--- v2.4.2/linux/drivers/usb/microtek.h	Wed Jun 28 19:49:00 2000
+++ linux/drivers/usb/microtek.h	Fri Mar 23 11:50:01 2001
@@ -21,20 +21,8 @@
 	void* data;
 	unsigned data_length;
 	int data_pipe;
+	int fragment;
 
-	enum {
-		mts_con_none,
-		mts_con_command,
-		mts_con_data,
-		mts_con_status,
-		mts_con_error,
-		mts_con_done
-	}
-	state;
-
-	atomic_t do_abort; /* when != 0 URB completion routines will
-			      return straightaway */
-	
 	u8 status; /* status returned from ep_response after command completion */
 };
 
@@ -44,18 +32,18 @@
 	struct mts_desc *prev;
 
 	struct usb_device *usb_dev;
-	
+
 	int interface;
 
 	/* Endpoint addresses */
 	u8 ep_out;
 	u8 ep_response;
 	u8 ep_image;
-	
+
 	struct Scsi_Host * host;
 	Scsi_Host_Template ctempl;
 	int host_number;
-	
+
 	struct semaphore lock;
 
 	struct urb urb;
@@ -68,5 +56,5 @@
 #define MTS_EP_IMAGE	0x3
 #define MTS_EP_TOTAL	0x3
 
-#define MTS_SCSI_ERR_MASK ~0x3fu 
+#define MTS_SCSI_ERR_MASK ~0x3fu
 
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- v2.4.2/linux/drivers/usb/pegasus.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/pegasus.c	Sun Mar 18 19:54:52 2001
@@ -54,7 +54,7 @@
 #define	PEGASUS_USE_INTR
 #define	PEGASUS_WRITE_EEPROM
 
-static const char *version = __FILE__ ": v0.4.17 2000/11/13 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
+static const char *version = __FILE__ ": v0.4.18 2001/03/18 (C) 1999-2000 Petko Manolov (petkan@dce.bg)";
 
 
 static int loopback = 0;
@@ -124,6 +124,7 @@
 static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
 	int	ret;
+	DECLARE_WAITQUEUE(wait, current);
 
 	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP;
@@ -131,22 +132,27 @@
 	}
 	pegasus->dr.requesttype = PEGASUS_REQT_READ;
 	pegasus->dr.request = PEGASUS_REQ_GET_REGS;
-	pegasus->dr.value = 0;
+	pegasus->dr.value = cpu_to_le16 (0);
 	pegasus->dr.index = cpu_to_le16p(&indx);
-	pegasus->dr.length = 
-	pegasus->ctrl_urb.transfer_buffer_length = cpu_to_le16p(&size);
+	pegasus->dr.length = cpu_to_le16p(&size);
+	pegasus->ctrl_urb.transfer_buffer_length = size;
 
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
 			  usb_rcvctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  data, size, ctrl_callback, pegasus );
 
+	add_wait_queue( &pegasus->ctrl_wait, &wait );
+	set_current_state( TASK_INTERRUPTIBLE );
+	pegasus->flags |= CTRL_URB_SLEEP;
+
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRLs %d", ret);
 		goto out;
 	}
-	pegasus->flags |= CTRL_URB_SLEEP;
-	interruptible_sleep_on( &pegasus->ctrl_wait );
+
+	schedule();
+	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 out:
 	return	ret;
 }
@@ -155,6 +161,7 @@
 static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
 {
 	int	ret;
+	DECLARE_WAITQUEUE(wait, current);
 
 	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP ;
@@ -162,22 +169,27 @@
 	}
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
-	pegasus->dr.value = 0;
+	pegasus->dr.value = cpu_to_le16 (0);
 	pegasus->dr.index = cpu_to_le16p( &indx );
-	pegasus->dr.length = 
-	pegasus->ctrl_urb.transfer_buffer_length = cpu_to_le16p( &size );
+	pegasus->dr.length = cpu_to_le16p( &size );
+	pegasus->ctrl_urb.transfer_buffer_length = size;
 
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  data, size, ctrl_callback, pegasus );
+			  
+	add_wait_queue( &pegasus->ctrl_wait, &wait );
+	set_current_state( TASK_INTERRUPTIBLE );
+	pegasus->flags |= CTRL_URB_SLEEP;
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
 		return	ret;
 	}
-	pegasus->flags |= CTRL_URB_SLEEP;
-	interruptible_sleep_on( &pegasus->ctrl_wait );
+
+	schedule();
+	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 
 	return	ret;
 }
@@ -186,29 +198,37 @@
 static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data )
 {
 	int	ret;
-
+	__u16 dat = data;
+	DECLARE_WAITQUEUE(wait, current);
+	
 	while ( pegasus->flags & ETH_REGS_CHANGED ) {
 		pegasus->flags |= CTRL_URB_SLEEP;
 		interruptible_sleep_on( &pegasus->ctrl_wait );
 	}
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REG;
-	pegasus->dr.value = data;
+	pegasus->dr.value = cpu_to_le16p( &dat);
 	pegasus->dr.index = cpu_to_le16p( &indx );
-	pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1;
+	pegasus->dr.length = cpu_to_le16( 1 );
+	pegasus->ctrl_urb.transfer_buffer_length = 1;
 
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  &data, 1, ctrl_callback, pegasus );
 
+	add_wait_queue( &pegasus->ctrl_wait, &wait );
+	set_current_state( TASK_INTERRUPTIBLE );
+	pegasus->flags |= CTRL_URB_SLEEP;
+
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
 		return	ret;
 	}
-	pegasus->flags |= CTRL_URB_SLEEP;
-	interruptible_sleep_on( &pegasus->ctrl_wait );
-	
+
+	schedule();
+	remove_wait_queue( &pegasus->ctrl_wait, &wait );
+
 	return	ret;
 }
 
@@ -220,8 +240,8 @@
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
 	pegasus->dr.value = 0;
-	pegasus->dr.index = EthCtrl0;
-	pegasus->dr.length = 
+	pegasus->dr.index =  cpu_to_le16(EthCtrl0);
+	pegasus->dr.length = cpu_to_le16(3);
 	pegasus->ctrl_urb.transfer_buffer_length = 3;
 
 	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
@@ -240,7 +260,8 @@
 {
 	int	i;
 	__u8	data[4] = { phy, 0, 0, indx };
-
+	__u16  regdi;
+	
 	set_register( pegasus, PhyCtrl, 0 );
 	set_registers( pegasus, PhyAddr, sizeof(data), data );
 	set_register( pegasus, PhyCtrl, (indx | PHY_READ) );
@@ -250,7 +271,8 @@
 			break;
 	}
 	if ( i < REG_TIMEOUT ) {
-		get_registers( pegasus, PhyData, 2, regd );
+		get_registers( pegasus, PhyData, 2, &regdi );
+		*regd = le16_to_cpu(regdi);
 		return	0;
 	}
 	warn( __FUNCTION__ " failed" );
@@ -283,18 +305,22 @@
 
 static int read_eprom_word( pegasus_t *pegasus, __u8 index, __u16 *retdata )
 {
-	int	i, tmp;
-
+	int	i;
+	__u8 tmp;
+	__u16 retdatai;
+	
 	set_register( pegasus, EpromCtrl, 0 );
 	set_register( pegasus, EpromOffset, index );
 	set_register( pegasus, EpromCtrl, EPROM_READ); 
+
 	for ( i=0; i < REG_TIMEOUT; i++ ) {
 		get_registers( pegasus, EpromCtrl, 1, &tmp );
 		if ( tmp & EPROM_DONE )
 			break;
 	}
 	if ( i < REG_TIMEOUT ) {
-		get_registers( pegasus, EpromData, 2, retdata );
+		get_registers( pegasus, EpromData, 2, &retdatai );
+		*retdata = le16_to_cpu (retdatai);
 		return	0;
 	}
 	warn( __FUNCTION__ " failed" );
@@ -349,9 +375,12 @@
 static inline void get_node_id( pegasus_t *pegasus, __u8 *id )
 {
 	int	i;
-
-	for (i = 0; i < 3; i++)
-		read_eprom_word( pegasus, i, (__u16 *)&id[i*2]);
+	__u16 w16;
+	
+	for (i = 0; i < 3; i++) {
+		read_eprom_word( pegasus, i, &w16);
+		((__u16 *) id)[i] = cpu_to_le16p (&w16);
+	}
 }
 
 
@@ -473,7 +502,7 @@
 	if ( !count )
 		goto goon;
 
-	rx_status = *(int *)(pegasus->rx_buff + count - 4);
+	rx_status = le32_to_cpu(*(int *)(pegasus->rx_buff + count - 4));
 	if ( rx_status & 0x000e0000 ) {
 		dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);
 		pegasus->stats.rx_errors++;
@@ -585,10 +614,11 @@
 	pegasus_t	*pegasus = net->priv;
 	int 	count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
 	int 	res;
-
+	__u16 l16 = skb->len;
+	
 	netif_stop_queue( net );
 		
-	((__u16 *)pegasus->tx_buff)[0] = skb->len;
+	((__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),
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.4.2/linux/drivers/usb/printer.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/printer.c	Fri Mar  2 17:50:22 2001
@@ -1,5 +1,5 @@
 /*
- * printer.c  Version 0.6
+ * printer.c  Version 0.8
  *
  * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
@@ -17,7 +17,8 @@
  *	v0.4 - fixes in unidirectional mode
  *	v0.5 - add DEVICE_ID string support
  *	v0.6 - never time out
- *	v0.? - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
+ *	v0.7 - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
+ *	v0.8 - add devfs support
  */
 
 /*
@@ -45,6 +46,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/lp.h>
+#include <linux/devfs_fs_kernel.h>
 #undef DEBUG
 #include <linux/usb.h>
 
@@ -78,6 +80,7 @@
 
 struct usblp {
 	struct usb_device 	*dev;			/* USB device */
+	devfs_handle_t		devfs;			/* devfs device */
 	struct urb		readurb, writeurb;	/* The urbs */
 	wait_queue_head_t	wait;			/* Zzzzz ... */
 	int			readcount;		/* Counter for reads */
@@ -90,6 +93,8 @@
 							/* first 2 bytes are (big-endian) length */
 };
 
+extern devfs_handle_t usb_devfs_handle;			/* /dev/usb dir. */
+
 static struct usblp *usblp_table[USBLP_MINORS];
 
 /* Quirks: various printer quirks are handled by this table & its flags. */
@@ -245,6 +250,7 @@
 		return 0;
 	}
 
+	devfs_unregister(usblp->devfs);
 	usblp_table[usblp->minor] = NULL;
 	kfree(usblp->device_id_string);
 	kfree(usblp);
@@ -454,6 +460,16 @@
 	return 0;
 }
 
+static struct file_operations usblp_fops = {
+	owner:		THIS_MODULE,
+	read:		usblp_read,
+	write:		usblp_write,
+	poll:		usblp_poll,
+	ioctl:		usblp_ioctl,
+	open:		usblp_open,
+	release:	usblp_release,
+};
+
 static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
 			 const struct usb_device_id *id)
 {
@@ -464,6 +480,7 @@
 	int alts = dev->actconfig->interface[ifnum].act_altsetting;
 	int length, err;
 	char *buf;
+	char name[6];
 
 	/* If a bidirectional interface exists, use it. */
 	for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
@@ -573,6 +590,17 @@
 	usblp_check_status(usblp, 0);
 #endif
 
+	sprintf(name, "lp%d", minor);
+	
+	/* Create with perms=664 */
+	usblp->devfs = devfs_register(usb_devfs_handle, name,
+				      DEVFS_FL_DEFAULT, USB_MAJOR,
+				      USBLP_MINOR_BASE + minor,
+				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+				      S_IWGRP, &usblp_fops, NULL);
+	if (usblp->devfs == NULL)
+		err("usblp%d: device node registration failed", minor);
+
 	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
 		minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
 
@@ -600,19 +628,10 @@
 
 	kfree(usblp->device_id_string);
 
+	devfs_unregister(usblp->devfs);
 	usblp_table[usblp->minor] = NULL;
 	kfree(usblp);
 }
-
-static struct file_operations usblp_fops = {
-	owner:		THIS_MODULE,
-	read:		usblp_read,
-	write:		usblp_write,
-	poll:		usblp_poll,
-	ioctl:		usblp_ioctl,
-	open:		usblp_open,
-	release:	usblp_release,
-};
 
 static struct usb_device_id usblp_ids [] = {
 	{ USB_INTERFACE_INFO(7, 1, 1) },
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.4.2/linux/drivers/usb/scanner.c	Thu Jan  4 13:15:32 2001
+++ linux/drivers/usb/scanner.c	Fri Mar  2 17:50:22 2001
@@ -1,7 +1,7 @@
 /* -*- linux-c -*- */
 
 /* 
- * Driver for USB Scanners (linux-2.4.0test1-ac7)
+ * Driver for USB Scanners (linux-2.4.0)
  *
  * Copyright (C) 1999, 2000 David E. Nelson
  *
@@ -208,6 +208,26 @@
  *    - Added the Epson Expression1600 ID's. Thanks to Karl Heinz
  *      Kremer <khk@khk.net>.
  *
+ * 0.4.5  2/28/2001
+ *    - Added Mustek ID's (BearPaw 2400, 1200 CU Plus, BearPaw 1200F).
+ *      Thanks to Henning Meier-Geinitz <henningmg@gmx.de>.
+ *    - Added read_timeout module parameter to override RD_NAK_TIMEOUT
+ *      when read()'ing from devices.
+ *    - Stalled pipes are now checked and cleared with
+ *      usb_clear_halt() for the read_scanner() function. This should
+ *      address the "funky result: -32" error messages.
+ *    - Removed Microtek scanner ID's.  Microtek scanners are now
+ *      supported via the drivers/usb/microtek.c driver.
+ *    - Added scanner specific read timeout's.
+ *    - Return status errors are NEGATIVE!!!  This should address the
+ *      "funky result: -110" error messages.
+ *    - Replaced USB_ST_TIMEOUT with ETIMEDOUT.
+ *    - rd_nak was still defined in MODULE_PARM.  It's been updated with
+ *      read_timeout.  Thanks to Mark W. Webb <markwebb@adelphia.net> for
+ *      reporting this bug.
+ *    - Added Epson Perfection 1640SU and 1640SU Photo.  Thanks to
+ *      Jean-Luc <f5ibh@db0bm.ampr.org>.
+ *
  *  TODO
  *
  *    - Performance
@@ -235,8 +255,7 @@
  *    System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
  *            300 dpi scan of the entire bed
  *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
- *       8 Bit Gray  ~ 17 secs - 4.2 Mbit/sec
- */
+ *       8 Bit Gray ~ 17 secs - 4.2 Mbit/sec */
 
 /* 
  * Scanner definitions, macros, module info, 
@@ -244,81 +263,6 @@
  */ 
 #include "scanner.h"
 
-/* Table of scanners that may work with this driver */
-static struct usb_device_id scanner_device_ids [] = {
-	/* Acer */
-	{ USB_DEVICE(0x04a5, 0x2060) },	/* Prisa Acerscan 620U & 640U (!)*/
-	{ USB_DEVICE(0x04a5, 0x2040) },	/* Prisa AcerScan 620U (!) */
-	{ USB_DEVICE(0x04a5, 0x2022) },	/* Vuego Scan Brisa 340U */
-	/* Agfa */
-	{ USB_DEVICE(0x06bd, 0x0001) },	/* SnapScan 1212U */
-	{ USB_DEVICE(0x06bd, 0x0002) },	/* SnapScan 1236U */
-	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
-	{ USB_DEVICE(0x06bd, 0x0100) },	/* SnapScan Touch */
-	/* Colorado -- See Primax/Colorado below */
-	/* Epson -- See Seiko/Epson below */
-	/* Genius */
-	{ USB_DEVICE(0x0458, 0x2001) },	/* ColorPage-Vivid Pro */
-	/* Hewlett Packard */
-	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
-	{ USB_DEVICE(0x03f0, 0x0101) },	/* 4100C */
-	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
-	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
-	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
-	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C */
-	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
-	{ USB_DEVICE(0x03f0, 0x0601) },	/* 6300C */
-	/* iVina */
-	{ USB_DEVICE(0x0638, 0x0268) },     /* 1200U */
-	/* Microtek */
-	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
-	{ USB_DEVICE(0x05da, 0x0094) },	/* Phantom 336CX - C3 */
-	{ USB_DEVICE(0x05da, 0x00a0) },	/* Phantom 336CX - C3 #2 */
-	{ USB_DEVICE(0x05da, 0x009a) },	/* Phantom C6 */
-	{ USB_DEVICE(0x05da, 0x00a3) },	/* ScanMaker V6USL */
-	{ USB_DEVICE(0x05da, 0x80a3) },	/* ScanMaker V6USL #2 */
-	{ USB_DEVICE(0x05da, 0x80ac) },	/* ScanMaker V6UL - SpicyU */
-	/* Mustek */
-	{ USB_DEVICE(0x055f, 0x0001) },	/* 1200 CU */
-	{ USB_DEVICE(0x0400, 0x1000) },	/* BearPaw 1200 */
-	{ USB_DEVICE(0x055f, 0x0002) },	/* 600 CU */
-	{ USB_DEVICE(0x055f, 0x0003) },	/* 1200 USB */
-	{ USB_DEVICE(0x055f, 0x0006) },	/* 1200 UB */
-	/* Primax/Colorado */
-	{ USB_DEVICE(0x0461, 0x0300) },	/* G2-300 #1 */
-	{ USB_DEVICE(0x0461, 0x0380) },	/* G2-600 #1 */
-	{ USB_DEVICE(0x0461, 0x0301) },	/* G2E-300 #1 */
-	{ USB_DEVICE(0x0461, 0x0381) },	/* ReadyScan 636i */
-	{ USB_DEVICE(0x0461, 0x0302) },	/* G2-300 #2 */
-	{ USB_DEVICE(0x0461, 0x0382) },	/* G2-600 #2 */
-	{ USB_DEVICE(0x0461, 0x0303) },	/* G2E-300 #2 */
-	{ USB_DEVICE(0x0461, 0x0383) },	/* G2E-600 */
-	{ USB_DEVICE(0x0461, 0x0340) },	/* Colorado USB 9600 */
-	{ USB_DEVICE(0x0461, 0x0360) },	/* Colorado USB 19200 */
-	{ USB_DEVICE(0x0461, 0x0341) },	/* Colorado 600u */
-	{ USB_DEVICE(0x0461, 0x0361) },	/* Colorado 1200u */
-	/* Seiko/Epson Corp. */
-	{ USB_DEVICE(0x04b8, 0x0101) },	/* Perfection 636U and 636Photo */
-	{ USB_DEVICE(0x04b8, 0x0103) },	/* Perfection 610 */
-	{ USB_DEVICE(0x04b8, 0x0104) },	/* Perfection 1200U and 1200Photo*/
-	{ USB_DEVICE(0x04b8, 0x0106) },	/* Stylus Scan 2500 */
-	{ USB_DEVICE(0x04b8, 0x0107) },	/* Expression 1600 */
-	/* Umax */
-	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
-	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
-	{ USB_DEVICE(0x1606, 0x0230) },	/* Astra 2200U */
-	/* Visioneer */
-	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
-	{ USB_DEVICE(0x04a7, 0x0211) },	/* OneTouch 7600 USB */
-	{ USB_DEVICE(0x04a7, 0x0231) },	/* 6100 USB */
-	{ USB_DEVICE(0x04a7, 0x0311) },	/* 6200 EPP/USB */
-	{ USB_DEVICE(0x04a7, 0x0321) },	/* OneTouch 8100 EPP/USB */
-	{ USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
-	{ }				/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, scanner_device_ids);
-
 
 static void
 irq_scanner(struct urb *urb)
@@ -475,9 +419,9 @@
 		result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
 		dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
 
-		if (result == USB_ST_TIMEOUT) {	/* NAK -- shouldn't happen */
+		if (result == -ETIMEDOUT) {	/* NAK -- shouldn't happen */
 			warn("write_scanner: NAK recieved.");
-			ret = -ETIME;
+			ret = result;
 			break;
 		} else if (result < 0) { /* We should not get any I/O errors */
 			warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
@@ -559,7 +503,7 @@
 
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
 
-		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, RD_NAK_TIMEOUT);
+		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, scn->rd_nak_timeout);
 		dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
 
 /*
@@ -576,23 +520,35 @@
  * Ctrl-C's are acted upon in a reasonable amount of time.
  */
 
-		if (result == USB_ST_TIMEOUT && !partial) { /* Timeout
-                                                               and no
-                                                               data */
-			if (--rd_expire <= 0) {
-				warn("read_scanner(%d): excessive NAK's received", scn_minor);
-				ret = -ETIME;
-				break;
-			} else {
-				interruptible_sleep_on_timeout(&scn->rd_wait_q, RD_NAK_TIMEOUT);
-				continue;
+		if (result == -ETIMEDOUT) { /* NAK */
+			if (!partial) { /* No data */
+				if (--rd_expire <= 0) {	/* Give it up */
+					warn("read_scanner(%d): excessive NAK's received", scn_minor);
+					ret = result;
+					break;
+				} else { /* Keep trying to read data */
+					interruptible_sleep_on_timeout(&scn->rd_wait_q, scn->rd_nak_timeout);
+					continue;
+				}
+			} else { /* Timeout w/ some data */
+				goto data_recvd;
 			}
+		}
+		
+		if (result == -EPIPE) { /* No hope */
+			if(usb_clear_halt(dev, scn->bulk_in_ep)) {
+				err("read_scanner(%d): Failure to clear endpoint halt condition (%d).", scn_minor, ret);
+			}
+			ret = result;
+			break;
 		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
 			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
 			ret = -EIO;
 			break;
 		}
 
+	data_recvd:
+
 #ifdef RD_DATA_DUMP
 		if (partial) {
 			unsigned char cnt, cnt_max;
@@ -826,6 +782,26 @@
 		return NULL;
 	}
 	dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
+	
+
+	switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
+	case 0x04b8:		/* Seiko/Epson */
+		scn->rd_nak_timeout = HZ * 40;
+		break;
+	case 0x055f:		/* Mustek */
+	case 0x0400:		/* Another Mustek */
+	case 0x0ff5:		/* And yet another Mustek */
+		scn->rd_nak_timeout = HZ * 1;
+	default:
+		scn->rd_nak_timeout = RD_NAK_TIMEOUT;
+	}
+
+
+	if (read_timeout > 0) {	/* User specified read timeout overrides everything */
+		info("probe_scanner: User specified USB read timeout - %d", read_timeout);
+		scn->rd_nak_timeout = read_timeout;
+	}
+
 
 	scn->bulk_in_ep = have_bulk_in;
 	scn->bulk_out_ep = have_bulk_out;
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.4.2/linux/drivers/usb/scanner.h	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/scanner.h	Fri Mar  2 17:50:22 2001
@@ -1,5 +1,5 @@
 /*
- * Driver for USB Scanners (linux-2.4.0test1-ac7)
+ * Driver for USB Scanners (linux-2.4.0)
  *
  * Copyright (C) 1999, 2000 David E. Nelson
  *
@@ -36,7 +36,7 @@
 
 #include <linux/usb.h>
 
-static __s32 vendor=-1, product=-1;
+static __s32 vendor=-1, product=-1, read_timeout=0;
 
 MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
 MODULE_DESCRIPTION("USB Scanner Driver");
@@ -47,6 +47,9 @@
 MODULE_PARM(product, "i");
 MODULE_PARM_DESC(product, "User specified USB idProduct");
 
+MODULE_PARM(read_timeout, "i");
+MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
+
 
 /* Enable to activate the ioctl interface.  This is mainly meant for */
 /* development purposes until an ioctl number is officially registered */
@@ -56,6 +59,85 @@
 // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
 // #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
 
+static struct usb_device_id scanner_device_ids [] = {
+	/* Acer */
+	{ USB_DEVICE(0x04a5, 0x2060) },	/* Prisa Acerscan 620U & 640U (!)*/
+	{ USB_DEVICE(0x04a5, 0x2040) },	/* Prisa AcerScan 620U (!) */
+	{ USB_DEVICE(0x04a5, 0x2022) },	/* Vuego Scan Brisa 340U */
+	/* Agfa */
+	{ USB_DEVICE(0x06bd, 0x0001) },	/* SnapScan 1212U */
+	{ USB_DEVICE(0x06bd, 0x0002) },	/* SnapScan 1236U */
+	{ USB_DEVICE(0x06bd, 0x2061) },	/* Another SnapScan 1212U (?)*/
+	{ USB_DEVICE(0x06bd, 0x0100) },	/* SnapScan Touch */
+	/* Colorado -- See Primax/Colorado below */
+	/* Epson -- See Seiko/Epson below */
+	/* Genius */
+	{ USB_DEVICE(0x0458, 0x2001) },	/* ColorPage-Vivid Pro */
+	/* Hewlett Packard */
+	{ USB_DEVICE(0x03f0, 0x0205) },	/* 3300C */
+	{ USB_DEVICE(0x03f0, 0x0101) },	/* 4100C */
+	{ USB_DEVICE(0x03f0, 0x0105) },	/* 4200C */
+	{ USB_DEVICE(0x03f0, 0x0102) },	/* PhotoSmart S20 */
+	{ USB_DEVICE(0x03f0, 0x0401) },	/* 5200C */
+	//	{ USB_DEVICE(0x03f0, 0x0701) },	/* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
+	{ USB_DEVICE(0x03f0, 0x0201) },	/* 6200C */
+	{ USB_DEVICE(0x03f0, 0x0601) },	/* 6300C */
+	/* iVina */
+	{ USB_DEVICE(0x0638, 0x0268) },     /* 1200U */
+	/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
+	//	{ USB_DEVICE(0x05da, 0x0099) },	/* ScanMaker X6 - X6U */
+	//	{ USB_DEVICE(0x05da, 0x0094) },	/* Phantom 336CX - C3 */
+	//	{ USB_DEVICE(0x05da, 0x00a0) },	/* Phantom 336CX - C3 #2 */
+	//	{ USB_DEVICE(0x05da, 0x009a) },	/* Phantom C6 */
+	//	{ USB_DEVICE(0x05da, 0x00a3) },	/* ScanMaker V6USL */
+	//	{ USB_DEVICE(0x05da, 0x80a3) },	/* ScanMaker V6USL #2 */
+	//	{ USB_DEVICE(0x05da, 0x80ac) },	/* ScanMaker V6UL - SpicyU */
+	/* Mustek */
+	{ USB_DEVICE(0x055f, 0x0001) },	/* 1200 CU */
+	{ USB_DEVICE(0x0400, 0x1000) },	/* BearPaw 1200 */
+	{ USB_DEVICE(0x055f, 0x0002) },	/* 600 CU */
+	{ USB_DEVICE(0x055f, 0x0003) },	/* 1200 USB */
+	{ USB_DEVICE(0x055f, 0x0006) },	/* 1200 UB */
+	{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
+	{ USB_DEVICE(0x055f, 0x0008) }, /* 1200 CU Plus */
+	{ USB_DEVICE(0x0ff5, 0x0010) }, /* BearPaw 1200F */
+	/* Primax/Colorado */
+	{ USB_DEVICE(0x0461, 0x0300) },	/* G2-300 #1 */
+	{ USB_DEVICE(0x0461, 0x0380) },	/* G2-600 #1 */
+	{ USB_DEVICE(0x0461, 0x0301) },	/* G2E-300 #1 */
+	{ USB_DEVICE(0x0461, 0x0381) },	/* ReadyScan 636i */
+	{ USB_DEVICE(0x0461, 0x0302) },	/* G2-300 #2 */
+	{ USB_DEVICE(0x0461, 0x0382) },	/* G2-600 #2 */
+	{ USB_DEVICE(0x0461, 0x0303) },	/* G2E-300 #2 */
+	{ USB_DEVICE(0x0461, 0x0383) },	/* G2E-600 */
+	{ USB_DEVICE(0x0461, 0x0340) },	/* Colorado USB 9600 */
+	{ USB_DEVICE(0x0461, 0x0360) },	/* Colorado USB 19200 */
+	{ USB_DEVICE(0x0461, 0x0341) },	/* Colorado 600u */
+	{ USB_DEVICE(0x0461, 0x0361) },	/* Colorado 1200u */
+	/* Seiko/Epson Corp. */
+	{ USB_DEVICE(0x04b8, 0x0101) },	/* Perfection 636U and 636Photo */
+	{ USB_DEVICE(0x04b8, 0x0103) },	/* Perfection 610 */
+	{ USB_DEVICE(0x04b8, 0x0104) },	/* Perfection 1200U and 1200Photo*/
+	{ USB_DEVICE(0x04b8, 0x0106) },	/* Stylus Scan 2500 */
+	{ USB_DEVICE(0x04b8, 0x0107) },	/* Expression 1600 */
+	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
+	{ USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
+	/* Umax */
+	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
+	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
+	{ USB_DEVICE(0x1606, 0x0230) },	/* Astra 2200U */
+	/* Visioneer */
+	{ USB_DEVICE(0x04a7, 0x0221) },	/* OneTouch 5300 USB */
+	{ USB_DEVICE(0x04a7, 0x0211) },	/* OneTouch 7600 USB */
+	{ USB_DEVICE(0x04a7, 0x0231) },	/* 6100 USB */
+	{ USB_DEVICE(0x04a7, 0x0311) },	/* 6200 EPP/USB */
+	{ USB_DEVICE(0x04a7, 0x0321) },	/* OneTouch 8100 EPP/USB */
+	{ USB_DEVICE(0x04a7, 0x0331) }, /* OneTouch 8600 EPP/USB */
+	{ }				/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, scanner_device_ids);
+
 #define IS_EP_BULK(ep)  ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
 #define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
 #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
@@ -73,7 +155,7 @@
 #define OBUF_SIZE 4096
 
 /* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */
-#define RD_NAK_TIMEOUT (10*HZ)	/* Number of X seconds to wait */
+#define RD_NAK_TIMEOUT (10*HZ)	/* Default number of X seconds to wait */
 #define RD_EXPIRE 12		/* Number of attempts to wait X seconds */
 
 
@@ -90,12 +172,13 @@
 	unsigned int ifnum;	/* Interface number of the USB device */
 	kdev_t scn_minor;	/* Scanner minor - used in disconnect() */
 	unsigned char button;	/* Front panel buffer */
-        char isopen;		/* Not zero if the device is open */
+	char isopen;		/* Not zero if the device is open */
 	char present;		/* Not zero if device is present */
 	char *obuf, *ibuf;	/* transfer buffers */
 	char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
 	wait_queue_head_t rd_wait_q; /* read timeouts */
 	struct semaphore gen_lock; /* lock to prevent concurrent reads or writes */
+	unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
 };
 
 static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- v2.4.2/linux/drivers/usb/serial/Config.in	Sat Feb  3 19:51:30 2001
+++ linux/drivers/usb/serial/Config.in	Mon Mar 19 17:21:54 2001
@@ -14,6 +14,7 @@
   dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+  dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- v2.4.2/linux/drivers/usb/serial/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/drivers/usb/serial/Makefile	Mon Mar 19 17:21:54 2001
@@ -17,6 +17,7 @@
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
 obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
+obj-$(CONFIG_USB_SERIAL_EDGEPORT)		+= io_edgeport.o
  
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- v2.4.2/linux/drivers/usb/serial/belkin_sa.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Fri Mar 23 11:50:01 2001
@@ -24,7 +24,11 @@
  * -- Add support for flush commands
  * -- Add everything that is missing :)
  *
- * (11/06/2000) gkh
+ * 12-Mar-2001 gkh
+ *	- Added support for the GoHubs GO-COM232 device which is the same as the
+ *	  Peracom device.
+ *
+ * 06-Nov-2000 gkh
  *	- Added support for the old Belkin and Peracom devices.
  *	- Made the port able to be opened multiple times.
  *	- Added some defaults incase the line settings are things these devices
@@ -90,6 +94,7 @@
 	{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
 	{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
 	{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
+	{ USB_DEVICE(GOHUBS_VID, GOHUBS_PID) },
 	{ }							/* Terminating entry */
 };
 
@@ -108,6 +113,11 @@
 	{ }							/* Terminating entry */
 };
 
+static __devinitdata struct usb_device_id gocom232_table [] = {
+	{ USB_DEVICE(GOHUBS_VID, GOHUBS_PID) },
+	{ }							/* Terminating entry */
+};
+
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
 /* All of the device info needed for the Belkin serial converter */
@@ -174,6 +184,27 @@
 	shutdown:		belkin_sa_shutdown,
 };
 
+/* the GoHubs Go-COM232 device is the same as the Peracom single port adapter */
+struct usb_serial_device_type gocom232_device = {
+	name:			"GO-COM232 USB Serial Converter",
+	id_table:		gocom232_table,			/* the GO-COM232 device */
+	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			belkin_sa_open,
+	close:			belkin_sa_close,
+	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
+	ioctl:			belkin_sa_ioctl,
+	set_termios:		belkin_sa_set_termios,
+	break_ctl:		belkin_sa_break_ctl,
+	startup:		belkin_sa_startup,
+	shutdown:		belkin_sa_shutdown,
+};
+
 
 struct belkin_sa_private {
 	unsigned long		control_state;
@@ -233,8 +264,8 @@
 			belkin_sa_close (&serial->port[i], NULL);
 		}
 		/* My special items, the standard routines free my urbs */
-		if (serial->port->private)
-			kfree(serial->port->private);
+		if (serial->port[i].private)
+			kfree(serial->port[i].private);
 	}
 }
 
@@ -558,6 +589,7 @@
 	usb_serial_register (&belkin_sa_device);
 	usb_serial_register (&belkin_old_device);
 	usb_serial_register (&peracom_device);
+	usb_serial_register (&gocom232_device);
 	return 0;
 }
 
@@ -567,6 +599,7 @@
 	usb_serial_deregister (&belkin_sa_device);
 	usb_serial_deregister (&belkin_old_device);
 	usb_serial_deregister (&peracom_device);
+	usb_serial_deregister (&gocom232_device);
 }
 
 
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/belkin_sa.h linux/drivers/usb/serial/belkin_sa.h
--- v2.4.2/linux/drivers/usb/serial/belkin_sa.h	Sat Nov 11 18:51:18 2000
+++ linux/drivers/usb/serial/belkin_sa.h	Tue Mar 20 14:02:46 2001
@@ -15,7 +15,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
- * (11/06/2000) gkh
+ * 12-Mar-2001 gkh
+ *	Added GoHubs GO-COM232 device id.
+ *
+ * 06-Nov-2000 gkh
  *	Added old Belkin and Peracom device ids, which this driver supports
  *
  * 12-Oct-2000 William Greathouse
@@ -38,6 +41,9 @@
 
 #define PERACOM_VID	0x0565	/* Peracom's vendor id */
 #define PERACOM_PID	0x0001	/* Peracom's single port serial converter's id */
+
+#define GOHUBS_VID	0x0921	/* GoHubs vendor id */
+#define GOHUBS_PID	0x0100	/* GoHubs single port serial converter's id (identical to the Peracom device) */
 
 /* Vendor Request Interface */
 #define BELKIN_SA_SET_BAUDRATE_REQUEST	0  /* Set baud rate */
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- v2.4.2/linux/drivers/usb/serial/digi_acceleport.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/digi_acceleport.c	Tue Mar 20 14:02:46 2001
@@ -1282,12 +1282,10 @@
 	|| priv->dp_write_urb_in_use ) {
 
 		/* buffer data if count is 1 (probably put_char) if possible */
-		if( count == 1 ) {
-			new_len = MIN( count,
-				DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len );
-			memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf,
-				new_len );
-			priv->dp_out_buf_len += new_len;
+		if( count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE ) {
+			priv->dp_out_buf[priv->dp_out_buf_len++]
+				= *(from_user ? user_buf : buf);
+			new_len = 1;
 		} else {
 			new_len = 0;
 		}
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_16654.h linux/drivers/usb/serial/io_16654.h
--- v2.4.2/linux/drivers/usb/serial/io_16654.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_16654.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,195 @@
+/************************************************************************
+ *
+ *	16654.H		Definitions for 16C654 UART used on EdgePorts
+ *
+ *	Copyright (c) 1998 Inside Out Networks, Inc.
+ *	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.
+ *
+ ************************************************************************/
+
+#if !defined(_16654_H)
+#define	_16654_H
+
+/************************************************************************
+ *
+ *			D e f i n e s   /   T y p e d e f s
+ *
+ ************************************************************************/
+
+	//
+	// UART register numbers
+	// Numbers 0-7 are passed to the Edgeport directly. Numbers 8 and
+	// above are used internally to indicate that we must enable access
+	// to them via LCR bit 0x80 or LCR = 0xBF.
+	// The register number sent to the Edgeport is then (x & 0x7).
+	//
+	// Driver must not access registers that affect operation of the
+	// the EdgePort firmware -- that includes THR, RHR, IER, FCR.
+
+
+#define THR			0	// ! Transmit Holding Register (Write)
+#define RDR			0	// ! Receive Holding Register (Read)
+#define IER			1	// ! Interrupt Enable Register
+#define FCR			2	// ! Fifo Control Register (Write)
+#define ISR			2	// Interrupt Status Register (Read)
+#define LCR			3	// Line Control Register
+#define MCR			4	// Modem Control Register
+#define LSR			5	// Line Status Register
+#define MSR			6	// Modem Status Register
+#define SPR			7	// ScratchPad Register
+#define DLL			8	// Bank2[ 0 ] Divisor Latch LSB
+#define DLM			9	// Bank2[ 1 ] Divisor Latch MSB
+#define EFR			10	// Bank2[ 2 ] Extended Function Register
+//efine unused			11	// Bank2[ 3 ]
+#define XON1			12	// Bank2[ 4 ] Xon-1
+#define XON2			13	// Bank2[ 5 ] Xon-2
+#define XOFF1			14	// Bank2[ 6 ] Xoff-1
+#define XOFF2			15	// Bank2[ 7 ] Xoff-2
+
+#define	NUM_16654_REGS		16
+
+#define IS_REG_2ND_BANK(x)	((x) >= 8)
+
+	//
+	// Bit definitions for each register
+	//
+
+#define IER_RX			0x01	// Enable receive interrupt
+#define IER_TX			0x02	// Enable transmit interrupt
+#define IER_RXS			0x04	// Enable receive status interrupt
+#define IER_MDM			0x08	// Enable modem status interrupt
+#define IER_SLEEP		0x10	// Enable sleep mode
+#define IER_XOFF		0x20	// Enable s/w flow control (XOFF) interrupt
+#define IER_RTS			0x40	// Enable RTS interrupt
+#define IER_CTS			0x80	// Enable CTS interrupt
+#define IER_ENABLE_ALL		0xFF	// Enable all ints
+
+
+#define FCR_FIFO_EN		0x01	// Enable FIFOs
+#define FCR_RXCLR		0x02	// Reset Rx FIFO
+#define FCR_TXCLR		0x04	// Reset Tx FIFO
+#define FCR_DMA_BLK		0x08	// Enable DMA block mode
+#define FCR_TX_LEVEL_MASK	0x30	// Mask for Tx FIFO Level
+#define FCR_TX_LEVEL_8		0x00	// Tx FIFO Level =  8 bytes
+#define FCR_TX_LEVEL_16		0x10	// Tx FIFO Level = 16 bytes
+#define FCR_TX_LEVEL_32		0x20	// Tx FIFO Level = 32 bytes
+#define FCR_TX_LEVEL_56		0x30	// Tx FIFO Level = 56 bytes
+#define FCR_RX_LEVEL_MASK	0xC0	// Mask for Rx FIFO Level
+#define FCR_RX_LEVEL_8		0x00	// Rx FIFO Level =  8 bytes
+#define FCR_RX_LEVEL_16		0x40	// Rx FIFO Level = 16 bytes
+#define FCR_RX_LEVEL_56		0x80	// Rx FIFO Level = 56 bytes
+#define FCR_RX_LEVEL_60		0xC0	// Rx FIFO Level = 60 bytes
+
+
+#define ISR_INT_MDM_STATUS	0x00	// Modem status int pending
+#define ISR_INT_NONE		0x01	// No interrupt pending
+#define ISR_INT_TXRDY		0x02	// Tx ready int pending
+#define ISR_INT_RXRDY		0x04	// Rx ready int pending
+#define ISR_INT_LINE_STATUS	0x06	// Line status int pending
+#define ISR_INT_RX_TIMEOUT	0x0C	// Rx timeout int pending
+#define ISR_INT_RX_XOFF		0x10	// Rx Xoff int pending
+#define ISR_INT_RTS_CTS		0x20	// RTS/CTS change int pending
+#define ISR_FIFO_ENABLED	0xC0	// Bits set if FIFOs enabled
+#define ISR_INT_BITS_MASK	0x3E	// Mask to isolate valid int causes
+
+
+#define LCR_BITS_5		0x00	// 5 bits/char
+#define LCR_BITS_6		0x01	// 6 bits/char
+#define LCR_BITS_7		0x02	// 7 bits/char
+#define LCR_BITS_8		0x03	// 8 bits/char
+#define LCR_BITS_MASK		0x03	// Mask for bits/char field
+
+#define LCR_STOP_1		0x00	// 1 stop bit
+#define LCR_STOP_1_5		0x04	// 1.5 stop bits (if 5   bits/char)
+#define LCR_STOP_2		0x04	// 2 stop bits   (if 6-8 bits/char)
+#define LCR_STOP_MASK		0x04	// Mask for stop bits field
+
+#define LCR_PAR_NONE		0x00	// No parity
+#define LCR_PAR_ODD		0x08	// Odd parity
+#define LCR_PAR_EVEN		0x18	// Even parity
+#define LCR_PAR_MARK		0x28	// Force parity bit to 1
+#define LCR_PAR_SPACE		0x38	// Force parity bit to 0
+#define LCR_PAR_MASK		0x38	// Mask for parity field
+
+#define LCR_SET_BREAK		0x40	// Set Break condition
+#define LCR_DL_ENABLE		0x80	// Enable access to divisor latch
+
+#define LCR_ACCESS_EFR		0xBF	// Load this value to access DLL,DLM,
+					// and also the '654-only registers
+					// EFR, XON1, XON2, XOFF1, XOFF2
+
+
+#define MCR_DTR			0x01	// Assert DTR
+#define MCR_RTS			0x02	// Assert RTS
+#define MCR_OUT1		0x04	// Loopback only: Sets state of RI
+#define MCR_MASTER_IE		0x08	// Enable interrupt outputs
+#define MCR_LOOPBACK		0x10	// Set internal (digital) loopback mode
+#define MCR_XON_ANY		0x20	// Enable any char to exit XOFF mode
+#define MCR_IR_ENABLE		0x40	// Enable IrDA functions
+#define MCR_BRG_DIV_4		0x80	// Divide baud rate clk by /4 instead of /1
+
+
+#define LSR_RX_AVAIL		0x01	// Rx data available
+#define LSR_OVER_ERR		0x02	// Rx overrun
+#define LSR_PAR_ERR		0x04	// Rx parity error
+#define LSR_FRM_ERR		0x08	// Rx framing error
+#define LSR_BREAK		0x10	// Rx break condition detected
+#define LSR_TX_EMPTY		0x20	// Tx Fifo empty
+#define LSR_TX_ALL_EMPTY	0x40	// Tx Fifo and shift register empty
+#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
+
+
+
+					//	Tx		Rx
+					//-------------------------------
+#define EFR_SWFC_NONE		0x00	//	None		None
+#define EFR_SWFC_RX1		0x02 	//	None		XOFF1
+#define EFR_SWFC_RX2		0x01 	//	None		XOFF2
+#define EFR_SWFC_RX12		0x03 	//	None		XOFF1 & XOFF2
+#define EFR_SWFC_TX1		0x08 	//	XOFF1		None
+#define EFR_SWFC_TX1_RX1	0x0a 	//	XOFF1		XOFF1
+#define EFR_SWFC_TX1_RX2	0x09 	//	XOFF1		XOFF2
+#define EFR_SWFC_TX1_RX12	0x0b 	//	XOFF1		XOFF1 & XOFF2
+#define EFR_SWFC_TX2		0x04 	//	XOFF2		None
+#define EFR_SWFC_TX2_RX1	0x06 	//	XOFF2		XOFF1
+#define EFR_SWFC_TX2_RX2	0x05 	//	XOFF2		XOFF2
+#define EFR_SWFC_TX2_RX12	0x07 	//	XOFF2		XOFF1 & XOFF2
+#define EFR_SWFC_TX12		0x0c 	//	XOFF1 & XOFF2	None
+#define EFR_SWFC_TX12_RX1	0x0e 	//	XOFF1 & XOFF2	XOFF1
+#define EFR_SWFC_TX12_RX2	0x0d 	//	XOFF1 & XOFF2	XOFF2
+#define EFR_SWFC_TX12_RX12	0x0f 	//	XOFF1 & XOFF2	XOFF1 & XOFF2
+
+#define EFR_TX_FC_MASK		0x0c	// Mask to isolate Rx flow control
+#define EFR_TX_FC_NONE		0x00	// No Tx Xon/Xoff flow control
+#define EFR_TX_FC_X1		0x08	// Transmit Xon1/Xoff1
+#define EFR_TX_FC_X2		0x04	// Transmit Xon2/Xoff2
+#define EFR_TX_FC_X1_2		0x0c	// Transmit Xon1&2/Xoff1&2
+
+#define EFR_RX_FC_MASK		0x03	// Mask to isolate Rx flow control
+#define EFR_RX_FC_NONE		0x00	// No Rx Xon/Xoff flow control
+#define EFR_RX_FC_X1		0x02	// Receiver compares Xon1/Xoff1
+#define EFR_RX_FC_X2		0x01	// Receiver compares Xon2/Xoff2
+#define EFR_RX_FC_X1_2		0x03	// Receiver compares Xon1&2/Xoff1&2
+
+
+#define EFR_SWFC_MASK		0x0F	// Mask for software flow control field
+#define EFR_ENABLE_16654	0x10	// Enable 16C654 features
+#define EFR_SPEC_DETECT		0x20	// Enable special character detect interrupt
+#define EFR_AUTO_RTS		0x40	// Use RTS for Rx flow control
+#define EFR_AUTO_CTS		0x80	// Use CTS for Tx flow control
+
+#endif	// if !defined(_16654_H)
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- v2.4.2/linux/drivers/usb/serial/io_edgeport.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_edgeport.c	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,3143 @@
+/*
+ * Edgeport USB Serial Converter driver
+ *
+ * Copyright(c) 2000 Inside Out Networks, All rights reserved.
+ * Copyright(c) 2001 Greg Kroah-Hartman <greg@kroah.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.
+ *
+ * Supports the following devices:
+ *	Edgeport/4
+ *	Edgeport/4t
+ *	Edgeport/2
+ *	Edgeport/4i
+ *	Edgeport/2i
+ *	Edgeport/421
+ *	Edgeport/21
+ *	Rapidport/4
+ *	Edgeport/8
+ *	Edgeport/2D8
+ *	Edgeport/4D8
+ *	Edgeport/8i
+ *
+ * Version history:
+ *
+ * 2.0 2001_03_05 greg kroah-hartman
+ *	- reworked entire driver to fit properly in with the other usb-serial
+ *	  drivers.  Occasional oopses still happen, but it's a good start.
+ *
+ * 1.2.3 (02/23/2001) greg kroah-hartman
+ *	- changed device table to work properly for 2.4.x final format.
+ *	- fixed problem with dropping data at high data rates.
+ *
+ * 1.2.2 (11/27/2000) greg kroah-hartman
+ *	- cleaned up more NTisms.
+ *	- Added device table for 2.4.0-test11
+ *
+ * 1.2.1 (11/08/2000) greg kroah-hartman
+ *	- Started to clean up NTisms.
+ *	- Fixed problem with dev field of urb for kernels >= 2.4.0-test9
+ *
+ * 1.2 (10/17/2000) David Iacovelli
+ * 	Remove all EPIC code and GPL source
+ *  Fix RELEVANT_IFLAG macro to include flow control 
+ *  changes port configuration changes.
+ *  Fix redefinition of SERIAL_MAGIC
+ *  Change all timeout values to 5 seconds
+ *  Tried to fix the UHCI multiple urb submission, but failed miserably.
+ *  it seems to work fine with OHCI.
+ *  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must 
+ *    find a way to work arount this UHCI bug )
+ *
+ * 1.1 (10/11/2000) David Iacovelli
+ *  Fix XON/XOFF flow control to support both IXON and IXOFF
+ *
+ * 0.9.27 (06/30/2000) David Iacovelli
+ *  Added transmit queue and now allocate urb for command writes.
+ *
+ * 0.9.26 (06/29/2000) David Iacovelli
+ *  Add support for 80251 based edgeport
+ *
+ * 0.9.25 (06/27/2000) David Iacovelli
+ *  Do not close the port if it has multiple opens.
+ *
+ * 0.9.24 (05/26/2000) David Iacovelli
+ *  Add IOCTLs to support RXTX and JAVA POS 
+ *  and first cut at running BlackBox Demo
+ *
+ * 0.9.23 (05/24/2000) David Iacovelli
+ *  Add IOCTLs to support RXTX and JAVA POS
+ *
+ * 0.9.22 (05/23/2000) David Iacovelli
+ *  fixed bug in enumeration.  If epconfig turns on mapping by
+ *  path after a device is already plugged in, we now update
+ *  the mapping correctly
+ *
+ * 0.9.21 (05/16/2000) David Iacovelli
+ *  Added BlockUntilChaseResp() to also wait for txcredits
+ *  Updated the way we allocate and handle write URBs 
+ *	Add debug code to dump buffers
+ *
+ * 0.9.20 (05/01/2000) David Iacovelli
+ *	change driver to use usb/tts/
+ *
+ * 0.9.19 (05/01/2000) David Iacovelli
+ *  Update code to compile if DEBUG is off
+ *
+ * 0.9.18 (04/28/2000) David Iacovelli
+ *  cleanup and test tty_register with devfs
+ *
+ * 0.9.17 (04/27/2000) greg kroah-hartman
+ * 	changed tty_register around to be like the way it
+ * 	was before, but now it works properly with devfs.
+ *
+ * 0.9.16 (04/26/2000) david iacovelli
+ *  Fixed bug in GetProductInfo()
+ *
+ * 0.9.15 (04/25/2000) david iacovelli
+ *	Updated enumeration
+ *
+ * 0.9.14 (04/24/2000) david iacovelli
+ *  Removed all config/status IOCTLS and 
+ *  converted to using /proc/edgeport
+ *  still playing with devfs
+ *
+ * 0.9.13 (04/24/2000) david iacovelli
+ *  Removed configuration based on ttyUSB0
+ *  Added support for configuration using /prod/edgeport
+ *  first attempt at using devfs (not working yet!)
+ *  Added IOCTL to GetProductInfo()
+ *  Added support for custom baud rates
+ *	Add support for random port numbers
+ *
+ * 0.9.12 (04/18/2000) david iacovelli
+ *	added additional configuration IOCTLs
+ *  use ttyUSB0 for configuration
+ *
+ * 0.9.11 (04/17/2000) greg kroah-hartman
+ *	fixed module initialization race conditions.
+ *	made all urbs dynamically allocated.
+ *	made driver devfs compatible. now it only registers the tty device
+ *	when the device is actually plugged in.
+ *
+ * 0.9.10 (04/13/2000) greg kroah-hartman
+ *	added proc interface framework.
+ *
+ * 0.9.9 (04/13/2000) david iacovelli
+ *	added enumeration code and ioctls to configure the device
+ *
+ * 0.9.8 (04/12/2000) david iacovelli
+ *  Change interrupt read start when device is plugged in
+ *  and stop when device is removed
+ *	process interrupt reads when all ports are closed 
+ *  (keep value of rxBytesAvail consistent with the edgeport)
+ *  set the USB_BULK_QUEUE flag so that we can shove a bunch 
+ *  of urbs at once down the pipe 
+ *
+ * 0.9.7 (04/10/2000) david iacovelli
+ * 	start to add enumeration code.
+ *  generate serial number for epic devices
+ *  add support for kdb
+ *
+ * 0.9.6 (03/30/2000) david iacovelli
+ *  add IOCTL to get string, manufacture, and boot descriptors
+ *
+ * 0.9.5 (03/14/2000) greg kroah-hartman
+ *	more error checking added to SerialOpen to try to fix UHCI open problem
+ *
+ * 0.9.4 (03/09/2000) greg kroah-hartman
+ *	added more error checking to handle oops when data is hanging
+ *	around and tty is abruptly closed.
+ *
+ * 0.9.3 (03/09/2000) david iacovelli
+ *	Add epic support for xon/xoff chars
+ *	play with performance
+ *
+ * 0.9.2 (03/08/2000) greg kroah-hartman
+ *	changed most "info" calls to "dbg"
+ *	implemented flow control properly in the termios call
+ *
+ * 0.9.1 (03/08/2000) david iacovelli
+ *	added EPIC support
+ *	enabled bootloader update
+ *
+ * 0.9 (03/08/2000) greg kroah-hartman
+ *	Release to IO networks.
+ *	Integrated changes that David made
+ *  made getting urbs for writing SMP safe
+ *
+ * 0.8 (03/07/2000) greg kroah-hartman
+ *	Release to IO networks.
+ *	Fixed problems that were seen in code by David.
+ *  Now both Edgeport/4 and Edgeport/2 works properly.
+ *  Changed most of the functions to use port instead of serial.
+ *
+ * 0.7 (02/27/2000) greg kroah-hartman
+ *	Milestone 3 release.
+ *	Release to IO Networks
+ *	ioctl for waiting on line change implemented.
+ *	ioctl for getting statistics implemented.
+ *	multiport support working.
+ *	lsr and msr registers are now handled properly.
+ *	change break now hooked up and working.
+ *	support for all known Edgeport devices.
+ *
+ * 0.6 (02/22/2000) greg kroah-hartman
+ *	Release to IO networks.
+ *	CHASE is implemented correctly when port is closed.
+ *	SerialOpen now blocks correctly until port is fully opened.
+ *
+ * 0.5 (02/20/2000) greg kroah-hartman
+ *	Release to IO networks.
+ *	Known problems:
+ *		modem status register changes are not sent on to the user
+ *		CHASE is not implemented when the port is closed.
+ *
+ * 0.4 (02/16/2000) greg kroah-hartman
+ *	Second cut at the CeBit demo.
+ *	Doesn't leak memory on every write to the port
+ *	Still small leaks on startup.
+ *	Added support for Edgeport/2 and Edgeport/8
+ *
+ * 0.3 (02/15/2000) greg kroah-hartman
+ *	CeBit demo release.
+ *	Force the line settings to 4800, 8, 1, e for the demo.
+ *	Warning! This version leaks memory like crazy!
+ *
+ * 0.2 (01/30/2000) greg kroah-hartman
+ *	Milestone 1 release.
+ *	Device is found by USB subsystem, enumerated, fimware is downloaded
+ *	and the descriptors are printed to the debug log, config is set, and
+ *	green light starts to blink. Open port works, and data can be sent
+ *	and received at the default settings of the UART. Loopback connector
+ *	and debug log confirms this.
+ * 
+ * 0.1 (01/23/2000) greg kroah-hartman
+ *	Initial release to help IO Networks try to set up their test system. 
+ *	Edgeport4 is recognized, firmware is downloaded, config is set so 
+ *	device blinks green light every 3 sec. Port is bound, but opening,
+ *	closing, and sending data do not work properly.
+ * 
+ */
+
+#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/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/serial.h>
+#include <linux/ioctl.h>
+#include <linux/proc_fs.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "io_edgeport.h"
+#include "io_ionsp.h"		/* info for the iosp messages */
+#include "io_16654.h"		/* 16654 UART defines */
+
+/* First, the latest boot code - for first generation edgeports */
+#define IMAGE_ARRAY_NAME	BootCodeImage_GEN1
+#define IMAGE_VERSION_NAME	BootCodeImageVersion_GEN1
+#include "io_fw_boot.h"		/* the bootloader firmware to download to a device, if it needs it */
+
+/* for second generation edgeports */
+#define IMAGE_ARRAY_NAME	BootCodeImage_GEN2
+#define IMAGE_VERSION_NAME	BootCodeImageVersion_GEN2
+#include "io_fw_boot2.h"	/* the bootloader firmware to download to a device, if it needs it */
+
+/* Then finally the main run-time operational code - for first generation edgeports */
+#define IMAGE_ARRAY_NAME	OperationalCodeImage_GEN1
+#define IMAGE_VERSION_NAME	OperationalCodeImageVersion_GEN1
+#include "io_fw_down.h"		/* Define array OperationalCodeImage[] */
+
+/* for second generation edgeports */
+#define IMAGE_ARRAY_NAME	OperationalCodeImage_GEN2
+#define IMAGE_VERSION_NAME	OperationalCodeImageVersion_GEN2
+#include "io_fw_down2.h"	/* Define array OperationalCodeImage[] */
+
+
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli");
+MODULE_DESCRIPTION("Edgeport USB Serial Driver");
+
+#define MAX_NAME_LEN		64
+
+
+#define CHASE_TIMEOUT		(5*HZ)		/* 5 seconds */
+#define OPEN_TIMEOUT		(5*HZ)		/* 5 seconds */
+#define COMMAND_TIMEOUT		(5*HZ)		/* 5 seconds */
+
+#ifndef SERIAL_MAGIC
+	#define SERIAL_MAGIC	0x6702
+#endif
+#define PORT_MAGIC		0x7301
+
+
+/* receive port state */
+enum RXSTATE {
+	EXPECT_HDR1 = 0,	/* Expect header byte 1 */
+	EXPECT_HDR2 = 1,	/* Expect header byte 2 */
+	EXPECT_DATA = 2,	/* Expect 'RxBytesRemaining' data */
+	EXPECT_HDR3 = 3,	/* Expect header byte 3 (for status hdrs only) */
+};
+
+
+/* the info for all of the devices that this driver supports */
+int EdgeportDevices[] = EDGEPORT_DEVICE_IDS;
+#define NUM_EDGEPORT_DEVICES (sizeof(EdgeportDevices) / sizeof(int))
+
+
+/* Transmit Fifo 
+ * This Transmit queue is an extension of the edgeport Rx buffer. 
+ * The maximum amount of data buffered in both the edgeport 
+ * Rx buffer (maxTxCredits) and this buffer will never exceed maxTxCredits.
+ */
+struct TxFifo {
+	unsigned int	head;	/* index to head pointer (write) */
+	unsigned int	tail;	/* index to tail pointer (read)  */
+	unsigned int	count;	/* Bytes in queue */
+	unsigned int	size;	/* Max size of queue (equal to Max number of TxCredits) */
+	unsigned char	*fifo;	/* allocated Buffer */
+};
+
+/* This structure holds all of the local port information */
+struct edgeport_port {
+	__u16			txCredits;		/* our current credits for this port */
+	__u16			maxTxCredits;		/* the max size of the port */
+
+	struct TxFifo		txfifo;			/* transmit fifo -- size will be maxTxCredits */
+	struct urb		*write_urb;		/* write URB for this port */
+	char			write_in_progress;	/* TRUE while a write URB is outstanding */
+
+	__u8			shadowLCR;		/* last LCR value received */
+	__u8			shadowMCR;		/* last MCR value received */
+	__u8			shadowMSR;		/* last MSR value received */
+	__u8			shadowLSR;		/* last LSR value received */
+	__u8			shadowXonChar;		/* last value set as XON char in Edgeport */
+	__u8			shadowXoffChar;		/* last value set as XOFF char in Edgeport */
+	__u8			validDataMask;
+	__u32			baudRate;
+
+	char			open;
+	char			openPending;
+	char			commandPending;
+	char			closePending;
+	char			chaseResponsePending;
+
+	wait_queue_head_t	wait_chase;		/* for handling sleeping while waiting for chase to finish */
+	wait_queue_head_t	wait_open;		/* for handling sleeping while waiting for open to finish */
+	wait_queue_head_t	wait_command;		/* for handling sleeping while waiting for command to finish */
+	wait_queue_head_t	delta_msr_wait;		/* for handling sleeping while waiting for msr change to happen */
+
+	struct async_icount	icount;
+	struct usb_serial_port	*port;			/* loop back to the owner of this object */
+};
+
+
+/* This structure holds all of the individual device information */
+struct edgeport_serial {
+	char			name[MAX_NAME_LEN+1];		/* string name of this device */
+
+	EDGE_MANUF_DESCRIPTOR		manuf_descriptor;	/* the manufacturer descriptor */
+	EDGE_BOOT_DESCRIPTOR		boot_descriptor;	/* the boot firmware descriptor */
+	struct edgeport_product_info	product_info;		/* Product Info */
+
+	__u8			interrupt_in_endpoint;		/* the interrupt endpoint handle */
+	unsigned char *		interrupt_in_buffer;		/* the buffer we use for the interrupt endpoint */
+	struct urb *		interrupt_read_urb;		/* our interrupt urb */
+
+	__u8			bulk_in_endpoint;		/* the bulk in endpoint handle */
+	unsigned char *		bulk_in_buffer;			/* the buffer we use for the bulk in endpoint */
+	struct urb *		read_urb;			/* our bulk read urb */
+
+	__u8			bulk_out_endpoint;		/* the bulk out endpoint handle */
+
+	__s16			rxBytesAvail;			/* the number of bytes that we need to read from this device */
+
+	enum RXSTATE		rxState;			/* the current state of the bulk receive processor */
+	__u8			rxHeader1;			/* receive header byte 1 */
+	__u8			rxHeader2;			/* receive header byte 2 */
+	__u8			rxHeader3;			/* receive header byte 3 */
+	__u8			rxPort;				/* the port that we are currently receiving data for */
+	__u8			rxStatusCode;			/* the receive status code */
+	__u8			rxStatusParam;			/* the receive status paramater */
+	__s16			rxBytesRemaining;		/* the number of port bytes left to read */
+	struct usb_serial	*serial;			/* loop back to the owner of this object */
+};
+
+/* baud rate information */
+typedef struct _DIVISOR_TABLE_ENTRY {
+	__u32   BaudRate;
+	__u16  Divisor;
+} DIVISOR_TABLE_ENTRY, *PDIVISOR_TABLE_ENTRY;
+
+//
+// Define table of divisors for Rev A EdgePort/4 hardware
+// These assume a 3.6864MHz crystal, the standard /16, and
+// MCR.7 = 0.
+//
+static DIVISOR_TABLE_ENTRY  DivisorTable[] = {
+	{   75,		3072},  
+	{   110,	2095},		/* 2094.545455 => 230450   => .0217 % over */
+	{   134,	1713},		/* 1713.011152 => 230398.5 => .00065% under */
+	{   150,	1536},
+	{   300,	768},
+	{   600,	384},
+	{   1200,	192},
+	{   1800,	128},
+	{   2400,	96},
+	{   4800,	48},
+	{   7200,	32},
+	{   9600,	24},
+	{   14400,	16},
+	{   19200,	12},
+	{   38400,	6},
+	{   57600,	4},
+	{   115200,	2},
+	{   230400,	1},
+};
+
+/* local variables */
+static int	CmdUrbs = 0;							/* Number of outstanding Command Write Urbs */
+
+
+/* local function prototypes */
+
+/* function prototypes for all URB callbacks */
+static void edge_interrupt_callback	(struct urb *urb);
+static void edge_bulk_in_callback		(struct urb *urb);
+static void edge_bulk_out_data_callback	(struct urb *urb);
+static void edge_bulk_out_cmd_callback	(struct urb *urb);
+
+/* function prototypes for the usbserial callbacks */
+static int  edge_open			(struct usb_serial_port *port, struct file *filp);
+static void edge_close			(struct usb_serial_port *port, struct file *filp);
+static int  edge_write			(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  edge_write_room		(struct usb_serial_port *port);
+static int  edge_chars_in_buffer	(struct usb_serial_port *port);
+static void edge_throttle		(struct usb_serial_port *port);
+static void edge_unthrottle		(struct usb_serial_port *port);
+static void edge_set_termios		(struct usb_serial_port *port, struct termios *old_termios);
+static int  edge_ioctl			(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
+static void edge_break			(struct usb_serial_port *port, int break_state);
+static int  edge_startup		(struct usb_serial *serial);
+static void edge_shutdown		(struct usb_serial *serial);
+
+
+#include "io_tables.h"	/* all of the devices that this driver supports */
+
+
+/* function prototypes for all of our local functions */
+static int  process_rcvd_data		(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
+static void process_rcvd_status		(struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
+static void handle_new_msr		(struct edgeport_port *edge_port, __u8 newMsr);
+static void handle_new_lsr		(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data);
+static int  send_iosp_ext_cmd		(struct edgeport_port *edge_port, __u8 command, __u8 param);
+static int  calc_baud_rate_divisor	(int baud_rate, int *divisor);
+static int  send_cmd_write_baud_rate	(struct edgeport_port *edge_port, int baudRate);
+static void change_port_settings	(struct edgeport_port *edge_port, struct termios *old_termios);
+static int  send_cmd_write_uart_register	(struct edgeport_port *edge_port, __u8 regNum, __u8 regValue);
+static int  write_cmd_usb		(struct edgeport_port *edge_port, unsigned char *buffer, int writeLength);
+static void send_more_port_data		(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port);
+
+static int  sram_write			(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data);
+static int  rom_read			(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data);
+static int  rom_write			(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data);
+static void get_manufacturing_desc	(struct edgeport_serial *edge_serial);
+static void get_boot_desc		(struct edgeport_serial *edge_serial);
+static void load_application_firmware	(struct edgeport_serial *edge_serial);
+
+
+static void unicode_to_ascii		(char *string, short *unicode, int unicode_size);
+
+static int  get_string_desc		(struct usb_device *dev, int Id, struct usb_string_descriptor **pRetDesc);
+
+
+
+
+
+#ifdef DEBUG
+
+/* Dump a buffer in HEX and Ascii */
+void DbgDisplayBuffer( void *pBuffer, __u32 Len )
+{
+	char    DisplayBuf[80];
+	char *  pStr = DisplayBuf;
+	__u8 *pBuf = pBuffer; 
+	__u32   i;
+	__u8   d;
+
+	while (Len) {
+		// Init for new line
+		memset( DisplayBuf, ' ', sizeof( DisplayBuf ));
+		DisplayBuf[79]=0;
+		pStr = DisplayBuf;
+		pStr[54] = '[';
+		pStr[71] = ']';
+
+		for ( i = 0; i < MIN(16, Len) ; i++ ) {
+			d = (__u8)(*pBuf >> 4);
+			pStr[(i*3)+0] = (char)((d < 10) ? d+'0' : d -10 + 'A');
+			d = (__u8)(*pBuf & 0xf);
+			pStr[(i*3)+1] = (char)((d < 10) ? d+'0' : d -10 + 'A');
+
+			if (*pBuf > 31 && *pBuf < 127)
+				pStr[i+55]=*pBuf;
+			else
+				pStr[i+55]='.';
+
+			pBuf++;
+		}
+		Len -= i;
+		dbg("%s", DisplayBuf );
+	}
+}
+#endif
+
+
+
+// ************************************************************************
+// ************************************************************************
+// ************************************************************************
+// ************************************************************************
+
+// These functions should be in firmware.c
+
+/************************************************************************
+ *									*
+ *	update_edgeport_E2PROM()	Compare current versions of		*
+ *				Boot ROM and Manufacture 		*
+ *				Descriptors with versions		*
+ *				embedded in this driver			*
+ *									*
+ ************************************************************************/
+void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
+{
+	__u32 BootCurVer;
+	__u32 BootNewVer;
+	__u8 BootMajorVersion;                  
+	__u8 BootMinorVersion;                  
+	__u16 BootBuildNumber;
+	__u8 *BootImage;      
+	__u32 BootSize;
+	PEDGE_FIRMWARE_IMAGE_RECORD record;
+	unsigned char *firmware;
+	int response;
+
+
+	switch (edge_serial->product_info.iDownloadFile) {
+		case EDGE_DOWNLOAD_FILE_I930:
+			BootMajorVersion	= BootCodeImageVersion_GEN1.MajorVersion;
+			BootMinorVersion	= BootCodeImageVersion_GEN1.MinorVersion;
+			BootBuildNumber		= BootCodeImageVersion_GEN1.BuildNumber;
+			BootImage		= &BootCodeImage_GEN1[0];
+			BootSize		= sizeof( BootCodeImage_GEN1 );
+			break;
+
+		case EDGE_DOWNLOAD_FILE_80251:
+			BootMajorVersion	= BootCodeImageVersion_GEN2.MajorVersion;
+			BootMinorVersion	= BootCodeImageVersion_GEN2.MinorVersion;
+			BootBuildNumber		= BootCodeImageVersion_GEN2.BuildNumber;
+			BootImage		= &BootCodeImage_GEN2[0];
+			BootSize		= sizeof( BootCodeImage_GEN2 );
+			break;
+
+		default:
+			return;
+	}
+
+	// Check Boot Image Version
+	BootCurVer = (edge_serial->boot_descriptor.MajorVersion << 24) +
+		     (edge_serial->boot_descriptor.MinorVersion << 16) +
+		      edge_serial->boot_descriptor.BuildNumber;
+
+	BootNewVer = (BootMajorVersion << 24) +
+		     (BootMinorVersion << 16) +
+		      BootBuildNumber;
+
+	dbg("Current Boot Image version %d.%d.%d",
+	    edge_serial->boot_descriptor.MajorVersion,
+	    edge_serial->boot_descriptor.MinorVersion,
+	    edge_serial->boot_descriptor.BuildNumber);
+
+
+	if (BootNewVer > BootCurVer) {
+		dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d",
+		    edge_serial->boot_descriptor.MajorVersion,
+		    edge_serial->boot_descriptor.MinorVersion,
+		    edge_serial->boot_descriptor.BuildNumber,
+		    BootMajorVersion,
+		    BootMinorVersion,
+		    BootBuildNumber);
+
+
+		dbg("Downloading new Boot Image");
+
+		firmware = BootImage;
+
+		for (;;) {
+			record = (PEDGE_FIRMWARE_IMAGE_RECORD)firmware;
+			response = rom_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]);
+			if (response < 0) {
+				err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len);
+				break;
+			}
+			firmware += sizeof (EDGE_FIRMWARE_IMAGE_RECORD) + record->Len;
+			if (firmware >= &BootImage[BootSize]) {
+				break;
+			}
+		}
+	} else {
+		dbg("Boot Image -- already up to date");
+	}
+}
+
+
+/************************************************************************
+ *									*
+ *  Get string descriptor from device					*
+ *									*
+ ************************************************************************/
+static int get_string (struct usb_device *dev, int Id, char *string)
+{
+	struct usb_string_descriptor StringDesc;
+	struct usb_string_descriptor *pStringDesc;
+
+	dbg(__FUNCTION__ " - USB String ID = %d", Id );
+
+	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) {
+		return 0;
+	}
+
+	pStringDesc = kmalloc (StringDesc.bLength, GFP_KERNEL);
+
+	if (!pStringDesc) {
+		return 0;
+	}
+
+	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, pStringDesc, StringDesc.bLength )) {
+		kfree(pStringDesc);
+		return 0;
+	}
+
+	unicode_to_ascii(string,  pStringDesc->wData,     pStringDesc->bLength/2-1);
+
+	kfree(pStringDesc);
+	return strlen(string);
+}
+
+
+/************************************************************************
+ *
+ *  Get string descriptor from device
+ *
+ ************************************************************************/
+static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_descriptor **pRetDesc)
+{
+	struct usb_string_descriptor StringDesc;
+	struct usb_string_descriptor *pStringDesc;
+
+	dbg(__FUNCTION__ " - USB String ID = %d", Id );
+
+	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, sizeof(StringDesc))) {
+		return 0;
+	}
+
+	pStringDesc = kmalloc (StringDesc.bLength, GFP_KERNEL);
+
+	if (!pStringDesc) {
+		return -1;
+	}
+
+	if (!usb_get_descriptor(dev, USB_DT_STRING, Id, pStringDesc, StringDesc.bLength )) {
+		kfree(pStringDesc);
+		return -1;
+	}
+
+	*pRetDesc = pStringDesc;
+	return 0;
+}
+
+
+
+
+/************************************************************************
+ *																		*
+ *																		*
+ ************************************************************************/
+static void get_product_info(struct edgeport_serial *edge_serial)
+{
+	struct edgeport_product_info *product_info = &edge_serial->product_info;
+
+	memset (product_info, 0, sizeof(struct edgeport_product_info));
+
+	product_info->ProductId		= (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_GENERATION_2);
+	product_info->NumPorts		= edge_serial->manuf_descriptor.NumPorts;
+	product_info->ProdInfoVer	= 0;
+
+	product_info->RomSize		= edge_serial->manuf_descriptor.RomSize;
+	product_info->RamSize		= edge_serial->manuf_descriptor.RamSize;
+	product_info->CpuRev		= edge_serial->manuf_descriptor.CpuRev;
+	product_info->BoardRev		= edge_serial->manuf_descriptor.BoardRev;
+
+	product_info->BootMajorVersion	= edge_serial->boot_descriptor.MajorVersion;
+	product_info->BootMinorVersion	= edge_serial->boot_descriptor.MinorVersion;
+	product_info->BootBuildNumber	= edge_serial->boot_descriptor.BuildNumber;
+
+	memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate));
+
+	// check if this is 2nd generation hardware
+	if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) {
+		product_info->FirmwareMajorVersion	= OperationalCodeImageVersion_GEN2.MajorVersion;
+		product_info->FirmwareMinorVersion	= OperationalCodeImageVersion_GEN2.MinorVersion;
+		product_info->FirmwareBuildNumber	= OperationalCodeImageVersion_GEN2.BuildNumber;
+		product_info->iDownloadFile		= EDGE_DOWNLOAD_FILE_80251;
+	} else {
+		product_info->FirmwareMajorVersion	= OperationalCodeImageVersion_GEN1.MajorVersion;
+		product_info->FirmwareMinorVersion	= OperationalCodeImageVersion_GEN1.MinorVersion;
+		product_info->FirmwareBuildNumber	= OperationalCodeImageVersion_GEN1.BuildNumber;
+		product_info->iDownloadFile		= EDGE_DOWNLOAD_FILE_I930;
+	}
+
+	// Determine Product type and set appropriate flags
+	switch (DEVICE_ID_FROM_USB_PRODUCT_ID(product_info->ProductId)) {
+		case ION_DEVICE_ID_EDGEPORT_COMPATIBLE:
+		case ION_DEVICE_ID_EDGEPORT_4T:
+		case ION_DEVICE_ID_EDGEPORT_4:
+		case ION_DEVICE_ID_EDGEPORT_2:
+		case ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU:
+		case ION_DEVICE_ID_EDGEPORT_8:
+		case ION_DEVICE_ID_EDGEPORT_421:
+		case ION_DEVICE_ID_EDGEPORT_21:
+		case ION_DEVICE_ID_EDGEPORT_2_DIN:
+		case ION_DEVICE_ID_EDGEPORT_4_DIN:
+		case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU:
+			product_info->IsRS232 = 1;
+			break;
+
+		case ION_DEVICE_ID_EDGEPORT_2I:				   // Edgeport/2 RS422/RS485
+			product_info->IsRS422 = 1;
+			product_info->IsRS485 = 1;
+			break;
+
+		case ION_DEVICE_ID_EDGEPORT_8I:				   // Edgeport/4 RS422
+		case ION_DEVICE_ID_EDGEPORT_4I:				   // Edgeport/4 RS422
+			product_info->IsRS422 = 1;
+			break;
+	}
+
+#ifdef DEBUG
+	// Dump Product Info structure
+	dbg("**Product Information:");
+	dbg("  ProductId             %x", product_info->ProductId );
+	dbg("  NumPorts              %d", product_info->NumPorts );
+	dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
+	dbg("  IsServer              %d", product_info->IsServer);
+	dbg("  IsRS232               %d", product_info->IsRS232 );
+	dbg("  IsRS422               %d", product_info->IsRS422 );
+	dbg("  IsRS485               %d", product_info->IsRS485 );
+	dbg("  RomSize               %d", product_info->RomSize );
+	dbg("  RamSize               %d", product_info->RamSize );
+	dbg("  CpuRev                %x", product_info->CpuRev  );
+	dbg("  BoardRev              %x", product_info->BoardRev);
+	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
+	    product_info->BootMinorVersion,
+	    product_info->BootBuildNumber);
+	dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
+	    product_info->FirmwareMinorVersion,
+	    product_info->FirmwareBuildNumber);
+	dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
+	    product_info->ManufactureDescDate[1],
+	    product_info->ManufactureDescDate[2]+1900);
+	dbg("  iDownloadFile         0x%x",     product_info->iDownloadFile);
+
+#endif
+}
+
+
+/************************************************************************/
+/************************************************************************/
+/*            U S B  C A L L B A C K   F U N C T I O N S                */
+/*            U S B  C A L L B A C K   F U N C T I O N S                */
+/************************************************************************/
+/************************************************************************/
+
+/*****************************************************************************
+ * edge_interrupt_callback
+ *	this is the callback function for when we have received data on the 
+ *	interrupt endpoint.
+ *****************************************************************************/
+static void edge_interrupt_callback (struct urb *urb)
+{
+	struct edgeport_serial	*edge_serial = (struct edgeport_serial *)urb->context;
+	struct edgeport_port *edge_port;
+	struct usb_serial_port *port;
+	unsigned char *data = urb->transfer_buffer;
+	int length = urb->actual_length;
+	int bytes_avail;
+	int position;
+	int txCredits;
+	int portNumber;
+	int result;
+
+	dbg(__FUNCTION__);
+
+	if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__" - nonzero control read status received: %d", urb->status);
+		return;
+	}
+
+	// process this interrupt-read even if there are no ports open
+	if (length) {
+#ifdef DEBUG
+		int i;
+		printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, data = ", length);
+		for (i = 0; i < length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+#endif
+
+		if (length > 1) {
+			bytes_avail = data[0] | (data[1] << 8);
+			if (bytes_avail) {
+				edge_serial->rxBytesAvail += bytes_avail;
+				dbg(__FUNCTION__" - bytes_avail = %d, rxBytesAvail %d", bytes_avail, edge_serial->rxBytesAvail);
+
+				if ((edge_serial->rxBytesAvail > 0) &&
+				    (edge_serial->read_urb->status != -EINPROGRESS)) {
+					dbg(" --- Posting a read");
+
+					/* we have pending bytes on the bulk in pipe, send a request */
+					edge_serial->read_urb->dev = edge_serial->serial->dev;
+					result = usb_submit_urb(edge_serial->read_urb);
+					if (result) {
+						dbg(__FUNCTION__" - usb_submit_urb(read bulk) failed with result = %d", result);
+					}
+				}
+			}
+		}
+		/* grab the txcredits for the ports if available */
+		position = 2;
+		portNumber = 0;
+		while ((position < length) && (portNumber < edge_serial->serial->num_ports)) {
+			txCredits = data[position] | (data[position+1] << 8);
+			if (txCredits) {
+				port = &edge_serial->serial->port[portNumber];
+				if (port_paranoia_check (port, __FUNCTION__) == 0) {
+					edge_port = (struct edgeport_port *)port->private;
+					if (edge_port->open) {
+						edge_port->txCredits += txCredits;
+						dbg(__FUNCTION__" - txcredits for port%d = %d", portNumber, edge_port->txCredits);
+
+						/* tell the tty driver that something has changed */
+						wake_up_interruptible(&edge_port->port->tty->write_wait);
+
+						// Since we have more credit, check if more data can be sent
+						send_more_port_data(edge_serial, edge_port);
+					}
+				}
+			}
+			position += 2;
+			++portNumber;
+		}
+	}
+}
+
+
+/*****************************************************************************
+ * edge_bulk_in_callback
+ *	this is the callback function for when we have received data on the 
+ *	bulk in endpoint.
+ *****************************************************************************/
+static void edge_bulk_in_callback (struct urb *urb)
+{
+	struct edgeport_serial	*edge_serial = (struct edgeport_serial *)urb->context;
+	unsigned char		*data = urb->transfer_buffer;
+	int			status;
+	__u16			raw_data_length;
+
+	dbg(__FUNCTION__);
+
+	if (serial_paranoia_check (edge_serial->serial, __FUNCTION__)) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__" - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+	if (urb->actual_length) {
+		raw_data_length = urb->actual_length;
+
+#ifdef DEBUG
+		{
+//			int i;
+			dbg (__FUNCTION__" - length = %d, data = ", raw_data_length);
+//			DbgDisplayBuffer((void *)data, raw_data_length);
+		}
+#endif
+
+		/* decrement our rxBytes available by the number that we just got */
+		edge_serial->rxBytesAvail -= raw_data_length;
+
+		dbg(__FUNCTION__" - Received = %d, rxBytesAvail %d", raw_data_length, edge_serial->rxBytesAvail);
+
+		process_rcvd_data (edge_serial, data, urb->actual_length);
+
+		/* check to see if there's any more data for us to read */
+		if ((edge_serial->rxBytesAvail > 0) &&
+		    (edge_serial->read_urb->status != -EINPROGRESS)) {
+			dbg(" --- Posting a read");
+
+			/* there is, so resubmit our urb */
+			edge_serial->read_urb->dev = edge_serial->serial->dev;
+			status = usb_submit_urb(edge_serial->read_urb);
+			if (status) {
+				err(__FUNCTION__" - usb_submit_urb(read bulk) failed, status = %d", status);
+			}
+		}
+	}
+}
+
+
+/*****************************************************************************
+ * edge_bulk_out_data_callback
+ *	this is the callback function for when we have finished sending serial data
+ *	on the bulk out endpoint.
+ *****************************************************************************/
+static void edge_bulk_out_data_callback (struct urb *urb)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+	struct tty_struct *tty;
+
+	dbg(__FUNCTION__);
+
+	if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status);
+	}
+
+	tty = edge_port->port->tty;
+
+	/* let the tty driver wakeup if it has a special write_wakeup function */
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+		(tty->ldisc.write_wakeup)(tty);
+	}
+
+	/* tell the tty driver that something has changed */
+	wake_up_interruptible(&tty->write_wait);
+
+	// Release the Write URB
+	edge_port->write_in_progress = FALSE;
+
+	// Check if more data needs to be sent
+	send_more_port_data((struct edgeport_serial *)(edge_port->port->serial->private), edge_port);
+}
+
+
+/*****************************************************************************
+ * BulkOutCmdCallback
+ *	this is the callback function for when we have finished sending a command
+ *	on the bulk out endpoint.
+ *****************************************************************************/
+static void edge_bulk_out_cmd_callback (struct urb *urb)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
+	struct tty_struct *tty;
+	int status = urb->status;
+
+	dbg(__FUNCTION__);
+
+#ifdef DEBUG	
+	CmdUrbs--;
+	dbg(__FUNCTION__" - FREE URB %p (outstanding %d)", urb, CmdUrbs);
+#endif
+
+
+	/* if this urb had a transfer buffer already (old transfer) free it */
+	if (urb->transfer_buffer != NULL) {
+		kfree(urb->transfer_buffer);
+	}
+
+	// Free the command urb
+	usb_unlink_urb (urb);
+	usb_free_urb   (urb);
+
+	if (port_paranoia_check (edge_port->port, __FUNCTION__)) {
+		return;
+	}
+
+	if (status) {
+		dbg(__FUNCTION__" - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	/* Get pointer to tty */
+	tty = edge_port->port->tty;
+
+	/* tell the tty driver that something has changed */
+	wake_up_interruptible(&tty->write_wait);
+
+
+	/* we have completed the command */
+	edge_port->commandPending = FALSE;
+	wake_up_interruptible(&edge_port->wait_command);
+}
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * SerialOpen
+ *	this function is called by the tty driver when a port is opened
+ *	If successful, we return 0
+ *	Otherwise we return a negative error number.
+ *****************************************************************************/
+static int edge_open (struct usb_serial_port *port, struct file * filp)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)port->private;
+	struct usb_serial *serial;
+	struct edgeport_serial *edge_serial;
+	int response;
+	int timeout;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	++port->open_count;
+	MOD_INC_USE_COUNT;
+	
+	if (!port->active) {
+		port->active = 1;
+
+		/* 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;
+	
+		/* see if we've set up our endpoint info yet (can't set it up in edge_startup
+		   as the structures were not set up at that time.) */
+		serial = port->serial;
+		edge_serial = (struct edgeport_serial *)serial->private;
+		if (edge_serial->interrupt_in_buffer == NULL) {
+			struct usb_serial_port *port0 = &serial->port[0];
+			
+			/* not set up yet, so do it now */
+			edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
+			edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
+			edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
+			edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
+			edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
+			edge_serial->read_urb = port0->read_urb;
+			edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
+		
+			/* set up our interrupt urb */
+			/* Like to use FILL_INT_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */
+			edge_serial->interrupt_read_urb->complete = edge_interrupt_callback;
+			edge_serial->interrupt_read_urb->context = edge_serial;
+			/* FILL_INT_URB(edge_serial->interrupt_read_urb, serial->dev, 
+				     usb_rcvintpipe (serial->dev, edge_serial->interrupt_in_endpoint),
+				     edge_serial->interrupt_in_buffer, edge_serial->interrupt_in_endpoint.wMaxPacketSize,
+				     edge_interrupt_callback, edge_serial, edge_serial->interrupt_in_endpoint.bInterval);
+			*/
+			
+			/* set up our bulk in urb */
+			/* Like to use FILL_BULK_URB, but we don't know wMaxPacketSize or bInterval, something to change for 2.5... */
+			edge_serial->read_urb->complete = edge_bulk_in_callback;
+			edge_serial->read_urb->context = edge_serial;
+			/* FILL_BULK_URB(edge_serial->read_urb, serial->dev, 
+				      usb_rcvbulkpipe (serial->dev, edge_serial->bulk_in_endpoint),
+				      edge_serial->bulk_in_buffer, edge_serial->bulk_in_endpoint->wMaxPacketSize,
+				      edge_bulk_in_callback, edge_serial);
+			*/
+		
+			/* start interrupt read for this edgeport
+			 * this interrupt will continue as long as the edgeport is connected */
+			response = usb_submit_urb (edge_serial->interrupt_read_urb);
+			if (response) {
+				err(__FUNCTION__" - Error %d submitting control urb", response);
+			}
+		}
+		
+		/* initialize our wait queues */
+		init_waitqueue_head(&edge_port->wait_open);
+		init_waitqueue_head(&edge_port->wait_chase);
+		init_waitqueue_head(&edge_port->delta_msr_wait);
+		init_waitqueue_head(&edge_port->wait_command);
+
+		/* initialize our icount structure */
+		memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+
+		/* initialize our port settings */
+		edge_port->txCredits            = 0;			/* Can't send any data yet */
+		edge_port->shadowMCR            = MCR_MASTER_IE;	/* Must always set this bit to enable ints! */
+		edge_port->chaseResponsePending = FALSE;
+
+		/* send a open port command */
+		edge_port->openPending = TRUE;
+		edge_port->open        = FALSE;
+		response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
+
+		if (response < 0) {
+			err(__FUNCTION__" - error sending open port command");
+			edge_port->openPending = FALSE;
+			port->active = 0;
+			port->open_count = 0;
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+
+		/* now wait for the port to be completly opened */
+		timeout = OPEN_TIMEOUT;
+		while (timeout && edge_port->openPending == TRUE) {
+			timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
+		}
+
+		if (edge_port->open == FALSE) {
+			/* open timed out */
+			dbg(__FUNCTION__" - open timedout");
+			edge_port->openPending = FALSE;
+			port->active = 0;
+			port->open_count = 0;
+			MOD_DEC_USE_COUNT;
+			return -ENODEV;
+		}
+
+		/* create the txfifo */
+		edge_port->txfifo.head	= 0;
+		edge_port->txfifo.tail	= 0;
+		edge_port->txfifo.count	= 0;
+		edge_port->txfifo.size	= edge_port->maxTxCredits;
+		edge_port->txfifo.fifo	= kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
+
+		if (!edge_port->txfifo.fifo) {
+			dbg(__FUNCTION__" - no memory");
+			edge_close (port, filp);
+			return -ENOMEM;
+		}
+
+		/* Allocate a URB for the write */
+		edge_port->write_urb = usb_alloc_urb (0);
+
+		if (!edge_port->write_urb) {
+			dbg(__FUNCTION__" - no memory");
+			edge_close (port, filp);
+			return -ENOMEM;
+		}
+
+		dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits);
+	}
+
+	dbg(__FUNCTION__" exited");
+
+	return 0;
+}
+
+
+/************************************************************************
+ *
+ * block_until_chase_response
+ *
+ *	This function will block the close until one of the following:
+ *		1. Response to our Chase comes from Edgeport
+ *		2. A timout of 10 seconds without activity has expired
+ *		   (1K of Edgeport data @ 2400 baud ==> 4 sec to empty)
+ *
+ ************************************************************************/
+static void block_until_chase_response(struct edgeport_port *edge_port)
+{
+	__u16 lastCredits;
+	int timeout = 1*HZ;
+	int wait = 10;
+
+	while (1) {
+		// Save Last credits
+		lastCredits = edge_port->txCredits;
+
+		// Did we get our Chase response
+		if (edge_port->chaseResponsePending == FALSE) {
+			dbg(__FUNCTION__" - Got Chase Response");
+
+			// did we get all of our credit back?
+			if (edge_port->txCredits == edge_port->maxTxCredits ) {
+				dbg(__FUNCTION__" - Got all credits");
+				return;
+			}
+		}
+
+		// Block the thread for a while
+		interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+
+		if (lastCredits == edge_port->txCredits) {
+			// No activity.. count down.
+			wait--;
+			if (wait == 0) {
+				edge_port->chaseResponsePending = FALSE;
+				dbg(__FUNCTION__" - Chase TIMEOUT");
+				return;
+			}
+		} else {
+			// Reset timout value back to 10 seconds
+			dbg(__FUNCTION__" - Last %d, Current %d", lastCredits, edge_port->txCredits);
+			wait = 10;
+		}
+	}
+}
+
+
+/************************************************************************
+ *
+ * block_until_tx_empty
+ *
+ *	This function will block the close until one of the following:
+ *		1. TX count are 0
+ *		2. The edgeport has stopped
+ *		3. A timout of 3 seconds without activity has expired
+ *
+ ************************************************************************/
+static void block_until_tx_empty (struct edgeport_port *edge_port)
+{
+	struct TxFifo *fifo = &edge_port->txfifo;
+	__u32 lastCount;
+	int timeout = HZ/10;
+	int wait = 30;
+
+	while (1) {
+		// Save Last count
+		lastCount = fifo->count;
+
+		// Is the Edgeport Buffer empty?
+		if (lastCount == 0) {
+			dbg(__FUNCTION__" - TX Buffer Empty");
+			return;
+		}
+
+		// Block the thread for a while
+		interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout);
+
+		dbg(__FUNCTION__ " wait");
+
+		if (lastCount == fifo->count) {
+			// No activity.. count down.
+			wait--;
+			if (wait == 0) {
+				dbg(__FUNCTION__" - TIMEOUT");
+				return;
+			}
+		} else {
+			// Reset timout value back to seconds
+			wait = 30;
+		}
+	}
+}
+
+
+/*****************************************************************************
+ * edge_close
+ *	this function is called by the tty driver when a port is closed
+ *****************************************************************************/
+static void edge_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial;
+	struct edgeport_serial *edge_serial;
+	struct edgeport_port *edge_port;
+	int status;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+			 
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+	
+	edge_serial = (struct edgeport_serial *)serial->private;
+	edge_port = (struct edgeport_port *)port->private;
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+		// block until tx is empty
+		block_until_tx_empty(edge_port);
+	
+		edge_port->closePending = TRUE;
+	
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
+	
+		dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
+	
+		/* close the port */
+		dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT");
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+	
+		//port->close = TRUE;
+		edge_port->closePending = FALSE;
+		edge_port->open = FALSE;
+		edge_port->openPending = FALSE;
+	
+		if (edge_port->write_urb) {
+			/* if this urb had a transfer buffer already (old transfer) free it */
+			if (edge_port->write_urb->transfer_buffer != NULL) {
+				kfree(edge_port->write_urb->transfer_buffer);
+			}
+	
+			usb_unlink_urb (edge_port->write_urb);
+			usb_free_urb   (edge_port->write_urb);
+		}
+	
+		if (edge_port->txfifo.fifo) {
+			kfree(edge_port->txfifo.fifo);
+		}
+	}
+
+	MOD_DEC_USE_COUNT;
+	dbg(__FUNCTION__" exited");
+}   
+
+
+
+
+/*****************************************************************************
+ * SerialWrite
+ *	this function is called by the tty driver when data should be written to
+ *	the port.
+ *	If successful, we return the number of bytes written, otherwise we return
+ *	a negative error number.
+ *****************************************************************************/
+static int edge_write (struct usb_serial_port *port, int from_user, const unsigned char *data, int count)
+{
+        struct edgeport_port *edge_port = (struct edgeport_port *)port->private;
+	struct TxFifo *fifo;
+	int copySize;
+	int bytesleft;
+	int firsthalf;
+	int secondhalf;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	// get a pointer to the Tx fifo
+	fifo = &edge_port->txfifo;
+
+	// calculate number of bytes to put in fifo
+	copySize = MIN(count, (edge_port->txCredits - fifo->count));
+
+	dbg(__FUNCTION__"(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes", 
+	    port->number, count, edge_port->txCredits - fifo->count, copySize);
+
+	/* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */
+	if (copySize == 0) {
+		dbg (__FUNCTION__" - copySize = Zero");
+		return 0;
+	}
+
+	// queue the data	
+	// since we can never overflow the buffer we do not have to check for full condition
+
+	// the copy is done is two parts -- first fill to the end of the buffer
+	// then copy the reset from the start of the buffer 
+
+	bytesleft = fifo->size - fifo->head;
+	firsthalf = MIN(bytesleft,copySize);
+	dbg (__FUNCTION__" - copy %d bytes of %d into fifo ", firsthalf, bytesleft);
+
+	/* now copy our data */
+	if (from_user) {
+		copy_from_user(&fifo->fifo[fifo->head], data, firsthalf);
+	} else {
+		memcpy(&fifo->fifo[fifo->head], data, firsthalf);
+	}  
+
+	// update the index and size
+	fifo->head  += firsthalf;
+	fifo->count += firsthalf;
+
+	// wrap the index
+	if (fifo->head == fifo->size) {
+		fifo->head = 0;
+	}
+
+	secondhalf = copySize-firsthalf;
+
+	if (secondhalf) {
+		dbg (__FUNCTION__" - copy rest of data %d", secondhalf);
+		if (from_user) {
+			copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
+		} else {
+			memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
+		}
+		// update the index and size
+		fifo->count += secondhalf;
+		fifo->head  += secondhalf;
+		// No need to check for wrap since we can not get to end of fifo in this part
+	}
+
+#ifdef DEBUG
+	if (copySize) {
+		dbg (__FUNCTION__" - length = %d, data = ", copySize);
+		DbgDisplayBuffer((void *)data, copySize);
+	}
+#endif
+
+	send_more_port_data((struct edgeport_serial *)port->serial->private, edge_port);
+
+	dbg(__FUNCTION__" wrote %d byte(s) TxCredits %d, Fifo %d", copySize, edge_port->txCredits, fifo->count);
+
+	return copySize;   
+}
+
+
+/************************************************************************
+ *
+ * send_more_port_data()
+ *
+ *	This routine attempts to write additional UART transmit data
+ *	to a port over the USB bulk pipe. It is called (1) when new
+ *	data has been written to a port's TxBuffer from higher layers
+ *	(2) when the peripheral sends us additional TxCredits indicating
+ *	that it can accept more	Tx data for a given port; and (3) when
+ *	a bulk write completes successfully and we want to see if we
+ *	can transmit more.
+ *
+ ************************************************************************/
+static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port)
+{
+	struct TxFifo	*fifo = &edge_port->txfifo;
+	struct urb	*urb;
+	unsigned char	*buffer;
+	int		status;
+	unsigned long	flags;
+	int		count;
+	int		bytesleft;
+	int		firsthalf;
+	int		secondhalf;
+
+	dbg(__FUNCTION__"(%d)", edge_port->port->number);
+
+	/* find our next free urb */	// ICK!!! FIXME!!!
+	save_flags(flags); cli();
+
+	if (edge_port->write_in_progress ||
+	    !edge_port->open             ||
+	    (fifo->count == 0)) {
+		restore_flags(flags);
+		dbg(__FUNCTION__"(%d) EXIT - fifo %d, PendingWrite = %d", edge_port->port->number, fifo->count, edge_port->write_in_progress);
+		return;
+	}
+
+	// since the amount of data in the fifo will always fit into the
+	// edgeport buffer we do not need to check the write length
+
+	//	Do we have enough credits for this port to make it worthwhile
+	//	to bother queueing a write. If it's too small, say a few bytes,
+	//	it's better to wait for more credits so we can do a larger
+	//	write.
+	if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) {
+		restore_flags(flags);
+		dbg(__FUNCTION__"(%d) Not enough credit - fifo %d TxCredit %d", edge_port->port->number, fifo->count, edge_port->txCredits );
+		return;
+	}
+
+	// lock this write
+	edge_port->write_in_progress = TRUE;
+	restore_flags(flags);
+
+	// get a pointer to the write_urb
+	urb = edge_port->write_urb;
+
+	/* if this urb had a transfer buffer already (old transfer) free it */
+	if (urb->transfer_buffer != NULL) {
+		kfree(urb->transfer_buffer);
+		urb->transfer_buffer = NULL;
+	}
+
+	/* build the data header for the buffer and port that we are about to send out */
+	count = fifo->count;
+	buffer = kmalloc (count+2, GFP_KERNEL);
+	if (buffer == NULL) {
+		err(__FUNCTION__" - no more kernel memory...");
+		edge_port->write_in_progress = FALSE;
+		return;
+	}
+	buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number, count);
+	buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number, count);
+
+	/* now copy our data */
+	bytesleft =  fifo->size - fifo->tail;
+	firsthalf = MIN(bytesleft,count);
+	memcpy(&buffer[2], &fifo->fifo[fifo->tail], firsthalf);
+	fifo->tail  += firsthalf;
+	fifo->count -= firsthalf;
+	if (fifo->tail == fifo->size) {
+		fifo->tail = 0;
+	}
+
+	secondhalf = count-firsthalf;
+	if (secondhalf) {
+		memcpy(&buffer[2+firsthalf], &fifo->fifo[fifo->tail], secondhalf);
+		fifo->tail  += secondhalf;
+		fifo->count -= secondhalf;
+	}
+
+#ifdef DEBUG
+	if (count) {
+		dbg (__FUNCTION__" - length = %d, data = ", count);
+		DbgDisplayBuffer((void *)&buffer[2], count);
+	}
+#endif
+
+	/* fill up the urb with all of our data and submit it */
+	FILL_BULK_URB (urb, edge_serial->serial->dev, 
+		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
+		       buffer, count+2, edge_bulk_out_data_callback, edge_port);
+
+	/* set the USB_BULK_QUEUE flag so that we can shove a bunch of urbs at once down the pipe */
+	urb->transfer_flags |= USB_QUEUE_BULK;
+
+	urb->dev = edge_serial->serial->dev;
+	status = usb_submit_urb(urb);
+	if (status) {
+		/* something went wrong */
+		dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
+		edge_port->write_in_progress = FALSE;
+	} else {
+		/* decrement the number of credits we have by the number we just sent */
+		edge_port->txCredits -= count;
+		edge_port->icount.tx += count;
+	}
+	dbg(__FUNCTION__" wrote %d byte(s) TxCredit %d, Fifo %d", count, edge_port->txCredits, fifo->count);
+}
+
+
+/*****************************************************************************
+ * edge_write_room
+ *	this function is called by the tty driver when it wants to know how many
+ *	bytes of data we can accept for a specific port.
+ *	If successful, we return the amount of room that we have for this port
+ *	(the txCredits), 
+ *	Otherwise we return a negative error number.
+ *****************************************************************************/
+static int edge_write_room (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int room;
+
+	dbg(__FUNCTION__);
+
+	if (edge_port->closePending == TRUE) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (!edge_port->open) {
+		dbg (__FUNCTION__" - port not opened");
+		return -EINVAL;
+	}
+
+	// total of both buffers is still txCredit
+	room = edge_port->txCredits - edge_port->txfifo.count;
+
+	dbg(__FUNCTION__" - returns %d", room);
+	return room;
+}
+
+
+/*****************************************************************************
+ * edge_chars_in_buffer
+ *	this function is called by the tty driver when it wants to know how many
+ *	bytes of data we currently have outstanding in the port (data that has
+ *	been written, but hasn't made it out the port yet)
+ *	If successful, we return the number of bytes left to be written in the 
+ *	system, 
+ *	Otherwise we return a negative error number.
+ *****************************************************************************/
+static int edge_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int num_chars;
+
+	dbg(__FUNCTION__);
+
+	if (!edge_port->open) {
+		dbg (__FUNCTION__" - port not opened");
+		return -EINVAL;
+	}
+
+	num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count;
+	if (num_chars) {
+		dbg(__FUNCTION__"(port %d) - returns %d", port->number, num_chars);
+	}
+
+	return num_chars;
+}
+
+
+/*****************************************************************************
+ * SerialThrottle
+ *	this function is called by the tty driver when it wants to stop the data
+ *	being read from the port.
+ *****************************************************************************/
+static void edge_throttle (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty;
+	int status;
+
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (!edge_port->open) {
+		dbg (__FUNCTION__" - port not opened");
+		return;
+	}
+
+	tty = port->tty;
+
+	/* if we are implementing XON/XOFF, send the stop character */
+	if (I_IXOFF(tty)) {
+		unsigned char stop_char = STOP_CHAR(tty);
+		status = edge_write (port, 0, &stop_char, 1);
+		if (status <= 0) {
+			return;
+		}
+	}
+
+	/* if we are implementing RTS/CTS, toggle that line */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		edge_port->shadowMCR &= ~MCR_RTS;
+		status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR);
+		if (status != 0) {
+			return;
+		}
+	}
+
+	return;
+}
+
+
+/*****************************************************************************
+ * edge_unthrottle
+ *	this function is called by the tty driver when it wants to resume the data
+ *	being read from the port (called after SerialThrottle is called)
+ *****************************************************************************/
+static void edge_unthrottle (struct usb_serial_port *port)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty;
+	int status;
+
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (!edge_port->open) {
+		dbg (__FUNCTION__" - port not opened");
+		return;
+	}
+
+	tty = port->tty;
+
+	/* if we are implementing XON/XOFF, send the start character */
+	if (I_IXOFF(tty)) {
+		unsigned char start_char = START_CHAR(tty);
+		status = edge_write (port, 0, &start_char, 1);
+		if (status <= 0) {
+			return;
+		}
+	}
+
+	/* if we are implementing RTS/CTS, toggle that line */
+	if (tty->termios->c_cflag & CRTSCTS) {
+		edge_port->shadowMCR |= MCR_RTS;
+		status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR);
+		if (status != 0) {
+			return;
+		}
+	}
+
+	return;
+}
+
+
+/*****************************************************************************
+ * SerialSetTermios
+ *	this function is called by the tty driver when it wants to change the termios structure
+ *****************************************************************************/
+static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct tty_struct *tty = port->tty;
+	unsigned int cflag = tty->termios->c_cflag;
+
+	dbg(__FUNCTION__" - clfag %08x %08x iflag %08x %08x", 
+	    tty->termios->c_cflag,
+	    old_termios->c_cflag,
+	    RELEVANT_IFLAG(tty->termios->c_iflag),
+	    RELEVANT_IFLAG(old_termios->c_iflag)
+	   );
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg(__FUNCTION__" - nothing to change");
+			return;
+		}
+	}
+
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (!edge_port->open) {
+		dbg (__FUNCTION__" - port not opened");
+		return;
+	}
+
+	/* change the port settings to the new ones specified */
+	change_port_settings (edge_port, old_termios);
+
+	return;
+}
+
+
+/*****************************************************************************
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ *****************************************************************************/
+static int get_lsr_info(struct edgeport_port *edge_port, unsigned int *value)
+{
+	unsigned int result = 0;
+
+	if (edge_port->maxTxCredits == edge_port->txCredits &&
+	    edge_port->txfifo.count == 0) {
+		dbg(__FUNCTION__" -- Empty");
+		result = TIOCSER_TEMT;
+	}
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int *value)
+{
+	unsigned int result = 0;
+	struct tty_struct *tty = edge_port->port->tty;
+
+	result = tty->read_cnt;
+
+	dbg(__FUNCTION__"(%d) = %d",  edge_port->port->number, result);
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	//return 0;
+	return -ENOIOCTLCMD;
+}
+
+static int set_modem_info(struct edgeport_port *edge_port, unsigned int *value)
+{
+	unsigned int mcr = edge_port->shadowMCR;
+	unsigned int arg;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	// turn off the RTS and DTR
+	mcr &=  ~(MCR_RTS | MCR_DTR);
+
+	mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
+	mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
+
+	edge_port->shadowMCR = mcr;
+
+	send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR);
+
+	return 0;
+}
+
+static int get_modem_info(struct edgeport_port *edge_port, unsigned int *value)
+{
+	unsigned int result = 0;
+	unsigned int msr = edge_port->shadowMSR;
+	unsigned int mcr = edge_port->shadowMCR;
+
+	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 */
+
+
+	dbg(__FUNCTION__" -- %x", result);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+
+
+static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+
+	memset(&tmp, 0, sizeof(tmp));
+
+	tmp.type		= PORT_16550A;
+	tmp.line		= edge_port->port->serial->minor;
+	tmp.port		= edge_port->port->number;
+	tmp.irq			= 0;
+	tmp.flags		= ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+	tmp.xmit_fifo_size	= edge_port->maxTxCredits;
+	tmp.baud_base		= 9600;
+	tmp.close_delay		= 5*HZ;
+	tmp.closing_wait	= 30*HZ;
+//	tmp.custom_divisor	= state->custom_divisor;
+//	tmp.hub6		= state->hub6;
+//	tmp.io_type		= state->io_type;
+
+
+	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+
+
+/*****************************************************************************
+ * SerialIoctl
+ *	this function handles any ioctl calls to the driver
+ *****************************************************************************/
+static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	struct async_icount cnow;
+	struct async_icount cprev;
+	struct serial_icounter_struct icount;
+	unsigned long flags;
+
+
+	dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd);
+
+	switch (cmd) {
+		// return number of bytes available
+		case TIOCINQ:
+			dbg(__FUNCTION__" (%d) TIOCINQ",  port->number);
+			return get_number_bytes_avail(edge_port, (unsigned int *) arg);
+			break;
+
+//		case TCGETS:		
+//			dbg(__FUNCTION__" (%d) TCGETS",  port->number);
+//			break;
+
+//		case TCSETS:		
+//			dbg(__FUNCTION__" (%d) TCSETS",  port->number);
+//			break;
+
+		case TIOCSERGETLSR:
+			dbg(__FUNCTION__" (%d) TIOCSERGETLSR",  port->number);
+			return get_lsr_info(edge_port, (unsigned int *) arg);
+			return 0;
+
+		case TIOCMSET:  
+			dbg(__FUNCTION__" (%d) TIOCMSET",  port->number);
+			return set_modem_info(edge_port, (unsigned int *) arg);
+
+		case TIOCMGET:  
+			dbg(__FUNCTION__" (%d) TIOCMGET",  port->number);
+			return get_modem_info(edge_port, (unsigned int *) arg);
+
+		case TIOCGSERIAL:
+			dbg(__FUNCTION__" (%d) TIOCGSERIAL",  port->number);
+			return get_serial_info(edge_port, (struct serial_struct *) arg);
+
+		case TIOCSSERIAL:
+			dbg(__FUNCTION__" (%d) TIOCSSERIAL",  port->number);
+			break;
+
+		case TIOCMIWAIT:
+			dbg(__FUNCTION__" (%d) TIOCMIWAIT",  port->number);
+			save_flags(flags); cli();
+			cprev = edge_port->icount;
+			restore_flags(flags);
+			while (1) {
+				interruptible_sleep_on(&edge_port->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				save_flags(flags); cli();
+				cnow = edge_port->icount; /* atomic copy */
+				restore_flags(flags);
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+			break;
+
+		case TIOCGICOUNT:
+			save_flags(flags); cli();
+			cnow = edge_port->icount;
+			restore_flags(flags);
+			icount.cts = cnow.cts;
+			icount.dsr = cnow.dsr;
+			icount.rng = cnow.rng;
+			icount.dcd = cnow.dcd;
+			icount.rx = cnow.rx;
+			icount.tx = cnow.tx;
+			icount.frame = cnow.frame;
+			icount.overrun = cnow.overrun;
+			icount.parity = cnow.parity;
+			icount.brk = cnow.brk;
+			icount.buf_overrun = cnow.buf_overrun;
+
+			dbg(__FUNCTION__" (%d) TIOCGICOUNT RX=%d, TX=%d",  port->number, icount.rx, icount.tx );
+			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+				return -EFAULT;
+			return 0;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+
+/*****************************************************************************
+ * SerialBreak
+ *	this function sends a break to the port
+ *****************************************************************************/
+static void edge_break (struct usb_serial_port *port, int break_state)
+{
+	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
+	int status;
+
+	/* flush and chase */
+	edge_port->chaseResponsePending = TRUE;
+
+	dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
+	status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+	if (status == 0) {
+		// block until chase finished
+		block_until_chase_response(edge_port);
+	} else {
+		edge_port->chaseResponsePending = FALSE;
+	}
+
+	if (break_state == -1) {
+		dbg(__FUNCTION__" - Sending IOSP_CMD_SET_BREAK");
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+	} else {
+		dbg(__FUNCTION__" - Sending IOSP_CMD_CLEAR_BREAK");
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+	}
+	if (status) {
+		dbg(__FUNCTION__" - error sending break set/clear command.");
+	}
+
+	return;
+}
+
+
+/*****************************************************************************
+ * process_rcvd_data
+ *	this function handles the data received on the bulk in pipe.
+ *****************************************************************************/
+static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength)
+{
+	struct usb_serial_port *port;
+	struct edgeport_port *edge_port;
+	struct tty_struct *tty;
+	__u16 lastBufferLength;
+	__u16 rxLen;
+	int i;
+
+	dbg(__FUNCTION__);
+
+	lastBufferLength = bufferLength + 1;
+
+	while (bufferLength > 0) {
+		/* failsafe incase we get a message that we don't understand */
+		if (lastBufferLength == bufferLength) {
+			dbg(__FUNCTION__" - stuck in loop, exiting it.");
+			break;
+		}
+		lastBufferLength = bufferLength;
+
+		switch (edge_serial->rxState) {
+			case EXPECT_HDR1:
+				edge_serial->rxHeader1 = *buffer;
+				++buffer;
+				--bufferLength;
+
+				if (bufferLength == 0) {
+					edge_serial->rxState = EXPECT_HDR2;
+					break;
+				}
+				/* otherwise, drop on through */
+
+			case EXPECT_HDR2:
+				edge_serial->rxHeader2 = *buffer;
+				++buffer;
+				--bufferLength;
+
+				dbg(__FUNCTION__" - Hdr1=%02X Hdr2=%02X", edge_serial->rxHeader1, edge_serial->rxHeader2);
+
+				// Process depending on whether this header is
+				// data or status
+
+				if (IS_CMD_STAT_HDR(edge_serial->rxHeader1)) {
+					// Decode this status header and goto EXPECT_HDR1 (if we
+					// can process the status with only 2 bytes), or goto
+					// EXPECT_HDR3 to get the third byte.
+
+					edge_serial->rxPort       = IOSP_GET_HDR_PORT(edge_serial->rxHeader1);
+					edge_serial->rxStatusCode = IOSP_GET_STATUS_CODE(edge_serial->rxHeader1);
+
+					if (!IOSP_STATUS_IS_2BYTE(edge_serial->rxStatusCode)) {
+						// This status needs additional bytes. Save what we have
+						// and then wait for more data.
+						edge_serial->rxStatusParam = edge_serial->rxHeader2;
+
+						edge_serial->rxState = EXPECT_HDR3;
+						break;
+					}
+
+					// We have all the header bytes, process the status now
+					process_rcvd_status (edge_serial, edge_serial->rxHeader2, 0);
+
+					edge_serial->rxState = EXPECT_HDR1;
+					break;
+				} else {
+					edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1);
+					edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, edge_serial->rxHeader2);
+
+					dbg(__FUNCTION__" - Data for Port %u Len %u", edge_serial->rxPort, edge_serial->rxBytesRemaining);
+
+					//ASSERT( DevExt->RxPort < DevExt->NumPorts );
+					//ASSERT( DevExt->RxBytesRemaining < IOSP_MAX_DATA_LENGTH );
+
+					if (bufferLength == 0 ) {
+						edge_serial->rxState = EXPECT_DATA;
+						break;
+					}
+					// Else, drop through
+				}
+
+			case EXPECT_DATA:	// Expect data
+
+				if (bufferLength < edge_serial->rxBytesRemaining) {
+					rxLen = bufferLength;
+					edge_serial->rxState = EXPECT_DATA;	// Expect data to start next buffer
+				} else {
+					// BufLen >= RxBytesRemaining
+					rxLen = edge_serial->rxBytesRemaining;
+					edge_serial->rxState = EXPECT_HDR1;	// Start another header next time
+				}
+
+				bufferLength -= rxLen;
+				edge_serial->rxBytesRemaining -= rxLen;
+
+				/* spit this data back into the tty driver if this port is open */
+				if (rxLen) {
+					port = &edge_serial->serial->port[edge_serial->rxPort];
+					if (port_paranoia_check (port, __FUNCTION__) == 0) {
+						edge_port = (struct edgeport_port *)port->private;
+						if (edge_port->open) {
+							tty = edge_port->port->tty;
+							if (tty) {
+								dbg (__FUNCTION__" - Sending %d bytes to TTY for port %d", rxLen, edge_serial->rxPort);
+								for (i = 0; i < rxLen ; ++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, buffer[i], 0);
+								}
+								tty_flip_buffer_push(tty);
+							}
+							edge_port->icount.rx += rxLen;
+						}
+					}
+					buffer += rxLen;
+				}
+
+				break;
+
+			case EXPECT_HDR3:			// Expect 3rd byte of status header
+				edge_serial->rxHeader3 = *buffer;
+				++buffer;
+				--bufferLength;
+
+				// We have all the header bytes, process the status now
+				process_rcvd_status (edge_serial, edge_serial->rxStatusParam, edge_serial->rxHeader3);
+				edge_serial->rxState = EXPECT_HDR1;
+				break;
+
+		}
+	}
+
+	return 0;
+}
+
+
+/*****************************************************************************
+ * process_rcvd_status
+ *	this function handles the any status messages received on the bulk in pipe.
+ *****************************************************************************/
+static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3)
+{
+	struct usb_serial_port *port;
+	struct edgeport_port *edge_port;
+	__u8 code = edge_serial->rxStatusCode;
+
+	/* switch the port pointer to the one being currently talked about */
+	port = &edge_serial->serial->port[edge_serial->rxPort];
+	if (port_paranoia_check (port, __FUNCTION__)) {
+		return;
+	}
+	edge_port = (struct edgeport_port *)port->private;
+	if (edge_port == NULL) {
+		err (__FUNCTION__ " - edge_port == NULL for port %d", edge_serial->rxPort);
+		return;
+	}
+
+	dbg(__FUNCTION__" - port %d", edge_serial->rxPort);
+
+	if (code == IOSP_EXT_STATUS) {
+		switch (byte2) {
+			case IOSP_EXT_STATUS_CHASE_RSP:
+				// we want to do EXT status regardless of port open/closed 
+				dbg(__FUNCTION__" - Port %u EXT CHASE_RSP Data = %02x", edge_serial->rxPort, byte3 );
+				// Currently, the only EXT_STATUS is Chase, so process here instead of one more call
+				// to one more subroutine. If/when more EXT_STATUS, there'll be more work to do.
+				// Also, we currently clear flag and close the port regardless of content of above's Byte3.
+				// We could choose to do something else when Byte3 says Timeout on Chase from Edgeport,
+				// like wait longer in block_until_chase_response, but for now we don't. 
+				edge_port->chaseResponsePending = FALSE;
+				wake_up_interruptible (&edge_port->wait_chase);
+				return;
+
+			case IOSP_EXT_STATUS_RX_CHECK_RSP:
+				dbg( __FUNCTION__" ========== Port %u CHECK_RSP Sequence = %02x =============\n", edge_serial->rxPort, byte3 );
+				//Port->RxCheckRsp = TRUE;
+				return;
+		}
+	}
+
+	if (code == IOSP_STATUS_OPEN_RSP) {
+		edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3);
+		edge_port->maxTxCredits = edge_port->txCredits;
+		dbg (__FUNCTION__" - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", edge_serial->rxPort, byte2, edge_port->txCredits);
+		handle_new_msr (edge_port, byte2);
+
+		/* send the current line settings to the port so we are in sync with any further termios calls */
+		change_port_settings (edge_port, edge_port->port->tty->termios);
+
+		/* we have completed the open */
+		edge_port->openPending = FALSE;
+		edge_port->open = TRUE;
+		wake_up_interruptible(&edge_port->wait_open);
+		return;
+	}
+
+	// If port is closed, silently discard all rcvd status. We can
+	// have cases where buffered status is received AFTER the close
+	// port command is sent to the Edgeport.
+	if ((!edge_port->open ) || (edge_port->closePending)) {
+		return;
+	}
+
+	switch (code) {
+		// Not currently sent by Edgeport
+		case IOSP_STATUS_LSR:
+			dbg(__FUNCTION__" - Port %u LSR Status = %02x", edge_serial->rxPort, byte2);
+			handle_new_lsr (edge_port, FALSE, byte2, 0);
+			break;
+
+		case IOSP_STATUS_LSR_DATA:
+			dbg(__FUNCTION__" - Port %u LSR Status = %02x, Data = %02x", edge_serial->rxPort, byte2, byte3);
+			// byte2 is LSR Register
+			// byte3 is broken data byte
+			handle_new_lsr (edge_port, TRUE, byte2, byte3);
+			break;
+			//
+			//	case IOSP_EXT_4_STATUS:
+			//		dbg(__FUNCTION__" - Port %u LSR Status = %02x Data = %02x", edge_serial->rxPort, byte2, byte3);
+			//		break;
+			//
+		case IOSP_STATUS_MSR:
+			dbg(__FUNCTION__" - Port %u MSR Status = %02x", edge_serial->rxPort, byte2);
+
+			// Process this new modem status and generate appropriate
+			// events, etc, based on the new status. This routine
+			// also saves the MSR in Port->ShadowMsr.
+			handle_new_msr(edge_port, byte2);
+			break;
+
+		default:
+			dbg(__FUNCTION__" - Unrecognized IOSP status code %u\n", code);
+			break;
+	}
+
+	return;
+}
+
+
+/*****************************************************************************
+ * handle_new_msr
+ *	this function handles any change to the msr register for a port.
+ *****************************************************************************/
+static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
+{
+	struct  async_icount *icount;
+
+	dbg(__FUNCTION__" %02x", newMsr);
+
+	if (newMsr & (MSR_DELTA_CTS | MSR_DELTA_DSR | MSR_DELTA_RI | MSR_DELTA_CD)) {
+		icount = &edge_port->icount;
+
+		/* update input line counters */
+		if (newMsr & MSR_DELTA_CTS) {
+			icount->cts++;
+		}
+		if (newMsr & MSR_DELTA_DSR) {
+			icount->dsr++;
+		}
+		if (newMsr & MSR_DELTA_CD) {
+			icount->dcd++;
+		}
+		if (newMsr & MSR_DELTA_RI) {
+			icount->rng++;
+		}
+		wake_up_interruptible(&edge_port->delta_msr_wait);
+	}
+
+	/* Save the new modem status */
+	edge_port->shadowMSR = newMsr & 0xf0;
+
+	return;
+}
+
+
+/*****************************************************************************
+ * handle_new_lsr
+ *	this function handles any change to the lsr register for a port.
+ *****************************************************************************/
+static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, __u8 lsr, __u8 data)
+{
+	__u8    newLsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK));
+	struct  async_icount *icount;
+
+	dbg(__FUNCTION__" - %02x", newLsr);
+
+	edge_port->shadowLSR = lsr;
+
+	if (newLsr & LSR_BREAK) {
+		//
+		// Parity and Framing errors only count if they
+		// occur exclusive of a break being
+		// received.
+		//
+		newLsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK);
+	}
+
+	/* Place LSR data byte into Rx buffer */
+	if (lsrData) {
+		tty_insert_flip_char(edge_port->port->tty, data, 0);
+		tty_flip_buffer_push(edge_port->port->tty);
+	}
+
+	/* update input line counters */
+	icount = &edge_port->icount;
+	if (newLsr & LSR_BREAK) {
+		icount->brk++;
+	}
+	if (newLsr & LSR_OVER_ERR) {
+		icount->overrun++;
+	}
+	if (newLsr & LSR_PAR_ERR) {
+		icount->parity++;
+	}
+	if (newLsr & LSR_FRM_ERR) {
+		icount->frame++;
+	}
+
+	return;
+}
+
+
+/****************************************************************************
+ * sram_write
+ *	writes a number of bytes to the Edgeport device's sram starting at the 
+ *	given address.
+ *	If successful returns the number of bytes written, otherwise it returns
+ *	a negative error number of the problem.
+ ****************************************************************************/
+static int sram_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data)
+{
+	int result;
+	__u16 current_length;
+	unsigned char *transfer_buffer;
+
+//	dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length);
+
+	transfer_buffer =  kmalloc (64, GFP_KERNEL);
+	if (!transfer_buffer) {
+		err(__FUNCTION__" - kmalloc(%d) failed.\n", 64);
+		return -ENOMEM;
+	}
+
+	/* need to split these writes up into 64 byte chunks */
+	result = 0;
+	while (length > 0) {
+		if (length > 64) {
+			current_length = 64;
+		} else {
+			current_length = length;
+		}
+//		dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length);
+		memcpy (transfer_buffer, data, current_length);
+		result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_RAM, 
+					  0x40, addr, extAddr, transfer_buffer, current_length, 300);
+		if (result < 0)
+			break;
+		length -= current_length;
+		addr += current_length;
+		data += current_length;
+	}       
+
+	kfree (transfer_buffer);
+	return result;
+}
+
+
+/****************************************************************************
+ * rom_write
+ *	writes a number of bytes to the Edgeport device's ROM starting at the
+ *	given address.
+ *	If successful returns the number of bytes written, otherwise it returns
+ *	a negative error number of the problem.
+ ****************************************************************************/
+static int rom_write (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data)
+{
+	int result;
+	__u16 current_length;
+	unsigned char *transfer_buffer;
+
+//	dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length);
+
+	transfer_buffer =  kmalloc (64, GFP_KERNEL);
+	if (!transfer_buffer) {
+		err(__FUNCTION__" - kmalloc(%d) failed.\n", 64);
+		return -ENOMEM;
+	}
+
+	/* need to split these writes up into 64 byte chunks */
+	result = 0;
+	while (length > 0) {
+		if (length > 64) {
+			current_length = 64;
+		} else {
+			current_length = length;
+		}
+//		dbg (__FUNCTION__" - writing %x, %x, %d", extAddr, addr, current_length);
+		memcpy (transfer_buffer, data, current_length);
+		result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), USB_REQUEST_ION_WRITE_ROM, 
+					  0x40, addr, extAddr, transfer_buffer, current_length, 300);
+		if (result < 0)
+			break;
+		length -= current_length;
+		addr += current_length;
+		data += current_length;
+	}       
+
+	kfree (transfer_buffer);
+	return result;
+}
+
+
+/****************************************************************************
+ * rom_read
+ *	reads a number of bytes from the Edgeport device starting at the given
+ *	address.
+ *	If successful returns the number of bytes read, otherwise it returns
+ *	a negative error number of the problem.
+ ****************************************************************************/
+static int rom_read (struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data)
+{
+	int result;
+	__u16 current_length;
+	unsigned char *transfer_buffer;
+
+	dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, length);
+
+	transfer_buffer =  kmalloc (64, GFP_KERNEL);
+	if (!transfer_buffer) {
+		err(__FUNCTION__" - kmalloc(%d) failed.\n", 64);
+		return -ENOMEM;
+	}
+
+	/* need to split these reads up into 64 byte chunks */
+	result = 0;
+	while (length > 0) {
+		if (length > 64) {
+			current_length = 64;
+		} else {
+			current_length = length;
+		}
+//		dbg (__FUNCTION__" - %x, %x, %d", extAddr, addr, current_length);
+		result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_READ_ROM, 
+					  0xC0, addr, extAddr, transfer_buffer, current_length, 300);
+		if (result < 0)
+			break;
+		memcpy (data, transfer_buffer, current_length);
+		length -= current_length;
+		addr += current_length;
+		data += current_length;
+	}       
+
+	kfree (transfer_buffer);
+	return result;
+}
+
+
+/****************************************************************************
+ * send_iosp_ext_cmd
+ *	Is used to send a IOSP message to the Edgeport device
+ ****************************************************************************/
+static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param)
+{
+	unsigned char   *buffer;
+	unsigned char   *currentCommand;
+	int             length = 0;
+	int             status = 0;
+
+	dbg(__FUNCTION__" - %d, %d", command, param);
+
+	buffer =  kmalloc (10, GFP_KERNEL);
+	if (!buffer) {
+		err(__FUNCTION__" - kmalloc(%d) failed.\n", 10);
+		return -ENOMEM;
+	}
+
+	currentCommand = buffer;
+
+	MAKE_CMD_EXT_CMD( &currentCommand, &length, edge_port->port->number, command, param);
+
+	status = write_cmd_usb (edge_port, buffer, length);
+	if (status) {
+		/* something bad happened, let's free up the memory */
+		kfree(buffer);
+	}
+
+	return status;
+}
+
+
+/*****************************************************************************
+ * write_cmd_usb
+ *	this function writes the given buffer out to the bulk write endpoint.
+ *****************************************************************************/
+static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int length)
+{
+	struct edgeport_serial *edge_serial = (struct edgeport_serial *)edge_port->port->serial->private;
+	int status = 0;
+	urb_t *urb;
+	int timeout;
+
+#ifdef DEBUG
+	if (length) {
+		int i;
+		printk (KERN_DEBUG __FILE__ ": "__FUNCTION__" - length = %d, buffer = ", length);
+		for (i = 0; i < length; ++i) {
+			printk ("%.2x ", buffer[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	/* Allocate our next urb */
+	urb = usb_alloc_urb (0);
+
+	CmdUrbs++;
+
+	dbg(__FUNCTION__" - ALLOCATE URB %p (outstanding %d)", urb, CmdUrbs);
+
+	if (!urb) {
+		return -ENOMEM;
+	}
+
+	FILL_BULK_URB (urb, edge_serial->serial->dev, 
+		       usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint),
+		       buffer, length, edge_bulk_out_cmd_callback, edge_port);
+
+	/* set the USB_BULK_QUEUE flag so that we can shove a bunch of urbs at once down the pipe */
+	urb->transfer_flags |= USB_QUEUE_BULK;
+
+	edge_port->commandPending = TRUE;
+	urb->dev = edge_serial->serial->dev;
+	status = usb_submit_urb(urb);
+
+	if (status) {
+		/* something went wrong */
+		dbg(__FUNCTION__" - usb_submit_urb(write bulk) failed");
+
+		/* if this urb had a transfer buffer already (old transfer) free it */
+		if (urb->transfer_buffer != NULL) {
+			kfree(urb->transfer_buffer);
+		}
+		usb_unlink_urb (urb);
+		usb_free_urb   (urb);
+		return status;
+	}
+
+	// wait for command to finish
+	timeout = COMMAND_TIMEOUT;
+#if 0
+	while (timeout && edge_port->commandPending == TRUE) {
+		timeout = interruptible_sleep_on_timeout (&edge_port->wait_command, timeout);
+	}
+
+	if (edge_port->commandPending == TRUE) {
+		/* command timed out */
+		dbg(__FUNCTION__" - command timed out");
+		status = -EINVAL;
+	}
+#endif
+	return status;
+}
+
+
+/*****************************************************************************
+ * send_cmd_write_baud_rate
+ *	this function sends the proper command to change the baud rate of the
+ *	specified port.
+ *****************************************************************************/
+static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
+{
+	unsigned char *cmdBuffer;
+	unsigned char *currCmd;
+	int cmdLen = 0;
+	int divisor;
+	int status;
+	unsigned char number = edge_port->port->number;
+
+	dbg(__FUNCTION__" - port = %d, baud = %d", number, baudRate);
+
+	status = calc_baud_rate_divisor (baudRate, &divisor);
+	if (status) {
+		err(__FUNCTION__" - bad baud rate");
+		return status;
+	}
+
+	// Alloc memory for the string of commands.
+	cmdBuffer =  kmalloc (0x100, GFP_KERNEL);
+	if (!cmdBuffer) {
+		err(__FUNCTION__" - kmalloc(%d) failed.\n", 0x100);
+		return -ENOMEM;
+	}
+	currCmd = cmdBuffer;
+
+	// Enable access to divisor latch
+	MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, LCR, LCR_DL_ENABLE );
+
+	// Write the divisor itself
+	MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, DLL, LOW8 (divisor) );
+	MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, DLM, HIGH8(divisor) );
+
+	// Restore original value to disable access to divisor latch
+	MAKE_CMD_WRITE_REG( &currCmd, &cmdLen, number, LCR, edge_port->shadowLCR);
+
+	status = write_cmd_usb(edge_port, cmdBuffer, cmdLen );
+
+	return status;
+}
+
+
+/*****************************************************************************
+ * calc_baud_rate_divisor
+ *	this function calculates the proper baud rate divisor for the specified
+ *	baud rate.
+ *****************************************************************************/
+static int calc_baud_rate_divisor (int baudrate, int *divisor)
+{
+	int i;
+	__u16 custom;
+	__u16 round1;
+	__u16 round;
+
+
+	dbg(__FUNCTION__" - %d", baudrate);
+
+	for (i = 0; i < NUM_ENTRIES(DivisorTable); i++) {
+		if ( DivisorTable[i].BaudRate == baudrate ) {
+			*divisor = DivisorTable[i].Divisor;
+			return 0;
+		}
+	}
+
+	// We have tried all of the standard baud rates
+	// lets try to calculate the divisor for this baud rate
+	// Make sure the baud rate is reasonable
+	if (baudrate > 75 &&  baudrate < 230400) {
+		// get divisor
+		custom = (__u16)(230400L  / baudrate);
+
+		// Check for round off
+		round1 = (__u16)(2304000L / baudrate);
+		round = (__u16)(round1 - (custom * 10));
+		if (round > 4) {
+			custom++;
+		}
+		*divisor = custom;
+
+		dbg(__FUNCTION__" - Baud %d = %d\n", baudrate, custom);
+		return 0;
+	}
+
+	return -1;
+}
+
+
+/*****************************************************************************
+ * send_cmd_write_uart_register
+ *	this function builds up a uart register message and sends to to the device.
+ *****************************************************************************/
+static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
+{
+	unsigned char *cmdBuffer;
+	unsigned char *currCmd;
+	unsigned long cmdLen = 0;
+	int status;
+
+	dbg (__FUNCTION__" - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", regValue);
+
+	// Alloc memory for the string of commands.
+	cmdBuffer = kmalloc (0x10, GFP_KERNEL);
+	if (cmdBuffer == NULL ) {
+		return -ENOMEM;
+	}
+
+	currCmd = cmdBuffer;
+
+	// Build a cmd in the buffer to write the given register
+	MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, edge_port->port->number, regNum, regValue);
+
+	status = write_cmd_usb(edge_port, cmdBuffer, cmdLen);
+
+	return status;
+}
+
+
+/*****************************************************************************
+ * change_port_settings
+ *	This routine is called to set the UART on the device to match the specified
+ *	new settings.
+ *****************************************************************************/
+static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios)
+{
+	struct tty_struct *tty;
+	int baud;
+	unsigned cflag;
+	__u8 mask = 0xff;
+	__u8 lData;
+	__u8 lParity;
+	__u8 lStop;
+	__u8 rxFlow;
+	__u8 txFlow;
+	int status;
+
+	dbg(__FUNCTION__" - port %d", edge_port->port->number);
+
+	if ((!edge_port->open) &&
+	    (!edge_port->openPending)) {
+		dbg(__FUNCTION__" - port not opened");
+		return;
+	}
+
+	tty = edge_port->port->tty;
+	if ((!tty) ||
+	    (!tty->termios)) {
+		dbg(__FUNCTION__" - no tty structures");
+		return;
+	}
+
+	cflag = tty->termios->c_cflag;
+
+	switch (cflag & CSIZE) {
+		case CS5:   lData = LCR_BITS_5; mask = 0x1f;    dbg(__FUNCTION__" - data bits = 5");   break;
+		case CS6:   lData = LCR_BITS_6; mask = 0x3f;    dbg(__FUNCTION__" - data bits = 6");   break;
+		case CS7:   lData = LCR_BITS_7; mask = 0x7f;    dbg(__FUNCTION__" - data bits = 7");   break;
+		default:
+		case CS8:   lData = LCR_BITS_8;                 dbg(__FUNCTION__" - data bits = 8");   break;
+	}
+
+	lParity = LCR_PAR_NONE;
+	if (cflag & PARENB) {
+		if (cflag & PARODD) {
+			lParity = LCR_PAR_ODD;
+			dbg(__FUNCTION__" - parity = odd");
+		} else {
+			lParity = LCR_PAR_EVEN;
+			dbg(__FUNCTION__" - parity = even");
+		}
+	} else {
+		dbg(__FUNCTION__" - parity = none");
+	}
+
+	if (cflag & CSTOPB) {
+		lStop = LCR_STOP_2;
+		dbg(__FUNCTION__" - stop bits = 2");
+	} else {
+		lStop = LCR_STOP_1;
+		dbg(__FUNCTION__" - stop bits = 1");
+	}
+
+	/* figure out the flow control settings */
+	rxFlow = txFlow = 0x00;
+	if (cflag & CRTSCTS) {
+		rxFlow |= IOSP_RX_FLOW_RTS;
+		txFlow |= IOSP_TX_FLOW_CTS;
+		dbg(__FUNCTION__" - RTS/CTS is enabled");
+	} else {
+		dbg(__FUNCTION__" - RTS/CTS is disabled");
+	}
+
+	/* if we are implementing XON/XOFF, set the start and stop character in the device */
+	if (I_IXOFF(tty) || I_IXON(tty)) {
+		unsigned char stop_char  = STOP_CHAR(tty);
+		unsigned char start_char = START_CHAR(tty);
+
+		{
+			send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+			send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+		}
+
+		/* if we are implementing INBOUND XON/XOFF */
+		if (I_IXOFF(tty)) {
+			rxFlow |= IOSP_RX_FLOW_XON_XOFF;
+			dbg(__FUNCTION__" - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char);
+		} else {
+			dbg(__FUNCTION__" - INBOUND XON/XOFF is disabled");
+		}
+
+		/* if we are implementing OUTBOUND XON/XOFF */
+		if (I_IXON(tty)) {
+			txFlow |= IOSP_TX_FLOW_XON_XOFF;
+			dbg(__FUNCTION__" - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", start_char, stop_char);
+		} else {
+			dbg(__FUNCTION__" - OUTBOUND XON/XOFF is disabled");
+		}
+	}
+
+	/* Set flow control to the configured value */
+	send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+	send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+
+
+	edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+	edge_port->shadowLCR |= (lData | lParity | lStop);
+
+	edge_port->validDataMask = mask;
+
+	/* Send the updated LCR value to the EdgePort */
+	status = send_cmd_write_uart_register(edge_port, LCR, edge_port->shadowLCR);
+	if (status != 0) {
+		return;
+	}
+
+	/* set up the MCR register and send it to the EdgePort */
+	edge_port->shadowMCR = MCR_MASTER_IE;
+	if (cflag & CBAUD) {
+		edge_port->shadowMCR |= (MCR_DTR | MCR_RTS);
+	}
+	status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR);
+	if (status != 0) {
+		return;
+	}
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(tty);
+	if (!baud) {
+		/* pick a default, any default... */
+		baud = 9600;
+	}
+
+	dbg(__FUNCTION__ " - baud rate = %d", baud);
+	status = send_cmd_write_baud_rate (edge_port, baud);
+
+	return;
+}
+
+
+/****************************************************************************
+ * unicode_to_ascii
+ *	Turns a string from Unicode into ASCII.
+ *	Doesn't do a good job with any characters that are outside the normal
+ *	ASCII range, but it's only for debugging...
+ ****************************************************************************/
+static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
+{
+	int i;
+	for (i = 0; i < unicode_size; ++i) {
+		string[i] = (char)(unicode[i]);
+	}
+	string[unicode_size] = 0x00;
+}
+
+
+/****************************************************************************
+ * get_manufacturing_desc
+ *	reads in the manufacturing descriptor and stores it into the serial 
+ *	structure.
+ ****************************************************************************/
+static void get_manufacturing_desc (struct edgeport_serial *edge_serial)
+{
+	int response;
+
+	dbg("getting manufacturer descriptor");
+
+	response = rom_read (edge_serial->serial, (EDGE_MANUF_DESC_ADDR & 0xffff0000) >> 16, 
+			    (__u16)(EDGE_MANUF_DESC_ADDR & 0x0000ffff), EDGE_MANUF_DESC_LEN,
+			    (__u8 *)(&edge_serial->manuf_descriptor));
+
+	if (response < 1) {
+		err("error in getting manufacturer descriptor");
+	} else {
+#ifdef DEBUG
+		char string[30];
+		dbg("**Manufacturer Descriptor");
+		dbg("  RomSize:        %dK", edge_serial->manuf_descriptor.RomSize);
+		dbg("  RamSize:        %dK", edge_serial->manuf_descriptor.RamSize);
+		dbg("  CpuRev:         %d", edge_serial->manuf_descriptor.CpuRev);
+		dbg("  BoardRev:       %d", edge_serial->manuf_descriptor.BoardRev);
+		dbg("  NumPorts:       %d", edge_serial->manuf_descriptor.NumPorts);
+		dbg("  DescDate:       %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900);
+		unicode_to_ascii (string, edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2-1);
+		dbg("  SerialNumber: %s", string);
+		unicode_to_ascii (string, edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2-1);
+		dbg("  AssemblyNumber: %s", string);
+		unicode_to_ascii (string, edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2-1);
+		dbg("  OemAssyNumber:  %s", string);
+		dbg("  UartType:       %d", edge_serial->manuf_descriptor.UartType);
+		dbg("  IonPid:         %d", edge_serial->manuf_descriptor.IonPid);
+		dbg("  IonConfig:      %d", edge_serial->manuf_descriptor.IonConfig);
+#endif
+	}
+}
+
+
+/****************************************************************************
+ * get_boot_desc
+ *	reads in the bootloader descriptor and stores it into the serial 
+ *	structure.
+ ****************************************************************************/
+static void get_boot_desc (struct edgeport_serial *edge_serial)
+{
+	int response;
+
+	dbg("getting boot descriptor");
+
+	response = rom_read (edge_serial->serial, (EDGE_BOOT_DESC_ADDR & 0xffff0000) >> 16, 
+			    (__u16)(EDGE_BOOT_DESC_ADDR & 0x0000ffff), EDGE_BOOT_DESC_LEN,
+			    (__u8 *)(&edge_serial->boot_descriptor));
+
+	if (response < 1) {
+		err("error in getting boot descriptor");
+	} else {
+		dbg("**Boot Descriptor:");
+		dbg("  BootCodeLength: %d", edge_serial->boot_descriptor.BootCodeLength);
+		dbg("  MajorVersion:   %d", edge_serial->boot_descriptor.MajorVersion);
+		dbg("  MinorVersion:   %d", edge_serial->boot_descriptor.MinorVersion);
+		dbg("  BuildNumber:    %d", edge_serial->boot_descriptor.BuildNumber);
+		dbg("  Capabilities:   0x%x", edge_serial->boot_descriptor.Capabilities);
+		dbg("  UConfig0:       %d", edge_serial->boot_descriptor.UConfig0);
+		dbg("  UConfig1:       %d", edge_serial->boot_descriptor.UConfig1);
+	}
+}
+
+
+/****************************************************************************
+ * load_application_firmware
+ *	This is called to load the application firmware to the device
+ ****************************************************************************/
+static void load_application_firmware (struct edgeport_serial *edge_serial)
+{
+	PEDGE_FIRMWARE_IMAGE_RECORD record;
+	unsigned char *firmware;
+	unsigned char *FirmwareImage;
+	int ImageSize;
+	int response;
+
+
+	switch (edge_serial->product_info.iDownloadFile) {
+		case EDGE_DOWNLOAD_FILE_I930:
+			dbg("downloading firmware version (930) %d.%d.%d", 
+			    OperationalCodeImageVersion_GEN1.MajorVersion, 
+			    OperationalCodeImageVersion_GEN1.MinorVersion, 
+			    OperationalCodeImageVersion_GEN1.BuildNumber);
+			firmware = &OperationalCodeImage_GEN1[0];
+			FirmwareImage = &OperationalCodeImage_GEN1[0];
+			ImageSize = sizeof(OperationalCodeImage_GEN1);
+			break;
+
+		case EDGE_DOWNLOAD_FILE_80251:
+			dbg("downloading firmware version (80251) %d.%d.%d", 
+			    OperationalCodeImageVersion_GEN2.MajorVersion, 
+			    OperationalCodeImageVersion_GEN2.MinorVersion, 
+			    OperationalCodeImageVersion_GEN2.BuildNumber);
+			firmware = &OperationalCodeImage_GEN2[0];
+			FirmwareImage = &OperationalCodeImage_GEN2[0];
+			ImageSize = sizeof(OperationalCodeImage_GEN2);
+			break;
+
+		case EDGE_DOWNLOAD_FILE_NONE:
+			dbg     ("No download file specified, skipping download\n");
+			return;
+
+		default:
+			return;
+	}
+
+
+	for (;;) {
+		record = (PEDGE_FIRMWARE_IMAGE_RECORD)firmware;
+		response = sram_write (edge_serial->serial, record->ExtAddr, record->Addr, record->Len, &record->Data[0]);
+		if (response < 0) {
+			err("sram_write failed (%x, %x, %d)", record->ExtAddr, record->Addr, record->Len);
+			break;
+		}
+		firmware += sizeof (EDGE_FIRMWARE_IMAGE_RECORD) + record->Len;
+		if (firmware >= &FirmwareImage[ImageSize]) {
+			break;
+		}
+	}
+
+	dbg("sending exec_dl_code");
+	response = usb_control_msg (edge_serial->serial->dev, 
+				    usb_sndctrlpipe(edge_serial->serial->dev, 0), 
+				    USB_REQUEST_ION_EXEC_DL_CODE, 
+				    0x40, 0x4000, 0x0001, NULL, 0, 3000);
+
+	return;
+}
+
+
+
+
+/****************************************************************************
+ * edge_startup
+ ****************************************************************************/
+static int edge_startup (struct usb_serial *serial)
+{
+	struct edgeport_serial *edge_serial;
+	struct edgeport_port *edge_port;
+	struct usb_device *dev;
+	int i;
+
+	dev = serial->dev;
+
+	/* create our private serial structure */
+	edge_serial = kmalloc (sizeof(struct edgeport_serial), GFP_KERNEL);
+	if (edge_serial == NULL) {
+		err(__FUNCTION__" - Out of memory");
+		return -ENOMEM;
+	}
+	memset (edge_serial, 0, sizeof(struct edgeport_serial));
+	edge_serial->serial = serial;
+	serial->private = edge_serial;
+
+	/* get the name for the device from the device */
+	if ( (i = get_string(dev, dev->descriptor.iManufacturer, &edge_serial->name[0])) != 0) {
+		edge_serial->name[i-1] = ' ';
+	}
+
+	get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]);
+
+	info("%s detected", edge_serial->name);
+
+	/* get the manufacturing descriptor for this device */
+	get_manufacturing_desc (edge_serial);
+
+	/* get the boot descriptor */
+	get_boot_desc (edge_serial);
+
+	get_product_info(edge_serial);
+
+	/* set the number of ports from the manufacturing description */
+	// FIXME  should we override this???
+	//serial->num_ports = serial->product_info.NumPorts;
+	if (edge_serial->product_info.NumPorts != serial->num_ports) {
+		warn(__FUNCTION__ " - Device Reported %d serial ports vs core thinking we have %d ports, email greg@kroah.com this info.", edge_serial->product_info.NumPorts, serial->num_ports);
+	}
+
+	dbg(__FUNCTION__ " - time 1 %ld", jiffies);
+
+	/* now load the application firmware into this device */
+	load_application_firmware (edge_serial);
+
+	dbg(__FUNCTION__ " - time 2 %ld", jiffies);
+
+	/* Check current Edgeport EEPROM and update if necessary */
+	update_edgeport_E2PROM (edge_serial);
+	
+	dbg(__FUNCTION__ " - time 3 %ld", jiffies);
+
+	/* set the configuration to use #1 */
+//	dbg("set_configuration 1");
+//	usb_set_configuration (dev, 1);
+
+	/* we set up the pointers to the endpoints in the edge_open function, 
+	 * as the structures aren't created yet. */
+
+	/* set up our port private structures */
+	for (i = 0; i < serial->num_ports; ++i) {
+		edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL);
+		if (edge_port == NULL) {
+			err(__FUNCTION__" - Out of memory");
+			return -ENOMEM;
+		}
+		memset (edge_port, 0, sizeof(struct edgeport_port));
+		edge_port->port = &serial->port[i];
+		serial->port[i].private = edge_port;
+	}
+	
+	return 0;
+}
+
+
+
+/****************************************************************************
+ * usb_edgeport_disconnect
+ *	This function is called whenever the device is removed from the usb bus.
+ ****************************************************************************/
+//static void usb_edgeport_disconnect (struct usb_device *dev, void *ptr)
+static void edge_shutdown (struct usb_serial *serial)
+{
+	int i;
+
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			edge_close (&serial->port[i], NULL);
+		}
+	}
+
+	/* free up any memory that we allocated */
+	// FIXME
+	
+}
+
+
+/****************************************************************************
+ * edgeport_init
+ *	This is called by the module subsystem, or on startup to initialize us
+ ****************************************************************************/
+int __init edgeport_init(void)
+{
+	usb_serial_register (&edgeport_4_device);
+	usb_serial_register (&rapidport_4_device);
+	usb_serial_register (&edgeport_4t_device);
+	usb_serial_register (&edgeport_2_device);
+	usb_serial_register (&edgeport_4i_device);
+	usb_serial_register (&edgeport_2i_device);
+	usb_serial_register (&edgeport_prl_device);
+	usb_serial_register (&edgeport_421_device);
+	usb_serial_register (&edgeport_21_device);
+	usb_serial_register (&edgeport_8dual_device);
+	usb_serial_register (&edgeport_8_device);
+	usb_serial_register (&edgeport_2din_device);
+	usb_serial_register (&edgeport_4din_device);
+	usb_serial_register (&edgeport_16dual_device);
+	usb_serial_register (&edgeport_compat_id_device);
+	usb_serial_register (&edgeport_8i_device);
+	
+	return 0;
+}
+
+
+
+/****************************************************************************
+ * edgeport_exit
+ *	Called when the driver is about to be unloaded.
+ ****************************************************************************/
+void __exit edgeport_exit (void)
+{
+	usb_serial_deregister (&edgeport_4_device);
+	usb_serial_deregister (&rapidport_4_device);
+	usb_serial_deregister (&edgeport_4t_device);
+	usb_serial_deregister (&edgeport_2_device);
+	usb_serial_deregister (&edgeport_4i_device);
+	usb_serial_deregister (&edgeport_2i_device);
+	usb_serial_deregister (&edgeport_prl_device);
+	usb_serial_deregister (&edgeport_421_device);
+	usb_serial_deregister (&edgeport_21_device);
+	usb_serial_deregister (&edgeport_8dual_device);
+	usb_serial_deregister (&edgeport_8_device);
+	usb_serial_deregister (&edgeport_2din_device);
+	usb_serial_deregister (&edgeport_4din_device);
+	usb_serial_deregister (&edgeport_16dual_device);
+	usb_serial_deregister (&edgeport_compat_id_device);
+	usb_serial_deregister (&edgeport_8i_device);
+}
+
+module_init(edgeport_init);
+module_exit(edgeport_exit);
+
+
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_edgeport.h linux/drivers/usb/serial/io_edgeport.h
--- v2.4.2/linux/drivers/usb/serial/io_edgeport.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_edgeport.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,152 @@
+/************************************************************************
+ *
+ *	io_edgeport.h	Edgeport Linux Interface definitions
+ *
+ *	Copyright (c) 2000 Inside Out Networks, Inc.
+ *
+ *	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.
+ *
+ *
+ ************************************************************************/
+
+#if !defined(_IO_EDGEPORT_H_)
+#define	_IO_EDGEPORT_H_
+
+
+#define MAX_RS232_PORTS		8	/* Max # of RS-232 ports per device */
+
+/* typedefs that the insideout headers need */
+#ifndef TRUE
+	#define TRUE		(1)
+#endif
+#ifndef FALSE
+	#define FALSE		(0)
+#endif
+#ifndef MIN
+	#define MIN(a,b)	(((a)<(b))?(a):(b))
+#endif
+#ifndef MAX
+	#define MAX(a,b)	(((a)>(b))?(a):(b))
+#endif
+#ifndef max
+	#define max		MAX
+#endif
+
+#ifndef LOW8
+	#define LOW8(a)		((unsigned char)(a & 0xff))
+#endif
+#ifndef HIGH8
+	#define HIGH8(a)	((unsigned char)((a & 0xff00) >> 8))
+#endif
+#ifndef NUM_ENTRIES
+	#define NUM_ENTRIES(x)	(sizeof(x)/sizeof((x)[0]))
+#endif
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include "io_usbvend.h"
+
+
+
+/* The following table is used to map the USBx port number to 
+ * the device serial number (or physical USB path), */
+#define MAX_EDGEPORTS	64
+
+struct comMapper {
+	char	SerialNumber[MAX_SERIALNUMBER_LEN+1];	/* Serial number/usb path */
+	int	numPorts;			       	/* Number of ports */
+	int	Original[MAX_RS232_PORTS];	       	/* Port numbers set by IOCTL */
+	int	Port[MAX_RS232_PORTS];		       	/* Actual used port numbers */
+};
+
+
+#define EDGEPORT_CONFIG_DEVICE "/proc/edgeport"
+
+/* /proc/edgeport Interface
+ * This interface uses read/write/lseek interface to talk to the edgeport driver
+ * the following read functions are supported: */
+#define PROC_GET_MAPPING_TO_PATH 	1
+#define PROC_GET_COM_ENTRY		2
+#define PROC_GET_EDGE_MANUF_DESCRIPTOR	3
+#define PROC_GET_BOOT_DESCRIPTOR	4
+#define PROC_GET_PRODUCT_INFO		5
+#define PROC_GET_STRINGS		6
+#define PROC_GET_CURRENT_COM_MAPPING	7
+
+/* The parameters to the lseek() for the read is: */
+#define PROC_READ_SETUP(Command, Argument)	((Command) + ((Argument)<<8))
+
+
+/* the following write functions are supported: */
+#define PROC_SET_COM_MAPPING 		1
+#define PROC_SET_COM_ENTRY		2
+
+
+/* The following sturcture is passed to the write */
+struct procWrite {
+	int	Command;
+	union {
+		struct comMapper	Entry;
+		int			ComMappingBasedOnUSBPort;	/* Boolean value */
+	} u;
+};
+
+/*
+ *	Product information read from the Edgeport
+ */
+struct edgeport_product_info {
+	__u16	ProductId;			/* Product Identifier */
+	__u8	NumPorts;			/* Number of ports on edgeport */
+	__u8	ProdInfoVer;			/* What version of structure is this? */
+
+	__u32	IsServer        :1;		/* Set if Server */
+	__u32	IsRS232         :1;		/* Set if RS-232 ports exist */
+	__u32	IsRS422         :1;		/* Set if RS-422 ports exist */
+	__u32	IsRS485         :1;		/* Set if RS-485 ports exist */
+	__u32	IsReserved      :28;		/* Reserved for later expansion */
+
+	__u8	RomSize;			/* Size of ROM/E2PROM in K */
+	__u8	RamSize;			/* Size of external RAM in K */
+	__u8	CpuRev;				/* CPU revision level (chg only if s/w visible) */
+	__u8	BoardRev;			/* PCB revision level (chg only if s/w visible) */
+
+	__u8	BootMajorVersion;		/* Boot Firmware version: xx. */
+	__u8	BootMinorVersion;		/*	   		  yy. */
+	__u16	BootBuildNumber;		/*		      	  zzzz (LE format) */
+
+	__u8	FirmwareMajorVersion;		/* Operational Firmware version:xx. */
+	__u8	FirmwareMinorVersion;		/*				yy. */
+	__u16	FirmwareBuildNumber;		/*				zzzz (LE format) */
+
+	__u8	ManufactureDescDate[3];		/* MM/DD/YY when descriptor template was compiled */
+	__u8	Unused1[1];			/* Available */
+
+	__u8	iDownloadFile;			/* What to download to EPiC device */
+	__u8	Unused2[2];			/* Available */
+};
+
+/*
+ *	Edgeport Stringblock String locations
+ */
+#define EDGESTRING_MANUFNAME		1	/* Manufacture Name */
+#define EDGESTRING_PRODNAME		2	/* Product Name */
+#define EDGESTRING_SERIALNUM		3	/* Serial Number */
+#define EDGESTRING_ASSEMNUM		4	/* Assembly Number */
+#define EDGESTRING_OEMASSEMNUM		5	/* OEM Assembly Number */
+#define EDGESTRING_MANUFDATE		6	/* Manufacture Date */
+#define EDGESTRING_ORIGSERIALNUM	7	/* Serial Number */
+
+struct string_block {
+	__u16	NumStrings;			/* Number of strings in block */
+	__u16	Strings[1];			/* Start of string block */
+};
+
+typedef struct string_block STRING_BLOCK, *PSTRING_BLOCK;
+
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_boot.h linux/drivers/usb/serial/io_fw_boot.h
--- v2.4.2/linux/drivers/usb/serial/io_fw_boot.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_fw_boot.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,558 @@
+//**************************************************************
+//* Edgeport/4 Binary Image
+//* Generated by HEX2C v1.06
+//* Copyright(c) 1998 Inside Out Networks, 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 of the License, or
+//*	(at your option) any later version.
+//**************************************************************
+
+
+//Image structure definition
+#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
+#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
+	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
+	{
+		unsigned short ExtAddr;
+		unsigned short Addr;
+		unsigned short Len;
+		unsigned char  Data[0];
+	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+
+	typedef struct _EDGE_FIRMWARE_VERSION_INFO
+	{
+		unsigned char	 MajorVersion;
+		unsigned char  MinorVersion;
+		unsigned short BuildNumber;
+	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+
+#endif
+
+#if !defined(IMAGE_ARRAY_NAME)
+#define IMAGE_ARRAY_NAME		FirmwareImage
+#define IMAGE_VERSION_NAME	FirmwareImageVersion
+#endif
+
+static unsigned char IMAGE_ARRAY_NAME[] = {
+
+// Segment #1, Start Address 00ff0000, Length 6
+0xff,0x00,0x00,0x00,0x06,0x00,
+    0x02, 0x00, 0x80, 0x02, 0x00, 0x03, 
+
+// Segment #2, Start Address 00ff000b, Length 3
+0xff,0x00,0x0b,0x00,0x03,0x00,
+    0x02, 0x00, 0x0b, 
+
+// Segment #3, Start Address 00ff0013, Length 3
+0xff,0x00,0x13,0x00,0x03,0x00,
+    0x02, 0x01, 0xb8, 
+
+// Segment #4, Start Address 00ff001b, Length 3
+0xff,0x00,0x1b,0x00,0x03,0x00,
+    0x02, 0x00, 0x1b, 
+
+// Segment #5, Start Address 00ff0023, Length 3
+0xff,0x00,0x23,0x00,0x03,0x00,
+    0x02, 0x00, 0x23, 
+
+// Segment #6, Start Address 00ff002b, Length 3
+0xff,0x00,0x2b,0x00,0x03,0x00,
+    0x02, 0x00, 0x2b, 
+
+// Segment #7, Start Address 00ff0033, Length 3
+0xff,0x00,0x33,0x00,0x03,0x00,
+    0x02, 0x00, 0x33, 
+
+// Segment #8, Start Address 00ff003b, Length 3
+0xff,0x00,0x3b,0x00,0x03,0x00,
+    0x02, 0x00, 0x3b, 
+
+// Segment #9, Start Address 00ff0043, Length 3
+0xff,0x00,0x43,0x00,0x03,0x00,
+    0x02, 0x01, 0xbd, 
+
+// Segment #10, Start Address 00ff004b, Length 3
+0xff,0x00,0x4b,0x00,0x03,0x00,
+    0x02, 0x01, 0xd0, 
+
+// Segment #11, Start Address 00ff0053, Length 3
+0xff,0x00,0x53,0x00,0x03,0x00,
+    0x02, 0x01, 0x21, 
+
+// Segment #12, Start Address 00ff007b, Length 3
+0xff,0x00,0x7b,0x00,0x03,0x00,
+    0x02, 0x00, 0x7b, 
+
+// Segment #13, Start Address 00ff0080, Length 358
+0xff,0x00,0x80,0x00,0x66,0x01,
+    0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x3f, 0xf2, 0x7e, 0xf8, 0x00, 0x23, 0x7e, 0x00, 0x01, 0x7e, 0x10, 
+    0x00, 0x12, 0x07, 0x5f, 0x69, 0x20, 0x00, 0x0a, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x05, 0x75, 0x90, 
+    0x0d, 0x80, 0x03, 0x75, 0x90, 0x1d, 0xd2, 0xb5, 0x7e, 0x00, 0x00, 0xa5, 0xd8, 0xfd, 0x75, 0xa8, 
+    0x00, 0x75, 0xb1, 0x00, 0xa9, 0xd5, 0x87, 0xca, 0x29, 0x12, 0x09, 0xcc, 0x12, 0x09, 0xa0, 0xf5, 
+    0x09, 0x7a, 0xa1, 0x20, 0x12, 0x01, 0xe6, 0xda, 0x29, 0xa9, 0xd0, 0xc7, 0x7e, 0x00, 0x05, 0x7a, 
+    0x01, 0xf1, 0x75, 0xe1, 0x10, 0xa9, 0xd7, 0xf4, 0xa9, 0xd7, 0xe4, 0xa5, 0xd8, 0xf1, 0x75, 0xf1, 
+    0x00, 0x75, 0xe1, 0x3f, 0x75, 0xa2, 0x03, 0x75, 0xa3, 0x00, 0x75, 0xc0, 0x00, 0x75, 0xc1, 0x00, 
+    0xa9, 0xd1, 0xb1, 0xa9, 0xd0, 0xb1, 0xa9, 0xd5, 0xd3, 0xd2, 0xaf, 0xe4, 0x7e, 0x04, 0x28, 0x00, 
+    0x8d, 0xef, 0x1b, 0x04, 0x78, 0xfa, 0x04, 0xa9, 0x34, 0xd3, 0x03, 0x30, 0xe0, 0xee, 0xbe, 0x24, 
+    0x00, 0x00, 0x78, 0x05, 0x63, 0x90, 0x30, 0x80, 0xe3, 0xb2, 0x95, 0x80, 0xdf, 0xbe, 0xb0, 0x02, 
+    0x22, 0xc0, 0xd0, 0xa9, 0x20, 0xdf, 0x0f, 0xa9, 0x31, 0xdf, 0x03, 0x02, 0x01, 0xb5, 0x75, 0x08, 
+    0x01, 0x12, 0x08, 0x33, 0x80, 0xfe, 0x75, 0x08, 0xfe, 0x12, 0x08, 0x33, 0x75, 0xa8, 0x00, 0x7e, 
+    0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x4b, 0x30, 0x01, 0x46, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 
+    0x11, 0x09, 0x74, 0x08, 0x19, 0xb2, 0x00, 0x10, 0x74, 0x0e, 0x19, 0xb2, 0x00, 0x04, 0x2e, 0x24, 
+    0x01, 0x00, 0xa5, 0xd9, 0xed, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0xe4, 0xd5, 0xe0, 0xfd, 
+    0x09, 0xb2, 0x00, 0x08, 0x20, 0xe0, 0x0a, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x18, 0x80, 
+    0xeb, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xe4, 0x43, 0x90, 0x30, 0xd2, 0xaa, 0x80, 0x05, 0xd2, 
+    0xaa, 0x43, 0x90, 0x34, 0xd2, 0xaf, 0xa9, 0xd1, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x11, 
+    0xdf, 0x03, 0xa9, 0xd2, 0xdf, 0x75, 0x08, 0xff, 0x12, 0x08, 0x33, 0xc0, 0xd1, 0xca, 0x02, 0xff, 
+    0xca, 0x06, 0x83, 0x00, 0x32, 0xd0, 0xd0, 0x32, 0xc2, 0x8b, 0xc2, 0xaa, 0x32, 0x75, 0x08, 0x08, 
+    0x12, 0x08, 0x33, 0xa9, 0xc0, 0xb1, 0xa9, 0xc5, 0xd3, 0xa9, 0xc6, 0xd3, 0xa9, 0xd2, 0xb1, 0x32, 
+    0xca, 0xb8, 0x75, 0x08, 0x02, 0x12, 0x08, 0x33, 0xe5, 0xc0, 0x54, 0x03, 0x68, 0x05, 0x12, 0x01, 
+    0xee, 0x80, 0xf5, 0xda, 0xb8, 0x32, 
+
+// Segment #14, Start Address 00ff1bca, Length 1
+0xff,0x00,0xca,0x1b,0x01,0x00,
+    0x00, 
+
+// Segment #15, Start Address 00ff01e6, Length 1613
+0xff,0x00,0xe6,0x01,0x4d,0x06,
+    0xe4, 0x7a, 0xb3, 0x3f, 0xf1, 0x02, 0x02, 0x63, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, 
+    0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0xc0, 0xf1, 0x7e, 0xb3, 0x01, 0x2b, 
+    0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x02, 
+    0x4d, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x02, 0xde, 0x80, 0x14, 0x30, 0xc1, 
+    0x08, 0x75, 0xf1, 0x00, 0x12, 0x02, 0xde, 0x80, 0x09, 0x30, 0xc0, 0x06, 0x75, 0xf1, 0x00, 0x12, 
+    0x02, 0x4d, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 
+    0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0xc2, 0xc0, 0x7e, 0xb3, 0x01, 0x2b, 0xb4, 0x02, 0x07, 
+    0x12, 0x02, 0x6f, 0x02, 0x02, 0x63, 0x22, 0xb4, 0x01, 0xfc, 0x02, 0x02, 0xa9, 0x7e, 0x00, 0x00, 
+    0x7a, 0x03, 0x01, 0x2b, 0x7a, 0x03, 0x01, 0x2c, 0x22, 0x7e, 0xb3, 0x01, 0x23, 0x54, 0x60, 0x60, 
+    0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x05, 0x0c, 0x75, 0x08, 0x71, 
+    0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0xf5, 0x8f, 0x22, 0x75, 0xf6, 0x00, 0x22, 0xbe, 0x57, 
+    0x01, 0x29, 0x28, 0x04, 0x7e, 0x57, 0x01, 0x29, 0x7a, 0x0f, 0x01, 0x2e, 0x7a, 0x57, 0x01, 0x32, 
+    0x02, 0x02, 0xa9, 0x7e, 0xef, 0x01, 0x2e, 0x7e, 0xf7, 0x01, 0x32, 0x7e, 0x07, 0x01, 0x32, 0x4d, 
+    0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 
+    0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x01, 0x2e, 0x7a, 0xf7, 0x01, 0x32, 0x75, 0x08, 
+    0x06, 0x12, 0x08, 0x33, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, 0x08, 0x03, 0x12, 0x08, 0x33, 
+    0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, 0xd7, 0xf4, 0xa9, 0x27, 0xf4, 
+    0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x03, 0x55, 0x7e, 0xb3, 0x01, 0x2c, 0xb4, 0x02, 
+    0x0f, 0xa9, 0xd4, 0xe4, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x01, 0x2c, 0x7a, 0xb3, 0x01, 0x2b, 0x22, 
+    0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, 0x7c, 0x32, 0x7e, 0x13, 0x01, 0x2d, 0x2c, 0x21, 0x7a, 0x23, 
+    0x01, 0x2d, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x01, 0x34, 0xe5, 0xe3, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 
+    0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, 0x75, 0x08, 0x70, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x2d, 
+    0x7e, 0xa3, 0x01, 0x2a, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x03, 0xec, 0x22, 0x02, 0x07, 0x55, 0xe5, 
+    0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, 0xe2, 0x7e, 0x01, 0xe3, 0x7e, 0x11, 0xe3, 0x7e, 0x31, 0xe3, 
+    0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, 0x7e, 0x41, 0xe3, 0x7e, 0x71, 0xe3, 0x7e, 0x61, 0xe3, 0x7a, 
+    0x0f, 0x01, 0x23, 0x7a, 0x1f, 0x01, 0x27, 0x75, 0x08, 0x04, 0x12, 0x08, 0x33, 0x7a, 0x01, 0x08, 
+    0x12, 0x08, 0x33, 0x7a, 0x11, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x21, 0x08, 0x12, 0x08, 0x33, 0x7a, 
+    0x31, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x41, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x51, 0x08, 0x12, 0x08, 
+    0x33, 0x7a, 0x61, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x71, 0x08, 0x12, 0x08, 0x33, 0xa9, 0xd4, 0xe4, 
+    0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, 0x12, 0x03, 0xc0, 0x22, 0x6d, 0x00, 0x7e, 0x14, 0x01, 0x02, 
+    0x7a, 0x07, 0x01, 0x32, 0x7a, 0x03, 0x01, 0x2d, 0x7e, 0xb3, 0x01, 0x23, 0x20, 0xe7, 0x0f, 0x7a, 
+    0x23, 0x01, 0x2c, 0x7a, 0x33, 0x01, 0x2b, 0xbe, 0x07, 0x01, 0x29, 0x68, 0x09, 0x22, 0x7a, 0x33, 
+    0x01, 0x2c, 0x7a, 0x23, 0x01, 0x2b, 0x7e, 0xb3, 0x01, 0x23, 0x54, 0xe3, 0x23, 0x23, 0x30, 0xe0, 
+    0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, 0x30, 0xe4, 0x03, 0x02, 0x07, 
+    0x55, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, 0x90, 0x04, 0x18, 0x75, 0x84, 
+    0xff, 0x73, 0x02, 0x05, 0x6c, 0x02, 0x04, 0x60, 0x02, 0x06, 0x09, 0x02, 0x06, 0x24, 0x02, 0x05, 
+    0x05, 0x02, 0x04, 0xc6, 0x02, 0x06, 0x3d, 0x02, 0x06, 0x3d, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 
+    0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 0x06, 0x40, 0x02, 
+    0x06, 0x40, 0x02, 0x06, 0x46, 0x02, 0x06, 0xfa, 0x02, 0x06, 0x43, 0x02, 0x06, 0x43, 0x02, 0x06, 
+    0x43, 0x02, 0x06, 0x43, 0x02, 0x06, 0x43, 0x02, 0x06, 0x43, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x06, 
+    0x2a, 0x7e, 0xb3, 0x01, 0x25, 0x60, 0x56, 0x7c, 0x0b, 0x7e, 0x13, 0x01, 0x26, 0x7e, 0x17, 0x01, 
+    0x27, 0x75, 0x08, 0x72, 0x12, 0x08, 0x33, 0x7a, 0x01, 0x08, 0x12, 0x08, 0x33, 0x7a, 0x11, 0x08, 
+    0x12, 0x08, 0x33, 0x12, 0x07, 0x5f, 0x40, 0x35, 0x02, 0x02, 0x94, 0xb4, 0x08, 0x10, 0x75, 0x08, 
+    0x74, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x3f, 0xf1, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0xb4, 0x00, 
+    0x1c, 0x75, 0x08, 0x75, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x05, 0x75, 0xf3, 
+    0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x07, 0x55, 
+    0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x00, 0x35, 0x75, 0x08, 0x76, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 
+    0x28, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, 0xb3, 0x01, 0x28, 0x20, 0xe7, 0x09, 0xe5, 0xe1, 0x30, 0xe7, 
+    0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, 0xe1, 0x30, 0xe6, 0x04, 0x74, 0x01, 0x80, 0x02, 0x74, 0x00, 
+    0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 0x22, 0x02, 0x07, 0x55, 0xc0, 
+    0xf1, 0x7e, 0xb3, 0x01, 0x28, 0x54, 0x0f, 0x42, 0xf1, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x00, 0x45, 
+    0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x01, 0x24, 0x75, 0x08, 0x77, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 
+    0x28, 0x54, 0x0f, 0x78, 0x05, 0x53, 0xe1, 0x3f, 0x80, 0x37, 0x7e, 0xb3, 0x01, 0x28, 0x20, 0xe7, 
+    0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, 0x53, 0xe1, 0xbf, 0x80, 0x26, 0xb4, 0x03, 0x17, 0x75, 0x08, 
+    0x78, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x28, 0x20, 0xe7, 0x05, 0x43, 0xe1, 0x80, 0x80, 0x11, 
+    0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x75, 0x08, 0x07, 0x12, 0x08, 0x33, 
+    0x22, 0xd0, 0xf1, 0x02, 0x02, 0x90, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x09, 0x23, 0x75, 0x08, 0x79, 
+    0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x11, 0xca, 0xb8, 0xc0, 
+    0xf1, 0x12, 0x01, 0x1d, 0xd0, 0xf1, 0xda, 0xb8, 0x50, 0x76, 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 
+    0xb4, 0x05, 0x08, 0x75, 0x08, 0x7a, 0x12, 0x08, 0x33, 0x80, 0x62, 0xb4, 0x03, 0x19, 0x75, 0x08, 
+    0x7b, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x01, 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 
+    0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 0x75, 0x08, 0x7c, 0x12, 0x08, 0x33, 
+    0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 
+    0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x01, 0x25, 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 
+    0x01, 0x26, 0x7e, 0x17, 0x01, 0x27, 0x75, 0x08, 0x73, 0x12, 0x08, 0x33, 0x7a, 0x01, 0x08, 0x12, 
+    0x08, 0x33, 0x7a, 0x11, 0x08, 0x12, 0x08, 0x33, 0x12, 0x07, 0x8b, 0x40, 0x03, 0x02, 0x02, 0x90, 
+    0x02, 0x07, 0x55, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x0b, 0xf6, 0x75, 0x08, 0x7d, 0x12, 0x08, 0x33, 
+    0x7e, 0xb3, 0x01, 0x26, 0x7e, 0xa3, 0x01, 0x28, 0x4c, 0xab, 0x78, 0xe4, 0x80, 0xdf, 0x7e, 0xb3, 
+    0x01, 0x24, 0xb4, 0x0a, 0xdb, 0x75, 0x08, 0x7e, 0x12, 0x08, 0x33, 0x7e, 0xb3, 0x01, 0x26, 0x70, 
+    0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0x02, 0x07, 0x55, 0x02, 0x07, 0x55, 0x02, 0x07, 0x55, 
+    0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x04, 0x20, 0x75, 0x08, 0xc3, 0x12, 0x08, 0x33, 0x7e, 0x04, 0x00, 
+    0x01, 0x7e, 0x17, 0x01, 0x25, 0x7e, 0x18, 0x01, 0x34, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 0x01, 
+    0x29, 0x12, 0x08, 0x3f, 0x02, 0x06, 0xf4, 0xb4, 0x06, 0x3a, 0x75, 0x08, 0xc1, 0x12, 0x08, 0x33, 
+    0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x01, 0x25, 0x7e, 0x78, 
+    0x01, 0x34, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x29, 0x75, 0x08, 0xc1, 0x12, 0x08, 0x33, 
+    0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x08, 0xd6, 0xd0, 0x87, 0xd0, 0xa8, 
+    0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x02, 0x90, 0xe4, 
+    0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 0x06, 
+    0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, 0x7e, 0x57, 0x01, 0x25, 0x4d, 0x55, 0x68, 0x05, 0xa9, 0xd2, 
+    0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x01, 
+    0x27, 0x7e, 0x17, 0x01, 0x25, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x02, 
+    0x90, 0x02, 0x07, 0x55, 0x7e, 0xb3, 0x01, 0x24, 0xb4, 0x03, 0x15, 0x75, 0x08, 0xc2, 0x12, 0x08, 
+    0x33, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x01, 0x25, 0x7e, 0x57, 0x01, 0x29, 0x02, 0x02, 0x94, 
+    0xb4, 0x05, 0x39, 0x75, 0x08, 0xc0, 0x12, 0x08, 0x33, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 
+    0xd5, 0x87, 0x7e, 0x08, 0x01, 0x34, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 
+    0x01, 0x25, 0x7e, 0x47, 0x01, 0x29, 0x12, 0x08, 0x3f, 0xd0, 0x87, 0xd0, 0xa8, 0x7e, 0x08, 0x01, 
+    0x34, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x01, 0x29, 0x02, 0x02, 0x94, 0x02, 0x07, 0x55, 0x75, 
+    0x08, 0x07, 0x12, 0x08, 0x33, 0x43, 0xe1, 0xc0, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 
+    0xd5, 0x87, 0x12, 0x07, 0xca, 0x40, 0x19, 0x7e, 0x08, 0x01, 0x34, 0x7a, 0x0c, 0x00, 0x00, 0xca, 
+    0x0b, 0xca, 0x49, 0x12, 0x08, 0x3f, 0xda, 0x59, 0xda, 0x0b, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 
+    0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x07, 
+    0xca, 0x40, 0x2b, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 0x01, 
+    0x34, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x29, 0xbd, 0x74, 0x78, 0x11, 0x75, 0x08, 0xc1, 
+    0x12, 0x08, 0x33, 0x12, 0x08, 0xd6, 0x40, 0x06, 0xd0, 0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 
+    0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 
+    0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0x03, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 
+    0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 
+    0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 
+    0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 
+    0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 
+    0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, 
+
+// Segment #16, EXCLUDED Start Address 00ff7c00, Length 199
+
+
+// Segment #17, EXCLUDED Start Address 00ff7f00, Length 192
+
+
+// Segment #17, Start Address 00ff7fc0, Length 64
+0xff,0x00,0xc0,0x7f,0x40,0x00,
+    0x40, 0x01, 0x02, 0x00, 0xca, 0x1b, 0x01, 0x0c, 0x02, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x01, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+// Segment #18, Start Address 00ff0833, Length 5015
+0xff,0x00,0x33,0x08,0x97,0x13,
+    0xca, 0x08, 0x7e, 0x01, 0x08, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x80, 0x50, 0x0b, 0x1a, 
+    0x60, 0x0b, 0x35, 0x0b, 0x1a, 0x70, 0x0b, 0x35, 0x0b, 0x1a, 0x80, 0x0b, 0x35, 0x0b, 0x1a, 0x90, 
+    0x0b, 0x35, 0x0b, 0x1a, 0xa0, 0x0b, 0x35, 0x0b, 0x1a, 0xb0, 0x0b, 0x35, 0x0b, 0x1a, 0xc0, 0x0b, 
+    0x35, 0x0b, 0x1a, 0xd0, 0x0b, 0x35, 0x1b, 0x0a, 0x60, 0x0b, 0x15, 0x1b, 0x0a, 0x70, 0x0b, 0x15, 
+    0x1b, 0x0a, 0x80, 0x0b, 0x15, 0x1b, 0x0a, 0x90, 0x0b, 0x15, 0x1b, 0x0a, 0xa0, 0x0b, 0x15, 0x1b, 
+    0x0a, 0xb0, 0x0b, 0x15, 0x1b, 0x0a, 0xc0, 0x0b, 0x15, 0x1b, 0x0a, 0xd0, 0x0b, 0x15, 0x9e, 0x44, 
+    0x00, 0x10, 0x50, 0xaa, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x0e, 0x7e, 0x1b, 0xc0, 0x7a, 0x0b, 0xc0, 
+    0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 0xfc, 0x7c, 
+    0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 0x44, 0x00, 
+    0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 0xfa, 0x7f, 
+    0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, 0x40, 0x9d, 
+    0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x09, 0x00, 0xda, 0x79, 
+    0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x43, 0x90, 0x30, 
+    0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 
+    0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, 0x6d, 0x77, 
+    0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 0x00, 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 0xf3, 0x7f, 
+    0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x1b, 0x10, 0xbc, 0x10, 0x68, 0x06, 0x1b, 0x54, 
+    0x78, 0xf5, 0x80, 0x2c, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 
+    0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 0x16, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 
+    0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x03, 0x63, 0x90, 0x30, 0x4d, 0x77, 0x78, 0x93, 0xc2, 0xd7, 0x22, 
+    0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 
+    0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 
+    0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 0x18, 0x7f, 
+    0xbd, 0x7a, 0x1c, 0x00, 0xff, 0x0b, 0x1a, 0x00, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 0x51, 0x23, 
+    0x7e, 0x18, 0x09, 0x76, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, 0xa5, 
+    0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 0x7e, 0xe8, 0x7f, 0xbf, 0x7a, 0xec, 0x00, 
+    0xff, 0xe0, 0xf5, 0x22, 0x54, 0xc0, 0x68, 0x16, 0x7e, 0xe8, 0x7f, 0xbe, 0x7a, 0xec, 0x00, 0xff, 
+    0xe0, 0x60, 0x0c, 0x12, 0x09, 0xa0, 0xf5, 0x09, 0x7a, 0xa1, 0x20, 0x02, 0x0f, 0x0a, 0x22, 0xc2, 
+    0x95, 0xd2, 0x94, 0x12, 0x19, 0xfb, 0x53, 0x90, 0xcf, 0x12, 0x19, 0xfb, 0x80, 0xf1, 0x0d, 0x0a, 
+    0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 
+    0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 
+    0x45, 0x64, 0x67, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x34, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x72, 
+    0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 
+    0x73, 0x2c, 0x20, 0x52, 0x65, 0x76, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x3b, 0x20, 0x43, 0x6f, 0x70, 
+    0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, 0x39, 0x39, 0x38, 0x20, 0x49, 0x6e, 0x73, 0x69, 
+    0x64, 0x65, 0x20, 0x4f, 0x75, 0x74, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x0d, 
+    0x0a, 0x00, 0x50, 0x61, 0x73, 0x73, 0x00, 0x46, 0x41, 0x49, 0x4c, 0x20, 0x21, 0x21, 0x00, 0x50, 
+    0x61, 0x73, 0x73, 0x20, 0x20, 0x20, 0x20, 0x00, 0x46, 0x41, 0x49, 0x4c, 0x20, 0x21, 0x21, 0x20, 
+    0x00, 0x0d, 0x0a, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x20, 0x52, 0x61, 0x6d, 0x3a, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x61, 0x6d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x3a, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x62, 
+    0x69, 0x74, 0x20, 0x30, 0x2d, 0x31, 0x34, 0x20, 0x74, 0x65, 0x73, 0x74, 0x3a, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x57, 0x72, 0x6f, 0x74, 0x65, 0x20, 0x41, 
+    0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x20, 0x30, 0x30, 0x3a, 0x00, 0x20, 0x20, 0x77, 0x69, 
+    0x74, 0x68, 0x20, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x20, 0x00, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 
+    0x72, 0x65, 0x61, 0x64, 0x3a, 0x20, 0x00, 0x0d, 0x0a, 0x4f, 0x6e, 0x65, 0x20, 0x6f, 0x72, 0x20, 
+    0x62, 0x6f, 0x74, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x6c, 0x6c, 
+    0x6f, 0x77, 0x69, 0x6e, 0x67, 0x20, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x62, 0x69, 
+    0x74, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x68, 
+    0x6f, 0x72, 0x74, 0x65, 0x64, 0x0d, 0x0a, 0x74, 0x6f, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 
+    0x69, 0x6e, 0x67, 0x3a, 0x20, 0x00, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x00, 0x0d, 0x0a, 0x44, 0x65, 
+    0x74, 0x65, 0x63, 0x74, 0x20, 0x55, 0x61, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 
+    0x53, 0x63, 0x72, 0x61, 0x74, 0x63, 0x68, 0x20, 0x50, 0x61, 0x64, 0x2c, 0x46, 0x69, 0x46, 0x6f, 
+    0x20, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x26, 0x20, 0x52, 0x53, 0x54, 0x3a, 0x20, 0x00, 
+    0x0d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x55, 0x61, 0x72, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74, 0x73, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, 0x31, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, 
+    0x32, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, 0x33, 0x20, 0x20, 0x20, 0x50, 0x6f, 0x72, 0x74, 
+    0x34, 0x0d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 
+    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 
+    0x2d, 0x00, 0x0d, 0x0a, 0x50, 0x6f, 0x72, 0x74, 0x20, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x72, 
+    0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x20, 
+    0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x41, 0x6e, 0x61, 0x6c, 
+    0x6f, 0x67, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 
+    0x52, 0x58, 0x44, 0x2c, 0x54, 0x58, 0x44, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x54, 0x53, 0x2c, 0x43, 
+    0x54, 0x53, 0x2c, 0x52, 0x49, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x00, 0x0d, 0x0a, 0x52, 0x58, 0x44, 0x2c, 0x54, 0x58, 0x44, 0x20, 0x74, 0x6f, 0x20, 0x44, 
+    0x54, 0x52, 0x2c, 0x44, 0x53, 0x52, 0x2c, 0x43, 0x44, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x5b, 0x43, 0x54, 0x53, 0x2c, 
+    0x52, 0x49, 0x5d, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x54, 0x52, 0x2c, 0x44, 0x53, 0x52, 0x2c, 0x43, 
+    0x44, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x5b, 
+    0x43, 0x54, 0x53, 0x2c, 0x43, 0x44, 0x5d, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x53, 0x52, 0x2c, 0x52, 
+    0x49, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 
+    0x44, 0x54, 0x52, 0x5b, 0x44, 0x53, 0x52, 0x2c, 0x43, 0x44, 0x5d, 0x20, 0x74, 0x6f, 0x20, 0x52, 
+    0x54, 0x53, 0x2c, 0x43, 0x54, 0x53, 0x2c, 0x52, 0x49, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 
+    0x20, 0x00, 0x0d, 0x0a, 0x44, 0x54, 0x52, 0x20, 0x74, 0x6f, 0x20, 0x43, 0x54, 0x53, 0x2c, 0x43, 
+    0x44, 0x20, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x20, 0x74, 0x6f, 0x20, 0x43, 
+    0x54, 0x53, 0x2c, 0x52, 0x49, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 
+    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 0x52, 0x54, 0x53, 0x20, 
+    0x74, 0x6f, 0x20, 0x43, 0x54, 0x53, 0x2c, 0x43, 0x44, 0x20, 0x4c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 
+    0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0d, 0x0a, 
+    0x44, 0x54, 0x52, 0x20, 0x74, 0x6f, 0x20, 0x44, 0x53, 0x52, 0x2c, 0x43, 0x44, 0x20, 0x4c, 0x6f, 
+    0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
+    0x20, 0x00, 0x0d, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x45, 0x20, 0x52, 0x20, 0x52, 0x20, 0x4f, 0x20, 
+    0x52, 0x20, 0x21, 0x21, 0x21, 0x2c, 0x20, 0x45, 0x20, 0x52, 0x20, 0x52, 0x20, 0x4f, 0x20, 0x52, 
+    0x20, 0x21, 0x21, 0x21, 0x20, 0x2c, 0x20, 0x45, 0x20, 0x52, 0x20, 0x52, 0x20, 0x4f, 0x20, 0x52, 
+    0x20, 0x21, 0x21, 0x21, 0x0d, 0x0a, 0x0a, 0x44, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 
+    0x63, 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x65, 0x6e, 0x74, 0x65, 
+    0x72, 0x20, 0x61, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x6f, 
+    0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x64, 0x65, 0x74, 0x65, 
+    0x63, 0x74, 0x65, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x00, 0x0d, 0x0a, 0x0a, 0x4e, 
+    0x6f, 0x20, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 
+    0x73, 0x20, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x0d, 0x0a, 0x00, 0x43, 0x6f, 
+    0x70, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 
+    0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x53, 0x6c, 0x61, 0x76, 0x65, 0x27, 
+    0x73, 0x20, 0x45, 0x45, 0x70, 0x72, 0x6f, 0x6d, 0x20, 0x2e, 0x2e, 0x2e, 0x00, 0x44, 0x6f, 0x6e, 
+    0x65, 0x0d, 0x0a, 0x0a, 0x2d, 0x3e, 0x20, 0x54, 0x75, 0x72, 0x6e, 0x20, 0x75, 0x6e, 0x69, 0x74, 
+    0x20, 0x6f, 0x66, 0x66, 0x2c, 0x20, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 
+    0x20, 0x63, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x73, 
+    0x74, 0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x20, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 
+    0x73, 0x74, 0x69, 0x63, 0x73, 0x2e, 0x00, 0xc2, 0xaf, 0xc2, 0x09, 0xc2, 0x0a, 0x75, 0x90, 0x0d, 
+    0x20, 0x17, 0x02, 0xd2, 0xb5, 0x43, 0x90, 0x30, 0x6c, 0x00, 0x7e, 0x10, 0x03, 0x12, 0x0f, 0x38, 
+    0x7e, 0x68, 0x0a, 0x01, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, 0x30, 0xb4, 0x02, 
+    0x80, 0x24, 0x02, 0x1b, 0x3c, 0x20, 0x09, 0x1d, 0xc2, 0x94, 0xd2, 0x95, 0x12, 0x19, 0xfb, 0x53, 
+    0x90, 0xcf, 0x12, 0x19, 0xfb, 0xc2, 0x95, 0xd2, 0x94, 0x12, 0x19, 0xfb, 0xa5, 0xd9, 0xe6, 0x43, 
+    0x90, 0x30, 0x12, 0x19, 0xfb, 0x22, 0x7e, 0x68, 0x0a, 0x94, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 
+    0x93, 0x7e, 0xe4, 0x10, 0x00, 0x7e, 0x40, 0x55, 0x7a, 0xe9, 0x40, 0x0b, 0xe4, 0x7e, 0x50, 0xaa, 
+    0x7a, 0xe9, 0x50, 0x1b, 0xe4, 0xbe, 0xe9, 0x40, 0x68, 0x19, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x13, 0x7a, 0xe9, 0x40, 0x7e, 0xe9, 
+    0x10, 0x80, 0xf8, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, 
+    0x7e, 0x68, 0x0a, 0xd8, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x78, 0x00, 0x00, 0x7e, 
+    0x70, 0x0e, 0x7e, 0xa4, 0xff, 0xff, 0x7e, 0xb4, 0xbf, 0xff, 0x7d, 0xcb, 0x0e, 0xc4, 0x7d, 0xdc, 
+    0x5d, 0xdb, 0x6c, 0xbb, 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 
+    0xfb, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 
+    0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x6c, 0xbb, 
+    0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x41, 0x0b, 0xb0, 0x7d, 0xfb, 0x5e, 
+    0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x34, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 
+    0xbe, 0x7b, 0xb0, 0x78, 0x27, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 
+    0x78, 0x1a, 0x0b, 0xb0, 0xbe, 0xc4, 0xff, 0xfe, 0x78, 0x92, 0x0e, 0xb4, 0xa5, 0xdf, 0x8b, 0x7e, 
+    0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x77, 0xca, 0x5b, 0xca, 0x6b, 
+    0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0b, 0x2a, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0a, 0x47, 0x12, 0x1a, 0xc9, 0x7e, 0x68, 0x0b, 0x79, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x6c, 0x77, 0xda, 0x6b, 0xca, 0x6b, 0x0b, 0x70, 0x0e, 0xc4, 
+    0xbe, 0xc4, 0xff, 0xff, 0x78, 0xf6, 0x1b, 0x70, 0x0a, 0x47, 0x12, 0x1a, 0xc9, 0x12, 0x1a, 0x08, 
+    0x30, 0x09, 0x30, 0xda, 0x6b, 0xda, 0x5b, 0x6c, 0xbb, 0x7e, 0x78, 0x00, 0x00, 0x7d, 0xfa, 0x5e, 
+    0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfb, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 
+    0xfc, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 
+    0xb0, 0x80, 0xd4, 0x7e, 0x68, 0x0a, 0xb6, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x30, 0x17, 
+    0x0e, 0x7e, 0x78, 0x04, 0x20, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x44, 0x7b, 0xe0, 0x80, 0x0c, 0x7e, 
+    0x78, 0x00, 0x00, 0x7a, 0x7c, 0x00, 0x01, 0x7e, 0x44, 0x80, 0x00, 0x0b, 0x00, 0x7e, 0x40, 0x3a, 
+    0x7c, 0x54, 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 0x7a, 0x5b, 0x50, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 
+    0xde, 0x02, 0x0b, 0x50, 0x1b, 0x84, 0x78, 0xf0, 0x7c, 0x54, 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 
+    0xbe, 0x5b, 0x50, 0x78, 0x1a, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 0xde, 0x02, 0x0b, 0x50, 0x1b, 0x84, 
+    0x78, 0xee, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x4b, 0x7f, 
+    0x45, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0a, 0xfa, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7d, 0x4b, 0x12, 0x1a, 0xc9, 0x7e, 0x68, 0x0b, 0x0f, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x6c, 0x88, 0x7c, 0x95, 0x12, 0x1a, 0xc9, 0x7e, 0x68, 
+    0x0b, 0x1d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x4b, 0x90, 0x12, 0x1a, 0xc9, 0x12, 
+    0x1a, 0x08, 0x30, 0x09, 0x05, 0x7e, 0x4b, 0x90, 0x80, 0xfb, 0x7e, 0x68, 0x0b, 0x7f, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, 0xd2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 
+    0x08, 0xbe, 0xb0, 0x01, 0x78, 0x0b, 0x09, 0xb2, 0x00, 0x14, 0xbe, 0xb0, 0x60, 0x78, 0x02, 0x80, 
+    0x17, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 
+    0x09, 0x11, 0x09, 0xb2, 0x00, 0x08, 0x80, 0xfa, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0b, 0xa1, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x0b, 0x00, 
+    0xc2, 0x92, 0x12, 0x19, 0xee, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x1c, 
+    0x7e, 0xb0, 0x01, 0x19, 0xb2, 0x00, 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x37, 0x09, 
+    0xb2, 0x00, 0x08, 0x5e, 0xb0, 0xc0, 0xbe, 0xb0, 0xc0, 0x78, 0x2b, 0x7e, 0xa0, 0xaa, 0x19, 0xa2, 
+    0x00, 0x1c, 0x6c, 0xbb, 0x19, 0xb2, 0x00, 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x16, 
+    0x09, 0xb2, 0x00, 0x08, 0x5e, 0xb0, 0xc0, 0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x75, 0x7a, 0x6c, 0x00, 
+    0xff, 0x12, 0x1a, 0x93, 0x80, 0x1b, 0x7e, 0x68, 0x0a, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 
+    0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0a, 0x19, 0xa2, 0x00, 0x1c, 0x09, 0xb2, 0x00, 0x1c, 0x80, 
+    0xf6, 0x7e, 0x68, 0x0b, 0xc3, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x68, 0x0c, 0x45, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x7e, 0xb0, 
+    0x01, 0x19, 0xb2, 0x00, 0x1c, 0x2e, 0x24, 0x01, 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xf3, 0x7e, 0x24, 
+    0x80, 0x00, 0x7e, 0x11, 0x09, 0x7e, 0xb0, 0x01, 0x0b, 0x00, 0x09, 0xa2, 0x00, 0x1c, 0xbc, 0xab, 
+    0x78, 0x16, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 
+    0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xe2, 0x80, 0x25, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 
+    0x09, 0xa2, 0x00, 0x1c, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf5, 0x80, 0xec, 0x7e, 0x68, 0x0c, 
+    0x69, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x13, 0x8a, 0x7e, 0x24, 0x80, 0x00, 0x7e, 
+    0x11, 0x09, 0x0b, 0x00, 0x74, 0x10, 0x19, 0xb2, 0x00, 0x10, 0x12, 0x13, 0x03, 0x2e, 0x24, 0x01, 
+    0x00, 0xa5, 0xd9, 0xee, 0x7e, 0x68, 0x0c, 0x8d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 
+    0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0xe4, 0x19, 0xb2, 0x00, 0x10, 0x12, 0x13, 0x03, 
+    0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xef, 0x30, 0x00, 0x03, 0x02, 0x18, 0xb7, 0x02, 0x13, 0xbb, 
+    0x74, 0x07, 0x19, 0xb2, 0x00, 0x08, 0x12, 0x19, 0xfb, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xc2, 0x0b, 0x7e, 0xb0, 0x55, 0x12, 0x13, 
+    0x64, 0x7e, 0xb0, 0xaa, 0x12, 0x13, 0x64, 0x7e, 0xb0, 0x00, 0x12, 0x13, 0x64, 0x7e, 0xb0, 0xff, 
+    0x12, 0x13, 0x64, 0x30, 0x0b, 0x0f, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 
+    0x93, 0x12, 0x1a, 0x08, 0x22, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 
+    0x22, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x09, 0xa2, 0x00, 0x00, 0xbc, 0xab, 0x78, 0x01, 
+    0x22, 0x20, 0x09, 0x03, 0xd2, 0x0b, 0x22, 0x12, 0x1a, 0x08, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 
+    0xee, 0x09, 0xa2, 0x00, 0x00, 0x80, 0xf3, 0xd2, 0x92, 0x12, 0x19, 0xee, 0xc2, 0x92, 0x12, 0x19, 
+    0xee, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x74, 0x80, 0x19, 0xb2, 0x00, 0x0c, 0x7e, 0x54, 
+    0x00, 0x02, 0x19, 0xa2, 0x00, 0x04, 0x19, 0xb2, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb2, 0x00, 0x0c, 
+    0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xe1, 0x22, 0x7e, 0x68, 0x0c, 0xb1, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x12, 0x19, 0xee, 0x09, 
+    0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 
+    0x18, 0x5e, 0xb0, 0x05, 0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 
+    0x93, 0x80, 0x1a, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 
+    0x08, 0x30, 0x09, 0x09, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x80, 0xf7, 0x2e, 0x24, 0x01, 
+    0x00, 0xa5, 0xd9, 0xb6, 0x7e, 0x68, 0x0c, 0xd5, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 
+    0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 
+    0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 
+    0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x1a, 0x7e, 
+    0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x09, 
+    0x19, 0xa2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x80, 0xf7, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xb6, 
+    0x30, 0x04, 0x03, 0x02, 0x16, 0x8c, 0x7e, 0x68, 0x0c, 0xf9, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 
+    0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 
+    0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 
+    0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 0x78, 0x3c, 
+    0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 
+    0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 
+    0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 0x78, 0x14, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe6, 0x7e, 0xa0, 0x02, 
+    0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x0d, 0x41, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 
+    0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 
+    0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 
+    0x18, 0x5e, 0xb0, 0x05, 0x78, 0x3c, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 
+    0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 
+    0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x14, 0x7e, 0x68, 
+    0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 
+    0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 
+    0x30, 0x09, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 
+    0x80, 0xf1, 0x7e, 0x68, 0x0d, 0x89, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 
+    0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 
+    0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0xbe, 0xb0, 0x50, 0x78, 0x1f, 0x6c, 0xaa, 0x19, 0xa2, 
+    0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0x78, 0x0d, 0x7e, 0x68, 
+    0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0f, 0x7e, 0xa0, 0x02, 0x19, 
+    0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 
+    0xd9, 0xa2, 0x7e, 0x68, 0x0d, 0xd1, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 
+    0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 
+    0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0xa0, 0xbe, 0xb0, 0xa0, 0x78, 0x1f, 
+    0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0xa0, 
+    0x78, 0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x20, 0x7e, 
+    0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0f, 
+    0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 
+    0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x02, 0x18, 0x2b, 0x7e, 0x68, 0x0d, 0x1d, 0x7a, 0x6c, 0x00, 
+    0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 
+    0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 
+    0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 
+    0x06, 0x78, 0x3c, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 
+    0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 
+    0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x06, 0x78, 0x14, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 
+    0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0xe6, 
+    0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 
+    0x68, 0x0d, 0x65, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 
+    0x09, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 
+    0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 
+    0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 0x3c, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 
+    0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 
+    0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 
+    0x14, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x2e, 0x24, 0x01, 0x00, 
+    0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 
+    0x12, 0x1a, 0x08, 0x30, 0x09, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 
+    0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x0d, 0xad, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 
+    0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 
+    0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x90, 0xbe, 0xb0, 0x90, 0x78, 0x1f, 0x6c, 
+    0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x90, 0x78, 
+    0x0d, 0x7e, 0x68, 0x0a, 0x82, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x80, 0x20, 0x7e, 0x68, 
+    0x0a, 0x8b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1a, 0x08, 0x30, 0x09, 0x0f, 0x7e, 
+    0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 
+    0x01, 0x00, 0xa5, 0xd9, 0xa2, 0x02, 0x18, 0xb7, 0x30, 0x17, 0x03, 0x02, 0x19, 0x3b, 0xc2, 0x8a, 
+    0x12, 0x19, 0x22, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x04, 
+    0x12, 0x19, 0xee, 0x0b, 0x00, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x20, 
+    0x8b, 0x3e, 0x20, 0x89, 0x3b, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x04, 0x09, 0xa2, 0x00, 0x10, 
+    0x4e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x30, 0x8b, 0x23, 0x30, 0x89, 0x20, 
+    0x09, 0xa2, 0x00, 0x10, 0x5e, 0xa0, 0xfd, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 0x7e, 0xa0, 
+    0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x19, 0xee, 0x20, 0x8b, 0x05, 0x20, 0x89, 0x02, 0x80, 0x1a, 
+    0x12, 0x1a, 0x08, 0x30, 0x09, 0x14, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x00, 0x00, 0x5e, 
+    0xa0, 0xfd, 0x19, 0xa2, 0x00, 0x10, 0x00, 0x00, 0x80, 0xec, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 
+    0x89, 0x02, 0x19, 0x3b, 0x20, 0x17, 0xfa, 0x12, 0x13, 0x8a, 0x12, 0x19, 0x22, 0x7e, 0x24, 0x80, 
+    0x00, 0x7e, 0x11, 0x09, 0x0b, 0x00, 0x20, 0x89, 0x26, 0x7e, 0xa0, 0xff, 0x19, 0xa2, 0x00, 0x04, 
+    0x12, 0x19, 0xee, 0x7e, 0xb0, 0x55, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x30, 0x89, 0x0f, 
+    0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x19, 0xee, 0x20, 0x89, 0x02, 0x80, 0x26, 0x12, 
+    0x1a, 0x08, 0x30, 0x09, 0x20, 0x7e, 0xa0, 0xff, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x19, 0xee, 0x7e, 
+    0xb0, 0x55, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x19, 0xee, 0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 
+    0x12, 0x19, 0xee, 0x80, 0xe0, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xa8, 0x02, 0x19, 0x3b, 0x7e, 
+    0x24, 0x80, 0x00, 0x7e, 0x11, 0x09, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x19, 0xee, 
+    0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xef, 0x22, 0x30, 0x0a, 0x19, 0x7e, 0x68, 0x0d, 0xf5, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0xd2, 0x09, 0x12, 0x19, 0xee, 0x12, 0x19, 0xee, 0x12, 0x19, 
+    0xee, 0x02, 0x0f, 0x10, 0x30, 0x17, 0x1c, 0x7e, 0x68, 0x0e, 0x6f, 0x7a, 0x6c, 0x00, 0xff, 0x12, 
+    0x1a, 0x93, 0x7e, 0x68, 0x0e, 0x91, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x1a, 0x93, 0x12, 0x1b, 0x3c, 
+    0x02, 0x19, 0xe6, 0x0b, 0x00, 0x7e, 0x78, 0x19, 0xa0, 0x7a, 0x7c, 0x00, 0xff, 0x7f, 0x67, 0x7a, 
+    0x6c, 0x00, 0x00, 0x7e, 0x70, 0x3e, 0x7e, 0x7b, 0xb0, 0x7a, 0x6b, 0xb0, 0x0b, 0x7c, 0x0b, 0x6c, 
+    0xa5, 0xdf, 0xf3, 0x7e, 0x78, 0x19, 0xa0, 0x7a, 0x7c, 0x00, 0x00, 0x89, 0x78, 0x7e, 0x78, 0x00, 
+    0x00, 0x7a, 0x7c, 0x00, 0xfe, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 0xfe, 0x74, 0xaa, 0x39, 
+    0xb7, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb7, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb7, 0x55, 0x55, 0x6c, 
+    0x99, 0x7a, 0x6b, 0x90, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x6b, 0x80, 0xbc, 0x89, 0x68, 0x08, 0x1b, 
+    0x54, 0x78, 0xf5, 0x8a, 0xff, 0x19, 0xde, 0x8a, 0xff, 0x19, 0xe6, 0x12, 0x1a, 0x08, 0x7e, 0x6b, 
+    0x80, 0x80, 0xfb, 0x7e, 0x10, 0xff, 0x12, 0x1a, 0x85, 0x80, 0xf8, 0xca, 0xf9, 0x7e, 0xf4, 0x00, 
+    0xff, 0x1b, 0xf4, 0x78, 0xfc, 0xda, 0xf9, 0x22, 0xca, 0xf9, 0x7e, 0xf4, 0x00, 0x00, 0x1b, 0xf4, 
+    0x78, 0xfc, 0xda, 0xf9, 0x22, 0x20, 0x09, 0x19, 0xd2, 0x0a, 0x12, 0x19, 0xfb, 0xc2, 0x95, 0xd2, 
+    0x94, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x43, 0x90, 0x30, 
+    0x22, 0xca, 0x0b, 0x7e, 0x10, 0x03, 0x7c, 0x30, 0x6c, 0x22, 0x0b, 0x20, 0x9e, 0x30, 0x0a, 0x50, 
+    0xf9, 0x2e, 0x30, 0x0b, 0x1b, 0x20, 0x68, 0x18, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x53, 0x90, 
+    0xcf, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x43, 0x90, 0x30, 0xa5, 0xda, 0xe8, 
+    0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x1b, 0x30, 0x68, 0x19, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 
+    0xc2, 0x95, 0xd2, 0x94, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x12, 0x19, 0xfb, 0x43, 0x90, 0x30, 
+    0xa5, 0xdb, 0xe7, 0x7e, 0x20, 0x0a, 0x12, 0x19, 0xfb, 0xa5, 0xda, 0xfa, 0xa5, 0xd9, 0xa7, 0xda, 
+    0x0b, 0x22, 0x20, 0x09, 0x0a, 0x12, 0x19, 0xfb, 0xb2, 0x94, 0x12, 0x19, 0xfb, 0xb2, 0x94, 0x22, 
+    0x30, 0x17, 0x32, 0x20, 0x09, 0x2f, 0xca, 0x2b, 0xca, 0x7b, 0x7e, 0x78, 0x80, 0x00, 0x7a, 0x7c, 
+    0x00, 0xfe, 0x12, 0x1b, 0x1c, 0x7e, 0x6b, 0xa0, 0x5c, 0xaa, 0x68, 0x10, 0x29, 0xb7, 0x00, 0x14, 
+    0x54, 0x60, 0x68, 0xf8, 0x39, 0xa7, 0x00, 0x00, 0x0b, 0x6c, 0x80, 0xe9, 0x12, 0x19, 0xee, 0xd2, 
+    0xb5, 0xda, 0x7b, 0xda, 0x2b, 0x22, 0x12, 0x1a, 0xd4, 0x7e, 0x68, 0x00, 0x0b, 0x12, 0x1a, 0x93, 
+    0x22, 0xca, 0x59, 0xca, 0x5b, 0x7e, 0xb4, 0x00, 0x0b, 0x7c, 0xb8, 0xc4, 0x12, 0x1b, 0x04, 0x7c, 
+    0xb8, 0x12, 0x1b, 0x04, 0x7c, 0xb9, 0xc4, 0x12, 0x1b, 0x04, 0x7c, 0xb9, 0x12, 0x1b, 0x04, 0x7e, 
+    0xb0, 0x68, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x6c, 0xbb, 0x7a, 0xb9, 0xb0, 0xda, 0x59, 0xda, 0x5b, 
+    0x22, 0x5e, 0xb0, 0x0f, 0x7c, 0xab, 0x9e, 0xa0, 0x0a, 0x40, 0x05, 0x2e, 0xb0, 0x37, 0x80, 0x03, 
+    0x2e, 0xb0, 0x30, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x22, 0xc2, 0xb5, 0xc2, 0x92, 0x12, 0x19, 0xee, 
+    0x74, 0x80, 0x39, 0xb7, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x06, 0x39, 0xa7, 0x00, 0x04, 0x39, 0xb7, 
+    0x00, 0x00, 0x74, 0x03, 0x39, 0xb7, 0x00, 0x0c, 0x22, 0x7e, 0x78, 0x00, 0x00, 0x7a, 0x7c, 0x00, 
+    0xff, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0x01, 0x7f, 0x65, 0x7e, 0x74, 0x20, 0x00, 0x12, 
+    0x08, 0xd6, 0x40, 0x54, 0x7e, 0x78, 0x7c, 0x00, 0x7a, 0x7c, 0x00, 0xff, 0x7e, 0x58, 0x00, 0x00, 
+    0x7a, 0x5c, 0x00, 0x01, 0x7e, 0x68, 0x7c, 0x00, 0x7a, 0x6c, 0x00, 0x01, 0x7e, 0x74, 0x04, 0x00, 
+    0x12, 0x08, 0xd6, 0x40, 0x33, 0x74, 0x80, 0x12, 0x1b, 0xb1, 0x40, 0x2c, 0x53, 0x90, 0xcf, 0xd2, 
+    0x08, 0x7e, 0x04, 0x00, 0x08, 0x7e, 0x14, 0x00, 0x00, 0x84, 0xa5, 0xdb, 0xfc, 0xa5, 0xda, 0xf9, 
+    0xa5, 0xd9, 0xf6, 0x74, 0x40, 0x12, 0x1b, 0xb1, 0x40, 0x0e, 0x7e, 0x68, 0x0e, 0xc0, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x1a, 0x93, 0x02, 0x19, 0xe6, 0xc2, 0x95, 0xd2, 0x94, 0x80, 0xfe, 0xf5, 0x0a, 
+    0x7e, 0x78, 0x00, 0x0a, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 0x01, 
+    0x7e, 0x74, 0x00, 0x01, 0x02, 0x08, 0xd6, 
+};
+
+static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+	1, 12, 2 };		// Major, Minor, Build
+
+#undef IMAGE_VERSION_NAME
+
+#undef IMAGE_ARRAY_NAME
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_boot2.h linux/drivers/usb/serial/io_fw_boot2.h
--- v2.4.2/linux/drivers/usb/serial/io_fw_boot2.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_fw_boot2.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,548 @@
+//**************************************************************
+//* Edgeport/4 Binary Image
+//* Generated by HEX2C v1.06
+//* Copyright(c) 1998 Inside Out Networks, 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 of the License, or
+//*	(at your option) any later version.
+//**************************************************************
+
+
+//Image structure definition
+#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
+#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
+	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
+	{
+		unsigned short ExtAddr;
+		unsigned short Addr;
+		unsigned short Len;
+		unsigned char  Data[0];
+	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+
+	typedef struct _EDGE_FIRMWARE_VERSION_INFO
+	{
+		unsigned char	 MajorVersion;
+		unsigned char  MinorVersion;
+		unsigned short BuildNumber;
+	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+
+#endif
+
+#if !defined(IMAGE_ARRAY_NAME)
+#define IMAGE_ARRAY_NAME		FirmwareImage
+#define IMAGE_VERSION_NAME	FirmwareImageVersion
+#endif
+
+static unsigned char IMAGE_ARRAY_NAME[] = {
+
+// Segment #1, Start Address 00ff0000, Length 6
+0xff,0x00,0x00,0x00,0x06,0x00,
+    0x02, 0x00, 0x80, 0x02, 0x00, 0x03, 
+
+// Segment #2, Start Address 00ff000b, Length 3
+0xff,0x00,0x0b,0x00,0x03,0x00,
+    0x02, 0x00, 0x0b, 
+
+// Segment #3, Start Address 00ff0013, Length 3
+0xff,0x00,0x13,0x00,0x03,0x00,
+    0x02, 0x02, 0x56, 
+
+// Segment #4, Start Address 00ff001b, Length 3
+0xff,0x00,0x1b,0x00,0x03,0x00,
+    0x02, 0x00, 0x1b, 
+
+// Segment #5, Start Address 00ff0023, Length 3
+0xff,0x00,0x23,0x00,0x03,0x00,
+    0x02, 0x00, 0x23, 
+
+// Segment #6, Start Address 00ff002b, Length 3
+0xff,0x00,0x2b,0x00,0x03,0x00,
+    0x02, 0x00, 0x2b, 
+
+// Segment #7, Start Address 00ff0033, Length 3
+0xff,0x00,0x33,0x00,0x03,0x00,
+    0x02, 0x00, 0x33, 
+
+// Segment #8, Start Address 00ff003b, Length 3
+0xff,0x00,0x3b,0x00,0x03,0x00,
+    0x02, 0x00, 0x3b, 
+
+// Segment #9, Start Address 00ff0043, Length 3
+0xff,0x00,0x43,0x00,0x03,0x00,
+    0x02, 0x00, 0x43, 
+
+// Segment #10, Start Address 00ff004b, Length 3
+0xff,0x00,0x4b,0x00,0x03,0x00,
+    0x02, 0x00, 0x4b, 
+
+// Segment #11, Start Address 00ff0053, Length 3
+0xff,0x00,0x53,0x00,0x03,0x00,
+    0x02, 0x01, 0xf5, 
+
+// Segment #12, Start Address 00ff007b, Length 3
+0xff,0x00,0x7b,0x00,0x03,0x00,
+    0x02, 0x00, 0x7b, 
+
+// Segment #13, Start Address 00ff0080, Length 534
+0xff,0x00,0x80,0x00,0x16,0x02,
+    0x7e, 0xb3, 0x91, 0x01, 0x20, 0xe3, 0x0c, 0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 
+    0xf2, 0x80, 0x0a, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x74, 0x00, 0x7a, 
+    0xb3, 0x91, 0x00, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x7e, 0xf8, 0x00, 0x24, 0x7e, 0x00, 0x01, 
+    0x7e, 0x10, 0x00, 0x12, 0x09, 0xd0, 0x69, 0x20, 0x00, 0x0a, 0x5e, 0x40, 0x1f, 0xbe, 0x24, 0x00, 
+    0x00, 0x78, 0x09, 0x7e, 0x00, 0x03, 0x7a, 0x03, 0x90, 0x00, 0x80, 0x07, 0x7e, 0x00, 0x02, 0x7a, 
+    0x03, 0x90, 0x00, 0x75, 0xb0, 0xdf, 0x7e, 0x00, 0x01, 0x7a, 0x03, 0x94, 0x00, 0x7a, 0x03, 0x01, 
+    0x24, 0x7e, 0x00, 0x01, 0x7a, 0x03, 0x93, 0x00, 0x7e, 0x00, 0x00, 0xa5, 0xd8, 0xfd, 0x75, 0xa8, 
+    0x00, 0x75, 0xb1, 0x00, 0xca, 0x29, 0x12, 0x0c, 0x66, 0x12, 0x0c, 0x37, 0xf5, 0x21, 0x7a, 0xa1, 
+    0x20, 0x20, 0x09, 0x08, 0x20, 0x0a, 0x0a, 0x7e, 0xb0, 0x0c, 0x80, 0x08, 0x7e, 0xb0, 0x00, 0x80, 
+    0x03, 0x7e, 0xb0, 0x08, 0x7a, 0xb3, 0x92, 0x00, 0x12, 0x02, 0x96, 0xda, 0x29, 0x74, 0x10, 0x7a, 
+    0xb3, 0x91, 0x01, 0x7e, 0x20, 0x04, 0x7c, 0xb2, 0xc2, 0xd7, 0x13, 0x13, 0x13, 0x13, 0x7a, 0xb3, 
+    0x91, 0x00, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x74, 0x02, 
+    0x7a, 0xb3, 0x91, 0x12, 0xa5, 0xda, 0xdf, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 
+    0xb3, 0x91, 0x1c, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x07, 0x74, 
+    0x34, 0x7a, 0xb3, 0x91, 0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x02, 0x7a, 0xb3, 0x91, 
+    0x06, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x07, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x44, 0x7a, 
+    0xb3, 0x91, 0x07, 0x74, 0xef, 0x7a, 0xb3, 0x91, 0x04, 0x74, 0x07, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 
+    0xb3, 0x91, 0x07, 0x7a, 0xb1, 0x0a, 0x75, 0x09, 0x01, 0xd2, 0xaa, 0xd2, 0xaf, 0xe4, 0x7e, 0x60, 
+    0x02, 0x4d, 0x22, 0x78, 0x03, 0x7e, 0x60, 0x03, 0x7c, 0x76, 0x7e, 0x04, 0x28, 0x00, 0x8d, 0xef, 
+    0x1b, 0x04, 0x78, 0xfa, 0x04, 0x7e, 0x20, 0x07, 0x7a, 0x23, 0x91, 0x06, 0x7e, 0x23, 0x91, 0x07, 
+    0x7e, 0x31, 0x0a, 0xbc, 0x32, 0x68, 0x22, 0x7a, 0x21, 0x0a, 0x7e, 0x21, 0x09, 0x68, 0x17, 0xca, 
+    0xb8, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 0x44, 0x02, 0x7a, 0xb3, 0x91, 
+    0x07, 0xda, 0xb8, 0x75, 0x09, 0x00, 0x30, 0xe0, 0xc1, 0x6c, 0x67, 0x7a, 0x63, 0x90, 0x00, 0x80, 
+    0xb9, 0xbe, 0xb0, 0x02, 0x22, 0xc0, 0xd0, 0x75, 0x08, 0xfe, 0x12, 0x0a, 0xc0, 0x74, 0x02, 0x7a, 
+    0xb3, 0x91, 0x06, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x07, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 
+    0x00, 0x7a, 0xb3, 0x91, 0x07, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x04, 0x7e, 0xb3, 0x3f, 0xf2, 0x30, 
+    0xe0, 0x08, 0x74, 0x18, 0x7a, 0xb3, 0x91, 0x01, 0x80, 0x06, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x01, 
+    0x74, 0x10, 0x7a, 0xb3, 0x91, 0x04, 0x02, 0x02, 0x36, 0x75, 0x08, 0xff, 0x12, 0x0a, 0xc0, 0x74, 
+    0x01, 0x7a, 0xb3, 0x91, 0x04, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 0x54, 
+    0xfc, 0x7a, 0xb3, 0x91, 0x07, 0x32, 0xca, 0xb8, 0x75, 0x08, 0x02, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 
+    0x91, 0x03, 0x20, 0xe5, 0x08, 0x30, 0xe0, 0x2b, 0x12, 0x02, 0x9e, 0x80, 0xf1, 0x7e, 0xb3, 0x91, 
+    0x04, 0x30, 0xe0, 0x05, 0xda, 0xb8, 0x02, 0x02, 0x39, 0x30, 0xe1, 0x05, 0xda, 0xb8, 0x02, 0x01, 
+    0xf5, 0x30, 0xe6, 0x05, 0x12, 0x04, 0x03, 0x80, 0xd5, 0x30, 0xe2, 0x05, 0xda, 0xb8, 0x02, 0x00, 
+    0x80, 0x80, 0xcb, 0xda, 0xb8, 0x32, 
+
+// Segment #14, EXCLUDED Start Address 00ff31d7, Length 1
+
+
+// Segment #15, Start Address 00ff0296, Length 2090
+0xff,0x00,0x96,0x02,0x2a,0x08,
+    0xe4, 0x7a, 0xb3, 0x3f, 0xf1, 0x02, 0x03, 0x41, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, 
+    0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 
+    0x7e, 0xb3, 0x01, 0x2e, 0xb4, 0x00, 0x02, 0x80, 0x1c, 0xb4, 0x01, 0x19, 0x7e, 0xb3, 0x91, 0x14, 
+    0x54, 0x14, 0x68, 0x05, 0x12, 0x03, 0x05, 0x80, 0x23, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x1c, 
+    0x12, 0x04, 0x43, 0x80, 0x17, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x05, 0x12, 0x04, 0x43, 0x80, 
+    0x0b, 0x7e, 0xb3, 0x91, 0x14, 0x54, 0x14, 0x68, 0x03, 0x12, 0x03, 0x05, 0xda, 0xeb, 0xda, 0x7b, 
+    0xda, 0x6b, 0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x20, 
+    0xe4, 0x19, 0x75, 0x08, 0x0a, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x2d, 0x70, 0x0a, 0x7e, 0xb3, 
+    0x01, 0x2e, 0xb4, 0x01, 0x1f, 0x02, 0x03, 0x9d, 0x02, 0x09, 0x8b, 0x75, 0x08, 0x0b, 0x12, 0x0a, 
+    0xc0, 0x74, 0x14, 0x7a, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 0x01, 0x2e, 0xb4, 0x02, 0x0c, 0x12, 0x03, 
+    0x4d, 0x02, 0x03, 0x41, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0x7e, 0x00, 0x00, 0x7a, 0x03, 
+    0x01, 0x2e, 0x7a, 0x03, 0x01, 0x2f, 0x22, 0x7e, 0xb3, 0x01, 0x25, 0x54, 0x60, 0x60, 0x05, 0xb4, 
+    0x40, 0x1e, 0x80, 0x1c, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x05, 0x15, 0x75, 0x08, 0x71, 0x12, 0x0a, 
+    0xc0, 0x7e, 0xb3, 0x01, 0x28, 0x7e, 0xa0, 0x01, 0x7a, 0xa3, 0x91, 0x06, 0x7a, 0xb3, 0x91, 0x07, 
+    0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x12, 0x22, 0xbe, 0x57, 
+    0x01, 0x2b, 0x28, 0x04, 0x7e, 0x57, 0x01, 0x2b, 0x7a, 0x0f, 0x01, 0x31, 0x7a, 0x57, 0x01, 0x35, 
+    0x74, 0x10, 0x7a, 0xb3, 0x91, 0x12, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 
+    0x1a, 0x70, 0x53, 0x7e, 0xb3, 0x91, 0x14, 0x20, 0xe4, 0x4c, 0x7e, 0xef, 0x01, 0x31, 0x7e, 0xf7, 
+    0x01, 0x35, 0x7e, 0x07, 0x01, 0x35, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0xe0, 0x7a, 0xb3, 
+    0x91, 0x17, 0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x06, 0xa5, 0xb8, 0x10, 0xf0, 0x80, 0x19, 0x7e, 
+    0xb0, 0x00, 0x7a, 0xb3, 0x01, 0x2e, 0xbe, 0x00, 0x10, 0x68, 0x0d, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 
+    0x01, 0x2e, 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x7a, 0xef, 0x01, 0x31, 0x7a, 0xf7, 0x01, 0x35, 
+    0x75, 0x08, 0x06, 0x12, 0x0a, 0xc0, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xca, 0x0b, 0xca, 
+    0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x75, 
+    0x08, 0x03, 0x12, 0x0a, 0xc0, 0x74, 0x00, 0x7a, 0xb3, 0x01, 0x2d, 0x74, 0x00, 0x7a, 0xb3, 0x91, 
+    0x00, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x12, 0x04, 0xb2, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 
+    0xda, 0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x08, 0x03, 
+    0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x2f, 0xb4, 0x02, 0x11, 0x74, 0x00, 0x7a, 0xb3, 0x01, 0x2f, 
+    0x7a, 0xb3, 0x01, 0x2e, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xb4, 0x01, 0x46, 0x7e, 0xb3, 
+    0x91, 0x04, 0x20, 0xe6, 0x42, 0x7e, 0x23, 0x91, 0x1a, 0x7c, 0x32, 0x7e, 0x13, 0x01, 0x30, 0x2c, 
+    0x21, 0x7a, 0x23, 0x01, 0x30, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x01, 0x37, 0x7e, 0xb3, 0x91, 0x16, 
+    0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf4, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x75, 0x08, 
+    0x70, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x30, 0x7e, 0xa3, 0x01, 0x2c, 0xbc, 0xab, 0x78, 0x03, 
+    0x12, 0x05, 0x52, 0x22, 0x02, 0x09, 0x8b, 0xda, 0x59, 0x02, 0x04, 0x15, 0x74, 0xe0, 0x7a, 0xb3, 
+    0x91, 0x00, 0x7e, 0x03, 0x91, 0x10, 0x7e, 0x13, 0x91, 0x11, 0x7e, 0x33, 0x91, 0x12, 0x7e, 0x23, 
+    0x91, 0x13, 0x7e, 0x53, 0x91, 0x14, 0x7e, 0x43, 0x91, 0x15, 0x7e, 0x73, 0x91, 0x16, 0x7e, 0x63, 
+    0x91, 0x17, 0x7a, 0x0f, 0x01, 0x25, 0x7a, 0x1f, 0x01, 0x29, 0x75, 0x08, 0x04, 0x12, 0x0a, 0xc0, 
+    0x7a, 0x01, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x11, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x21, 0x08, 0x12, 
+    0x0a, 0xc0, 0x7a, 0x31, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x41, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x51, 
+    0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x61, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x71, 0x08, 0x12, 0x0a, 0xc0, 
+    0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x04, 0x12, 0x05, 0x26, 0x22, 
+    0x6d, 0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x01, 0x35, 0x7a, 0x03, 0x01, 0x30, 0x7e, 0xb3, 
+    0x01, 0x25, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x01, 0x2f, 0x7a, 0x33, 0x01, 0x2e, 0xbe, 0x07, 0x01, 
+    0x2b, 0x68, 0x09, 0x22, 0x7a, 0x33, 0x01, 0x2f, 0x7a, 0x23, 0x01, 0x2e, 0x7e, 0xb3, 0x01, 0x25, 
+    0x54, 0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 
+    0x06, 0x30, 0xe4, 0x03, 0x02, 0x09, 0x8b, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 
+    0xf0, 0x90, 0x05, 0x7e, 0x75, 0x84, 0xff, 0x73, 0x02, 0x07, 0x39, 0x02, 0x05, 0xc6, 0x02, 0x07, 
+    0xd2, 0x02, 0x07, 0xed, 0x02, 0x06, 0xd0, 0x02, 0x06, 0x5b, 0x02, 0x08, 0x1e, 0x02, 0x08, 0x1e, 
+    0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 
+    0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x21, 0x02, 0x08, 0x27, 0x02, 0x08, 0xf9, 0x02, 0x08, 
+    0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 0x02, 0x08, 0x24, 
+    0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x01, 0x26, 
+    0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x01, 0x27, 0x60, 0x79, 0x7c, 0x0b, 0x7e, 0x13, 0x01, 0x28, 0x7e, 
+    0x17, 0x01, 0x29, 0x75, 0x08, 0x72, 0x12, 0x0a, 0xc0, 0x7a, 0x01, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 
+    0x11, 0x08, 0x12, 0x0a, 0xc0, 0x12, 0x09, 0xd0, 0x40, 0x58, 0x02, 0x03, 0x84, 0xb4, 0x08, 0x1c, 
+    0x75, 0x08, 0x74, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x3f, 0xf1, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 
+    0x00, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x01, 0x02, 0x03, 0x84, 0xb4, 0x00, 0x33, 0x75, 
+    0x08, 0x75, 0x12, 0x0a, 0xc0, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7e, 
+    0xb3, 0x3f, 0xf2, 0x30, 0xe0, 0x07, 0x74, 0x02, 0x7a, 0x0b, 0xb0, 0x80, 0x05, 0x74, 0x00, 0x7a, 
+    0x0b, 0xb0, 0x0b, 0x14, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x02, 0xda, 0x0b, 0x02, 
+    0x03, 0x84, 0x02, 0x09, 0x8b, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 
+    0x1c, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x00, 0x5f, 0x75, 0x08, 0x76, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 
+    0x01, 0x2a, 0x54, 0x0f, 0xb4, 0x02, 0x05, 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 
+    0xb0, 0x00, 0x80, 0x0f, 0x7e, 0xb3, 0x01, 0x2a, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 
+    0x7e, 0xb0, 0x20, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x11, 0x30, 0xe0, 0x04, 0x74, 0x01, 
+    0x80, 0x02, 0x74, 0x00, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7a, 0x0b, 
+    0xb0, 0x0b, 0x14, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0x54, 
+    0x00, 0x02, 0xda, 0x0b, 0x02, 0x03, 0x84, 0x02, 0x09, 0x8b, 0x7e, 0xb3, 0x01, 0x2a, 0x54, 0x0f, 
+    0xb4, 0x02, 0x05, 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 0xb0, 0x00, 0x80, 0x0f, 
+    0x7e, 0xb3, 0x01, 0x2a, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 0x7e, 0xb0, 0x20, 0x7a, 
+    0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x01, 0x28, 0xb4, 0x00, 0x26, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x01, 
+    0x0e, 0x75, 0x08, 0x77, 0x12, 0x0a, 0xc0, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0x1b, 0xb4, 
+    0x03, 0x0e, 0x75, 0x08, 0x78, 0x12, 0x0a, 0xc0, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x11, 0x80, 0x0a, 
+    0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x12, 0x09, 0x8b, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 
+    0x02, 0x03, 0x77, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x09, 0x1f, 0x75, 0x08, 0x79, 0x12, 0x0a, 0xc0, 
+    0x7e, 0xb3, 0x01, 0x28, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x0d, 0xca, 0xb8, 0x12, 0x01, 0xf1, 0xda, 
+    0xb8, 0x50, 0x76, 0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x08, 0x7a, 0x12, 
+    0x0a, 0xc0, 0x80, 0x62, 0xb4, 0x03, 0x19, 0x75, 0x08, 0x7b, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 
+    0x28, 0xb4, 0x01, 0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 
+    0xb4, 0x01, 0x19, 0x75, 0x08, 0x7c, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x28, 0xb4, 0x01, 0x39, 
+    0x7e, 0xb3, 0x3f, 0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 
+    0xb3, 0x01, 0x27, 0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x01, 0x28, 0x7e, 0x17, 0x01, 0x29, 0x75, 
+    0x08, 0x73, 0x12, 0x0a, 0xc0, 0x7a, 0x01, 0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x11, 0x08, 0x12, 0x0a, 
+    0xc0, 0x12, 0x0a, 0x0a, 0x40, 0x03, 0x02, 0x03, 0x77, 0x02, 0x09, 0x8b, 0x7e, 0xb3, 0x01, 0x26, 
+    0xb4, 0x0b, 0xf6, 0x75, 0x08, 0x7d, 0x12, 0x0a, 0xc0, 0x7e, 0xb3, 0x01, 0x28, 0x7e, 0xa3, 0x01, 
+    0x2a, 0x4c, 0xab, 0x78, 0xe4, 0x80, 0xdf, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 
+    0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x0a, 0xcf, 0x75, 0x08, 0x7e, 0x12, 0x0a, 0xc0, 
+    0x7e, 0xb3, 0x01, 0x28, 0x70, 0xc3, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0x7a, 0x0b, 
+    0xb0, 0x7e, 0x54, 0x00, 0x01, 0x02, 0x03, 0x84, 0x02, 0x09, 0x8b, 0x02, 0x09, 0x8b, 0x02, 0x09, 
+    0x8b, 0x7e, 0xb3, 0x01, 0x26, 0xb4, 0x04, 0x20, 0x75, 0x08, 0xc3, 0x12, 0x0a, 0xc0, 0x7e, 0x04, 
+    0x00, 0x01, 0x7e, 0x17, 0x01, 0x27, 0x7e, 0x18, 0x01, 0x37, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 
+    0x01, 0x2b, 0x12, 0x0a, 0xcc, 0x02, 0x08, 0xf3, 0xb4, 0x06, 0x42, 0x75, 0x08, 0xc1, 0x12, 0x0a, 
+    0xc0, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x01, 0x27, 0x7e, 
+    0x78, 0x01, 0x37, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x2b, 0x75, 0x08, 0xc1, 0x12, 0x0a, 
+    0xc0, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x0b, 0x63, 0x7e, 
+    0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0x40, 0x65, 0x80, 0x60, 0xb4, 0x00, 0x24, 
+    0xc2, 0xaf, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x01, 0x24, 0x12, 0x03, 0x77, 
+    0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 
+    0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x20, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0x23, 0x91, 
+    0x07, 0x7e, 0x57, 0x01, 0x27, 0x4d, 0x55, 0x68, 0x05, 0x4e, 0x20, 0x02, 0x80, 0x03, 0x5e, 0x20, 
+    0xfd, 0x7a, 0x23, 0x91, 0x07, 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x01, 0x29, 
+    0x7e, 0x17, 0x01, 0x27, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x03, 0x77, 
+    0x02, 0x09, 0x8b, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 
+    0xb3, 0x01, 0x26, 0xb4, 0x03, 0x15, 0x75, 0x08, 0xc2, 0x12, 0x0a, 0xc0, 0x7e, 0x04, 0x00, 0x01, 
+    0x7e, 0x17, 0x01, 0x27, 0x7e, 0x57, 0x01, 0x2b, 0x02, 0x03, 0x84, 0xb4, 0x05, 0x41, 0x75, 0x08, 
+    0xc0, 0x12, 0x0a, 0xc0, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x7e, 
+    0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x01, 0x27, 0x7e, 
+    0x47, 0x01, 0x2b, 0x12, 0x0a, 0xcc, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 
+    0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x01, 0x2b, 0x02, 0x03, 0x84, 0xb4, 
+    0x01, 0x20, 0x7e, 0x00, 0x00, 0x7e, 0x10, 0x01, 0x75, 0x08, 0x72, 0x12, 0x0a, 0xc0, 0x7a, 0x01, 
+    0x08, 0x12, 0x0a, 0xc0, 0x7a, 0x11, 0x08, 0x12, 0x0a, 0xc0, 0x12, 0x09, 0xd0, 0x40, 0x03, 0x02, 
+    0x03, 0x84, 0x02, 0x09, 0x8b, 0x75, 0x08, 0x07, 0x12, 0x0a, 0xc0, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 
+    0x90, 0x00, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x15, 0x74, 0x01, 
+    0x7a, 0xb3, 0x91, 0x11, 0x7e, 0xb3, 0x91, 0x15, 0x54, 0x60, 0xbe, 0xb0, 0x40, 0x68, 0x08, 0x74, 
+    0x20, 0x7a, 0xb3, 0x91, 0x15, 0x80, 0xed, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x04, 0x7a, 
+    0xb3, 0x91, 0x14, 0x74, 0xff, 0x7a, 0xb3, 0x01, 0x2d, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 
+    0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x0a, 0x57, 0x40, 0x1f, 0x7e, 0x08, 0x01, 0x37, 0x7a, 0x0c, 
+    0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x0a, 0xcc, 0xda, 0x59, 0xda, 0x0b, 0x7e, 0x43, 0x01, 
+    0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0xc3, 0x22, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 
+    0x00, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 
+    0x0a, 0x57, 0x40, 0x31, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 
+    0x01, 0x37, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x01, 0x2b, 0xbd, 0x74, 0x78, 0x17, 0x75, 0x08, 
+    0xc1, 0x12, 0x0a, 0xc0, 0x12, 0x0b, 0x63, 0x40, 0x0c, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 
+    0x00, 0xd0, 0xa8, 0xc3, 0x22, 0x7e, 0x43, 0x01, 0x24, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0xd3, 
+    0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 
+    0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0x03, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 
+    0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 
+    0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 
+    0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 
+    0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 
+    0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, 
+
+// Segment #16, EXCLUDED Start Address 00ff7c00, Length 227
+
+
+// Segment #17, EXCLUDED Start Address 00ff7f00, Length 192
+
+
+// Segment #17, Start Address 00ff7fc0, Length 64
+0xff,0x00,0xc0,0x7f,0x40,0x00,
+    0x40, 0x01, 0x02, 0x00, 0xd7, 0x31, 0x02, 0x00, 0x03, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x01, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+
+// Segment #18, Start Address 00ff0ac0, Length 4163
+0xff,0x00,0xc0,0x0a,0x43,0x10,
+    0xca, 0x08, 0x7e, 0x01, 0x08, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x80, 0x50, 0x0b, 0x1a, 
+    0x60, 0x0b, 0x35, 0x0b, 0x1a, 0x70, 0x0b, 0x35, 0x0b, 0x1a, 0x80, 0x0b, 0x35, 0x0b, 0x1a, 0x90, 
+    0x0b, 0x35, 0x0b, 0x1a, 0xa0, 0x0b, 0x35, 0x0b, 0x1a, 0xb0, 0x0b, 0x35, 0x0b, 0x1a, 0xc0, 0x0b, 
+    0x35, 0x0b, 0x1a, 0xd0, 0x0b, 0x35, 0x1b, 0x0a, 0x60, 0x0b, 0x15, 0x1b, 0x0a, 0x70, 0x0b, 0x15, 
+    0x1b, 0x0a, 0x80, 0x0b, 0x15, 0x1b, 0x0a, 0x90, 0x0b, 0x15, 0x1b, 0x0a, 0xa0, 0x0b, 0x15, 0x1b, 
+    0x0a, 0xb0, 0x0b, 0x15, 0x1b, 0x0a, 0xc0, 0x0b, 0x15, 0x1b, 0x0a, 0xd0, 0x0b, 0x15, 0x9e, 0x44, 
+    0x00, 0x10, 0x50, 0xaa, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x0e, 0x7e, 0x1b, 0xc0, 0x7a, 0x0b, 0xc0, 
+    0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 0xfc, 0x7c, 
+    0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 0x44, 0x00, 
+    0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 0xfa, 0x7f, 
+    0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, 0x40, 0x9d, 
+    0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x0b, 0x8d, 0xda, 0x79, 
+    0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x7e, 0xc0, 0x03, 
+    0x7e, 0xd0, 0x00, 0x7a, 0xd3, 0x90, 0x00, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 
+    0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 
+    0x06, 0x2d, 0x70, 0x7d, 0x07, 0x6d, 0x77, 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 0x00, 0x0b, 
+    0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 0xf3, 0x7f, 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x1b, 
+    0x10, 0xbc, 0x10, 0x68, 0x06, 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2f, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 
+    0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 
+    0x19, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x06, 0x6c, 0xdc, 0x7a, 
+    0xd3, 0x90, 0x00, 0x4d, 0x77, 0x78, 0x90, 0xc2, 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 
+    0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 
+    0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 0xff, 0x0b, 
+    0x1a, 0x00, 0x5e, 0x10, 0x1f, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 0x51, 0x23, 0x7e, 0x18, 0x0c, 
+    0x0d, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, 0xa5, 0xb8, 0x02, 0x03, 
+    0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 0x7e, 0xe8, 0x7f, 0xbf, 0x7a, 0xec, 0x00, 0xff, 0xe0, 0xf5, 
+    0x23, 0x54, 0xc0, 0x68, 0x38, 0x7e, 0xe8, 0x7f, 0xbe, 0x7a, 0xec, 0x00, 0xff, 0xe0, 0x60, 0x2e, 
+    0x12, 0x0c, 0x37, 0xf5, 0x21, 0x7a, 0xa1, 0x20, 0x20, 0x09, 0x0c, 0x20, 0x0a, 0x12, 0x7e, 0xb0, 
+    0x0e, 0x7a, 0xb3, 0x92, 0x00, 0x80, 0x10, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x92, 0x00, 0x80, 0x07, 
+    0x7e, 0xb0, 0x0a, 0x7a, 0xb3, 0x92, 0x00, 0x7a, 0xb1, 0x0d, 0x02, 0x0c, 0xc4, 0x22, 0x7e, 0xb0, 
+    0x02, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x03, 0x7a, 0xb3, 0x90, 0x00, 0x12, 
+    0x19, 0x0c, 0x80, 0xea, 0xc2, 0xaf, 0xc2, 0x11, 0xc2, 0x12, 0x75, 0xb0, 0xdf, 0x7e, 0x00, 0x01, 
+    0x7a, 0x03, 0x93, 0x00, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x90, 0x00, 0x6c, 0x00, 0x7e, 0x10, 0x03, 
+    0x12, 0x0c, 0xf5, 0x7e, 0x68, 0x2c, 0x66, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 
+    0x80, 0x32, 0x02, 0x1a, 0x6e, 0x20, 0x11, 0x2b, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x90, 0x00, 0x12, 
+    0x19, 0x0c, 0x7e, 0xb0, 0x03, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x02, 0x7a, 
+    0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0xa5, 0xd9, 0xdc, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, 
+    0x12, 0x19, 0x0c, 0x22, 0x7e, 0x68, 0x2c, 0xf9, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 
+    0xe4, 0x10, 0x00, 0x7e, 0x40, 0x55, 0x7a, 0xe9, 0x40, 0x0b, 0xe4, 0x7e, 0x50, 0xaa, 0x7a, 0xe9, 
+    0x50, 0x1b, 0xe4, 0xbe, 0xe9, 0x40, 0x68, 0x19, 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x13, 0x7a, 0xe9, 0x40, 0x7e, 0xe9, 0x10, 0x80, 
+    0xf8, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x7e, 0x68, 
+    0x2d, 0x3d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x78, 0x00, 0x00, 0x7e, 0x70, 0x0e, 
+    0x7e, 0xa4, 0xff, 0xff, 0x7e, 0xb4, 0xbf, 0xff, 0x7d, 0xcb, 0x0e, 0xc4, 0x7d, 0xdc, 0x5d, 0xdb, 
+    0x6c, 0xbb, 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfb, 0x5e, 
+    0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 
+    0xb0, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x6c, 0xbb, 0x7d, 0xfa, 
+    0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x41, 0x0b, 0xb0, 0x7d, 0xfb, 0x5e, 0xf4, 0x7f, 
+    0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x34, 0x0b, 0xb0, 0x7d, 0xfc, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 
+    0xb0, 0x78, 0x27, 0x0b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0xbe, 0x7b, 0xb0, 0x78, 0x1a, 
+    0x0b, 0xb0, 0xbe, 0xc4, 0xff, 0xfe, 0x78, 0x92, 0x0e, 0xb4, 0xa5, 0xdf, 0x8b, 0x7e, 0x68, 0x2c, 
+    0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x77, 0xca, 0x5b, 0xca, 0x6b, 0x7e, 0x68, 
+    0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2d, 0x8f, 0x7a, 0x6c, 0x00, 
+    0xff, 0x12, 0x19, 0xc4, 0x0a, 0x47, 0x12, 0x19, 0xfa, 0x7e, 0x68, 0x2d, 0xde, 0x7a, 0x6c, 0x00, 
+    0xff, 0x12, 0x19, 0xc4, 0x6c, 0x77, 0xda, 0x6b, 0xca, 0x6b, 0x0b, 0x70, 0x0e, 0xc4, 0xbe, 0xc4, 
+    0xff, 0xff, 0x78, 0xf6, 0x1b, 0x70, 0x0a, 0x47, 0x12, 0x19, 0xfa, 0x12, 0x19, 0x19, 0x30, 0x11, 
+    0x30, 0xda, 0x6b, 0xda, 0x5b, 0x6c, 0xbb, 0x7e, 0x78, 0x00, 0x00, 0x7d, 0xfa, 0x5e, 0xf4, 0x7f, 
+    0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfb, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfc, 0x5e, 
+    0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x7d, 0xfd, 0x5e, 0xf4, 0x7f, 0xff, 0x7a, 0x7b, 0xb0, 0x80, 
+    0xd4, 0x7e, 0x68, 0x2d, 0x1b, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x30, 0x1f, 0x0e, 0x7e, 
+    0x78, 0x04, 0x20, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x44, 0x7b, 0xe0, 0x80, 0x0c, 0x7e, 0x78, 0x00, 
+    0x00, 0x7a, 0x7c, 0x00, 0x01, 0x7e, 0x44, 0x80, 0x00, 0x0b, 0x00, 0x7e, 0x40, 0x3a, 0x7c, 0x54, 
+    0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 0x7a, 0x5b, 0x50, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 0xde, 0x02, 
+    0x0b, 0x50, 0x1b, 0x84, 0x78, 0xf0, 0x7c, 0x54, 0x7f, 0x57, 0x7d, 0x84, 0x6c, 0x66, 0xbe, 0x5b, 
+    0x50, 0x78, 0x1a, 0x0b, 0x5c, 0x0b, 0x50, 0xa5, 0xde, 0x02, 0x0b, 0x50, 0x1b, 0x84, 0x78, 0xee, 
+    0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x4b, 0x7f, 0x45, 0x7e, 
+    0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2d, 0x5f, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x19, 0xc4, 0x7d, 0x4b, 0x12, 0x19, 0xfa, 0x7e, 0x68, 0x2d, 0x74, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x19, 0xc4, 0x6c, 0x88, 0x7c, 0x95, 0x12, 0x19, 0xfa, 0x7e, 0x68, 0x2d, 0x82, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x4b, 0x90, 0x12, 0x19, 0xfa, 0x12, 0x19, 0x19, 
+    0x30, 0x11, 0x05, 0x7e, 0x4b, 0x90, 0x80, 0xfb, 0x7e, 0x68, 0x2e, 0x28, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x19, 0xc4, 0x0b, 0x00, 0x7e, 0xb0, 0x80, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xa0, 0x55, 0x7a, 
+    0xa3, 0x91, 0x10, 0x7e, 0xb3, 0x91, 0x07, 0x7e, 0xb3, 0x91, 0x10, 0xbc, 0xab, 0x78, 0x20, 0x7e, 
+    0xa0, 0xaa, 0x7a, 0xa3, 0x91, 0x10, 0x7e, 0xb3, 0x91, 0x07, 0x7e, 0xb3, 0x91, 0x10, 0xbc, 0xab, 
+    0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x1b, 0x7e, 
+    0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x0a, 
+    0x7a, 0xa3, 0x91, 0x10, 0x7e, 0xb3, 0x91, 0x10, 0x80, 0xf6, 0x7e, 0x68, 0x2e, 0x4a, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x12, 0x31, 0x0b, 0x00, 0x7e, 0xe4, 0x10, 0x00, 0x7e, 0xa0, 
+    0xa5, 0xca, 0xa8, 0x7a, 0xe9, 0xa0, 0x7e, 0xb0, 0x30, 0x7a, 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xa0, 
+    0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x95, 0x00, 0x12, 0x19, 0x0c, 0x0b, 0xe5, 0x7e, 0xb0, 0x20, 0x7a, 
+    0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xb0, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xb0, 
+    0xda, 0xa8, 0xbc, 0xab, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 
+    0xc4, 0x80, 0x1d, 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 
+    0x19, 0x30, 0x11, 0x0c, 0x7e, 0xb0, 0x38, 0x7a, 0xb3, 0x95, 0x00, 0x7e, 0xe9, 0xb0, 0x80, 0xfb, 
+    0x80, 0x00, 0x7e, 0x68, 0x2d, 0xe4, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x75, 
+    0xb0, 0xdf, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 0x08, 0xbe, 0xb0, 0x01, 0x78, 0x0b, 0x09, 
+    0xb2, 0x00, 0x14, 0xbe, 0xb0, 0x60, 0x78, 0x02, 0x80, 0x17, 0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x11, 0x09, 0xb2, 0x00, 0x08, 0x80, 
+    0xfa, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2e, 0x06, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x0b, 0x00, 0x75, 0xb0, 0xef, 0x12, 0x18, 0xff, 0x7e, 
+    0x24, 0x80, 0x00, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x1c, 0x7e, 0xb0, 0x01, 0x19, 0xb2, 0x00, 
+    0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x37, 0x09, 0xb2, 0x00, 0x08, 0x5e, 0xb0, 0xc0, 
+    0xbe, 0xb0, 0xc0, 0x78, 0x2b, 0x7e, 0xa0, 0xaa, 0x19, 0xa2, 0x00, 0x1c, 0x6c, 0xbb, 0x19, 0xb2, 
+    0x00, 0x08, 0x09, 0xb2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x16, 0x09, 0xb2, 0x00, 0x08, 0x5e, 0xb0, 
+    0xc0, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xda, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x1b, 
+    0x7e, 0x68, 0x2c, 0xdf, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 
+    0x0a, 0x19, 0xa2, 0x00, 0x1c, 0x09, 0xb2, 0x00, 0x1c, 0x80, 0xf6, 0x7e, 0x68, 0x2e, 0x6c, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x2e, 0xee, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 
+    0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x7e, 0xb0, 0x01, 0x19, 0xb2, 0x00, 0x1c, 0x2e, 
+    0x24, 0x01, 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xf3, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x7e, 
+    0xb0, 0x01, 0x0b, 0x00, 0x09, 0xa2, 0x00, 0x1c, 0xbc, 0xab, 0x78, 0x16, 0x7e, 0x68, 0x2c, 0xe7, 
+    0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0x0b, 0xb0, 0xa5, 0xd9, 0xe2, 
+    0x80, 0x25, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 
+    0x30, 0x11, 0xe4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x09, 0xa2, 0x00, 0x1c, 0x2e, 0x24, 
+    0x01, 0x00, 0xa5, 0xd9, 0xf5, 0x80, 0xec, 0x7e, 0x68, 0x2f, 0x12, 0x7a, 0x6c, 0x00, 0xff, 0x12, 
+    0x19, 0xc4, 0x12, 0x12, 0x31, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x74, 0x10, 
+    0x19, 0xb2, 0x00, 0x10, 0x12, 0x11, 0xaa, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xee, 0x7e, 0x68, 
+    0x2f, 0x36, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 
+    0x0b, 0x00, 0xe4, 0x19, 0xb2, 0x00, 0x10, 0x12, 0x11, 0xaa, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 
+    0xef, 0x30, 0x00, 0x03, 0x02, 0x17, 0x3b, 0x02, 0x12, 0x6a, 0x74, 0x07, 0x19, 0xb2, 0x00, 0x08, 
+    0x12, 0x19, 0x0c, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 
+    0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 0xb2, 0x00, 0x14, 0x09, 0xb2, 0x00, 0x00, 0x09, 
+    0xb2, 0x00, 0x14, 0xc2, 0x13, 0x7e, 0xb0, 0x55, 0x12, 0x12, 0x0b, 0x7e, 0xb0, 0xaa, 0x12, 0x12, 
+    0x0b, 0x7e, 0xb0, 0x00, 0x12, 0x12, 0x0b, 0x7e, 0xb0, 0xff, 0x12, 0x12, 0x0b, 0x30, 0x13, 0x0f, 
+    0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x22, 0x7e, 
+    0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x22, 0x19, 0xb2, 0x00, 0x00, 0x12, 
+    0x18, 0xff, 0x09, 0xa2, 0x00, 0x00, 0xbc, 0xab, 0x78, 0x01, 0x22, 0x20, 0x11, 0x03, 0xd2, 0x13, 
+    0x22, 0x12, 0x19, 0x19, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x09, 0xa2, 0x00, 0x00, 0x80, 
+    0xf3, 0x75, 0xb0, 0xdf, 0x12, 0x18, 0xff, 0x75, 0xb0, 0xef, 0x12, 0x18, 0xff, 0x7e, 0x24, 0x80, 
+    0x00, 0x7e, 0x11, 0x21, 0x74, 0x80, 0x19, 0xb2, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x02, 0x19, 0xa2, 
+    0x00, 0x04, 0x19, 0xb2, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb2, 0x00, 0x0c, 0x74, 0x06, 0x19, 0xb2, 
+    0x00, 0x08, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xdb, 0x22, 0x7e, 0x68, 0x2f, 0x5a, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x12, 0x18, 
+    0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x09, 
+    0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x19, 0xc4, 0x80, 0x1a, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 
+    0x12, 0x19, 0x19, 0x30, 0x11, 0x09, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x80, 0xf7, 0x2e, 
+    0x24, 0x01, 0x00, 0xa5, 0xd9, 0xb6, 0x7e, 0x68, 0x2f, 0x7e, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 
+    0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 
+    0x18, 0x7e, 0xa0, 0x55, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 
+    0xb0, 0x0a, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 
+    0x1a, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 
+    0x11, 0x09, 0x19, 0xa2, 0x00, 0x00, 0x12, 0x18, 0xff, 0x80, 0xf7, 0x2e, 0x24, 0x01, 0x00, 0xa5, 
+    0xd9, 0xb6, 0x30, 0x04, 0x03, 0x02, 0x15, 0x9f, 0x7e, 0x68, 0x2f, 0xa2, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 
+    0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 
+    0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 
+    0x78, 0x3c, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 
+    0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 
+    0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x0a, 0x78, 0x14, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 
+    0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 
+    0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 
+    0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 
+    0x2f, 0xea, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 
+    0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 
+    0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 
+    0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x3c, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 
+    0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x02, 
+    0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x05, 0x78, 0x14, 
+    0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0xa5, 
+    0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 
+    0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 
+    0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x30, 0x32, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 
+    0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 
+    0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0xbe, 0xb0, 0x50, 0x78, 0x1f, 0x6c, 0xaa, 
+    0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x50, 0x78, 0x0d, 
+    0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 0x20, 0x7e, 0x68, 0x2c, 
+    0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0x0f, 0x7e, 0xa0, 
+    0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 
+    0x00, 0xa5, 0xd9, 0xa2, 0x7e, 0x68, 0x30, 0x7a, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 
+    0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 0x19, 
+    0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0xa0, 0xbe, 0xb0, 0xa0, 
+    0x78, 0x1f, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 
+    0xb0, 0xa0, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x80, 
+    0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 
+    0x11, 0x0f, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 
+    0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x7e, 0x68, 0x30, 0x9e, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x20, 0xb1, 0x26, 0x7e, 
+    0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x30, 0xb1, 0x19, 0x6c, 0xaa, 0x19, 0xa2, 
+    0x00, 0x10, 0x12, 0x18, 0xff, 0x20, 0xb1, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 
+    0x12, 0x19, 0xc4, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 
+    0x12, 0x19, 0x19, 0x30, 0x11, 0x0f, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 
+    0xa2, 0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xae, 0x02, 0x17, 0x3b, 0x7e, 
+    0x68, 0x2f, 0xc6, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 
+    0x21, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 
+    0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 
+    0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x06, 0x78, 0x3c, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 
+    0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 
+    0x01, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x06, 0x78, 
+    0x14, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 
+    0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 
+    0x12, 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 
+    0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x30, 0x0e, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 
+    0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 
+    0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x01, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 
+    0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 0x3c, 0x7e, 
+    0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x7e, 0xa0, 0x03, 
+    0x19, 0xa2, 0x00, 0x10, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 
+    0x00, 0x18, 0x5e, 0xb0, 0x09, 0x78, 0x14, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 
+    0x19, 0xc4, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0x9e, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 0x19, 0x19, 0x30, 0x11, 0xe6, 0x7e, 0xa0, 0x01, 0x19, 
+    0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x80, 0xf1, 0x7e, 0x68, 0x30, 0x56, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x7e, 
+    0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 0x00, 0x18, 0x5e, 0xb0, 0x90, 
+    0xbe, 0xb0, 0x90, 0x78, 0x1f, 0x6c, 0xaa, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x09, 0xb2, 
+    0x00, 0x18, 0x5e, 0xb0, 0x90, 0x78, 0x0d, 0x7e, 0x68, 0x2c, 0xe7, 0x7a, 0x6c, 0x00, 0xff, 0x12, 
+    0x19, 0xc4, 0x80, 0x20, 0x7e, 0x68, 0x2c, 0xf0, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x12, 
+    0x19, 0x19, 0x30, 0x11, 0x0f, 0x7e, 0xa0, 0x02, 0x19, 0xa2, 0x00, 0x10, 0x6c, 0xaa, 0x19, 0xa2, 
+    0x00, 0x10, 0x80, 0xf1, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xa2, 0x20, 0x1f, 0x68, 0x12, 0x12, 
+    0x31, 0x12, 0x17, 0xa9, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 0x0b, 0x00, 0x20, 0x89, 0x26, 
+    0x7e, 0xa0, 0xff, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x18, 0xff, 0x7e, 0xb0, 0x55, 0x19, 0xb2, 0x00, 
+    0x00, 0x12, 0x18, 0xff, 0x30, 0x89, 0x0f, 0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x18, 
+    0xff, 0x20, 0x89, 0x02, 0x80, 0x26, 0x12, 0x19, 0x19, 0x30, 0x11, 0x20, 0x7e, 0xa0, 0xff, 0x19, 
+    0xa2, 0x00, 0x04, 0x12, 0x18, 0xff, 0x7e, 0xb0, 0x55, 0x19, 0xb2, 0x00, 0x00, 0x12, 0x18, 0xff, 
+    0x7e, 0xa0, 0x00, 0x19, 0xa2, 0x00, 0x04, 0x12, 0x18, 0xff, 0x80, 0xe0, 0x2e, 0x24, 0x01, 0x00, 
+    0xa5, 0xd9, 0xa8, 0x02, 0x17, 0xc2, 0x02, 0x18, 0x4c, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x21, 
+    0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 0x10, 0x12, 0x18, 0xff, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 
+    0xef, 0x22, 0x30, 0x1f, 0x03, 0x02, 0x18, 0x4c, 0xc2, 0x8a, 0x12, 0x17, 0xa9, 0x0b, 0x00, 0x12, 
+    0x18, 0x16, 0x20, 0x8b, 0x24, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x02, 0x7a, 0xb3, 0x91, 
+    0x07, 0x74, 0x0c, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x07, 0x12, 0x19, 0x0c, 
+    0x30, 0x8b, 0x06, 0x12, 0x18, 0x16, 0x30, 0x8b, 0xad, 0x12, 0x19, 0x19, 0x30, 0x11, 0xa7, 0x12, 
+    0x18, 0x16, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x07, 0x12, 0x19, 
+    0x0c, 0x12, 0x18, 0x16, 0x80, 0xe9, 0x7e, 0xa0, 0x00, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 0x7a, 
+    0xa3, 0x91, 0x07, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7a, 0xa3, 0x91, 0x07, 0x12, 0x18, 0xff, 
+    0x74, 0xef, 0x7a, 0xb3, 0x91, 0x04, 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x03, 0x74, 0x0c, 0x7a, 0xb3, 
+    0x91, 0x06, 0x74, 0x08, 0x7a, 0xb3, 0x91, 0x07, 0x12, 0x19, 0x0c, 0x22, 0x30, 0x12, 0x19, 0x7e, 
+    0x68, 0x30, 0xc2, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0xd2, 0x11, 0x12, 0x18, 0xff, 0x12, 
+    0x18, 0xff, 0x12, 0x18, 0xff, 0x02, 0x0c, 0xca, 0x30, 0x1f, 0x1c, 0x7e, 0x68, 0x31, 0x3c, 0x7a, 
+    0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x7e, 0x68, 0x31, 0x5e, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 
+    0xc4, 0x12, 0x1a, 0x6e, 0x02, 0x18, 0xf7, 0x0b, 0x00, 0x7e, 0x78, 0x18, 0xb1, 0x7a, 0x7c, 0x00, 
+    0xff, 0x7f, 0x67, 0x7a, 0x6c, 0x00, 0x00, 0x7e, 0x70, 0x3e, 0x7e, 0x7b, 0xb0, 0x7a, 0x6b, 0xb0, 
+    0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xdf, 0xf3, 0x7e, 0x78, 0x18, 0xb1, 0x7a, 0x7c, 0x00, 0x00, 0x89, 
+    0x78, 0x7e, 0x78, 0x00, 0x00, 0x7a, 0x7c, 0x00, 0xfe, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 
+    0xfe, 0x74, 0xaa, 0x39, 0xb7, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb7, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 
+    0xb7, 0x55, 0x55, 0x6c, 0x99, 0x7a, 0x6b, 0x90, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x6b, 0x80, 0xbc, 
+    0x89, 0x68, 0x08, 0x1b, 0x54, 0x78, 0xf5, 0x8a, 0xff, 0x18, 0xef, 0x8a, 0xff, 0x18, 0xf7, 0x12, 
+    0x19, 0x19, 0x7e, 0x6b, 0x80, 0x80, 0xfb, 0x7e, 0x10, 0xff, 0x12, 0x19, 0xac, 0x80, 0xf8, 0xca, 
+    0xf9, 0x7e, 0xf4, 0x00, 0xff, 0x1b, 0xf4, 0x78, 0xfc, 0xda, 0xf9, 0x22, 0xca, 0xf9, 0x7e, 0xf4, 
+    0x00, 0x00, 0x1b, 0xf4, 0x78, 0xfc, 0xda, 0xf9, 0x22, 0x20, 0x11, 0x20, 0xd2, 0x12, 0x12, 0x19, 
+    0x0c, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x12, 0x19, 
+    0x0c, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, 0x22, 0xca, 0x0b, 0x7e, 0x10, 
+    0x03, 0x7c, 0x30, 0x6c, 0x22, 0x0b, 0x20, 0x9e, 0x30, 0x0a, 0x50, 0xf9, 0x2e, 0x30, 0x0b, 0x1b, 
+    0x20, 0x68, 0x20, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x03, 0x7a, 0xb3, 0x90, 0x00, 
+    0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, 
+    0xa5, 0xda, 0xe0, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 0x1b, 0x30, 0x68, 0x20, 0x12, 0x19, 0x0c, 
+    0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x12, 0x19, 0x0c, 
+    0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x90, 0x00, 0xa5, 0xdb, 0xe0, 0x7e, 0x20, 0x0a, 
+    0x12, 0x19, 0x0c, 0xa5, 0xda, 0xfa, 0xa5, 0xd9, 0x98, 0xda, 0x0b, 0x22, 0x20, 0x11, 0x14, 0x12, 
+    0x19, 0x0c, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x90, 0x00, 0x12, 0x19, 0x0c, 0x7e, 0xb0, 0x00, 0x7a, 
+    0xb3, 0x90, 0x00, 0x22, 0x30, 0x1f, 0x32, 0x20, 0x11, 0x2f, 0xca, 0x2b, 0xca, 0x7b, 0x7e, 0x78, 
+    0x80, 0x00, 0x7a, 0x7c, 0x00, 0xfe, 0x12, 0x1a, 0x4d, 0x7e, 0x6b, 0xa0, 0x5c, 0xaa, 0x68, 0x10, 
+    0x29, 0xb7, 0x00, 0x14, 0x54, 0x60, 0x68, 0xf8, 0x39, 0xa7, 0x00, 0x00, 0x0b, 0x6c, 0x80, 0xe9, 
+    0x12, 0x18, 0xff, 0xd2, 0xb5, 0xda, 0x7b, 0xda, 0x2b, 0x22, 0x12, 0x1a, 0x05, 0x7e, 0x68, 0x00, 
+    0x0c, 0x12, 0x19, 0xc4, 0x22, 0xca, 0x59, 0xca, 0x5b, 0x7e, 0xb4, 0x00, 0x0c, 0x7c, 0xb8, 0xc4, 
+    0x12, 0x1a, 0x35, 0x7c, 0xb8, 0x12, 0x1a, 0x35, 0x7c, 0xb9, 0xc4, 0x12, 0x1a, 0x35, 0x7c, 0xb9, 
+    0x12, 0x1a, 0x35, 0x7e, 0xb0, 0x68, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x6c, 0xbb, 0x7a, 0xb9, 0xb0, 
+    0xda, 0x59, 0xda, 0x5b, 0x22, 0x5e, 0xb0, 0x0f, 0x7c, 0xab, 0x9e, 0xa0, 0x0a, 0x40, 0x05, 0x2e, 
+    0xb0, 0x37, 0x80, 0x03, 0x2e, 0xb0, 0x30, 0x7a, 0xb9, 0xb0, 0x0b, 0xb4, 0x22, 0xc2, 0xb5, 0x75, 
+    0xb0, 0xef, 0x12, 0x18, 0xff, 0x74, 0x80, 0x39, 0xb7, 0x00, 0x0c, 0x7e, 0x54, 0x00, 0x06, 0x39, 
+    0xa7, 0x00, 0x04, 0x39, 0xb7, 0x00, 0x00, 0x74, 0x03, 0x39, 0xb7, 0x00, 0x0c, 0x22, 0x7e, 0x78, 
+    0x00, 0x00, 0x7a, 0x7c, 0x00, 0xff, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0x01, 0x7f, 0x65, 
+    0x7e, 0x74, 0x20, 0x00, 0x12, 0x0b, 0x63, 0x40, 0x58, 0x7e, 0x78, 0x7c, 0x00, 0x7a, 0x7c, 0x00, 
+    0xff, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0x01, 0x7e, 0x68, 0x7c, 0x00, 0x7a, 0x6c, 0x00, 
+    0x01, 0x7e, 0x74, 0x04, 0x00, 0x12, 0x0b, 0x63, 0x40, 0x37, 0x74, 0x80, 0x12, 0x1a, 0xea, 0x40, 
+    0x30, 0x7e, 0x00, 0x03, 0x7a, 0x03, 0x90, 0x00, 0xd2, 0x10, 0x7e, 0x04, 0x00, 0x08, 0x7e, 0x14, 
+    0x00, 0x00, 0x84, 0xa5, 0xdb, 0xfc, 0xa5, 0xda, 0xf9, 0xa5, 0xd9, 0xf6, 0x74, 0x40, 0x12, 0x1a, 
+    0xea, 0x40, 0x0e, 0x7e, 0x68, 0x31, 0x8d, 0x7a, 0x6c, 0x00, 0xff, 0x12, 0x19, 0xc4, 0x02, 0x18, 
+    0xf7, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x80, 0xfe, 0xf5, 0x0b, 0x7e, 0x78, 0x00, 0x0b, 
+    0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x68, 0x7f, 0xbf, 0x7a, 0x6c, 0x00, 0x01, 0x7e, 0x74, 0x00, 0x01, 
+    0x02, 0x0b, 0x63, 
+
+// Segment #19, EXCLUDED Start Address 00ff2c66, Length 1393
+
+};
+
+static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+	2, 0, 3 };		// Major, Minor, Build
+
+#undef IMAGE_VERSION_NAME
+
+#undef IMAGE_ARRAY_NAME
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_down.h linux/drivers/usb/serial/io_fw_down.h
--- v2.4.2/linux/drivers/usb/serial/io_fw_down.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_fw_down.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,1123 @@
+//**************************************************************
+//* Edgeport/4 Binary Image
+//* Generated by HEX2C v1.06
+//* Copyright(c) 1998 Inside Out Networks, 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 of the License, or
+//*	(at your option) any later version.
+//**************************************************************
+
+
+//Image structure definition
+#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
+	#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
+	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
+	{
+		unsigned short	ExtAddr;
+		unsigned short	Addr;
+		unsigned short	Len;
+		unsigned char	Data[0];
+	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+
+	typedef struct _EDGE_FIRMWARE_VERSION_INFO
+	{
+		unsigned char	MajorVersion;
+		unsigned char	MinorVersion;
+		unsigned short	BuildNumber;
+	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+
+#endif
+
+#if !defined(IMAGE_ARRAY_NAME)
+	#define IMAGE_ARRAY_NAME	FirmwareImage
+	#define IMAGE_VERSION_NAME	FirmwareImageVersion
+#endif
+
+static unsigned char IMAGE_ARRAY_NAME[] = {
+
+// Segment #1, Start Address 00ff0000, Length 6
+0xff,0x00,0x00,0x00,0x06,0x00,
+    0x02, 0x00, 0x80, 0x02, 0x49, 0x39, 
+
+// Segment #2, Start Address 00ff000b, Length 3
+0xff,0x00,0x0b,0x00,0x03,0x00,
+    0x02, 0x44, 0x1a, 
+
+// Segment #3, Start Address 00ff0013, Length 3
+0xff,0x00,0x13,0x00,0x03,0x00,
+    0x02, 0x00, 0x13, 
+
+// Segment #4, Start Address 00ff001b, Length 3
+0xff,0x00,0x1b,0x00,0x03,0x00,
+    0x02, 0x00, 0x1b, 
+
+// Segment #5, Start Address 00ff0023, Length 3
+0xff,0x00,0x23,0x00,0x03,0x00,
+    0x02, 0x00, 0x23, 
+
+// Segment #6, Start Address 00ff002b, Length 3
+0xff,0x00,0x2b,0x00,0x03,0x00,
+    0x02, 0x00, 0x2b, 
+
+// Segment #7, Start Address 00ff0033, Length 3
+0xff,0x00,0x33,0x00,0x03,0x00,
+    0x02, 0x00, 0x33, 
+
+// Segment #8, Start Address 00ff003b, Length 3
+0xff,0x00,0x3b,0x00,0x03,0x00,
+    0x02, 0x00, 0x3b, 
+
+// Segment #9, Start Address 00ff0043, Length 3
+0xff,0x00,0x43,0x00,0x03,0x00,
+    0x02, 0x00, 0x43, 
+
+// Segment #10, Start Address 00ff004b, Length 3
+0xff,0x00,0x4b,0x00,0x03,0x00,
+    0x02, 0x70, 0xd4, 
+
+// Segment #11, Start Address 00ff0053, Length 3
+0xff,0x00,0x53,0x00,0x03,0x00,
+    0x02, 0x77, 0x9d, 
+
+// Segment #12, Start Address 00ff007b, Length 3
+0xff,0x00,0x7b,0x00,0x03,0x00,
+    0x02, 0x00, 0x7b, 
+
+// Segment #13, Start Address 00ff0080, Length 7
+0xff,0x00,0x80,0x00,0x07,0x00,
+    0x7e, 0x14, 0x00, 0x00, 0x02, 0x40, 0x51, 
+
+// Segment #14, Start Address 00ff4000, Length 15920
+0xff,0x00,0x00,0x40,0x30,0x3e,
+    0x7e, 0x04, 0x00, 0x01, 0x7e, 0x14, 0x7f, 0xf8, 0x7e, 0x24, 0x00, 0xfe, 0x7d, 0x31, 0x0b, 0x1a, 
+    0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x6a, 0x7e, 0xf8, 0x00, 0x59, 0xd2, 
+    0x04, 0xc2, 0x94, 0xd2, 0x95, 0x7e, 0xf4, 0x40, 0x2c, 0x02, 0x40, 0x7c, 0x12, 0x7f, 0x3f, 0xf5, 
+    0x2e, 0x7a, 0xa1, 0x2d, 0x7a, 0x11, 0x58, 0x12, 0x77, 0xda, 0x12, 0x40, 0xdc, 0x7e, 0xb3, 0x3f, 
+    0xf1, 0x60, 0x03, 0x12, 0x43, 0x68, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x7f, 0xd2, 0xaf, 0x02, 0x44, 
+    0x06, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x5f, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xa9, 
+    0x25, 0x87, 0x03, 0xa9, 0xd5, 0x87, 0xd2, 0x93, 0x89, 0x08, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 
+    0x40, 0x78, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 0xc2, 0x93, 0x89, 0x08, 0x7e, 0x08, 0x00, 0x20, 
+    0x7e, 0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x8e, 0x02, 0x7e, 0x4b, 0x7e, 0x08, 
+    0x01, 0x59, 0x7e, 0x44, 0x28, 0x7c, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xa0, 0x02, 0x7e, 0x4b, 
+    0x7e, 0x08, 0x00, 0x59, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xb2, 0x02, 
+    0x7e, 0x4b, 0x75, 0x57, 0x20, 0x75, 0x56, 0x30, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x54, 0x58, 0x75, 
+    0x55, 0x08, 0x75, 0x51, 0x08, 0x75, 0x53, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, 
+    0x00, 0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x42, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, 
+    0xb8, 0x7f, 0x75, 0xb3, 0x07, 0x75, 0xb2, 0x07, 0xd2, 0xa9, 0x22, 0xd2, 0x92, 0xe4, 0xd5, 0xe0, 
+    0xfd, 0xc2, 0x92, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2e, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 0x00, 
+    0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x72, 0x0b, 0x20, 
+    0xbe, 0x21, 0x2e, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 0xb0, 
+    0x00, 0x0c, 0x74, 0x10, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x80, 0x19, 0xb0, 0x00, 0x0c, 0x7e, 0x54, 
+    0x00, 0x02, 0x19, 0xa0, 0x00, 0x04, 0x19, 0xb0, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb0, 0x00, 0x0c, 
+    0x74, 0x07, 0x20, 0x68, 0x02, 0x74, 0x0f, 0x19, 0xb0, 0x00, 0x04, 0x30, 0x6b, 0x17, 0x74, 0xbf, 
+    0x19, 0xb0, 0x00, 0x0c, 0x74, 0x28, 0x20, 0x68, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 0x74, 
+    0x03, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 0x00, 
+    0x10, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 0x00, 
+    0x10, 0x54, 0x08, 0x19, 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 0xb2, 
+    0x23, 0x0a, 0x2b, 0x49, 0x22, 0x41, 0x99, 0x89, 0x24, 0x41, 0xa9, 0x41, 0xc6, 0x41, 0xe3, 0x42, 
+    0x00, 0x42, 0x1d, 0x42, 0x3a, 0x42, 0x57, 0x42, 0x74, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x08, 0x7e, 
+    0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x6d, 0x00, 0x7a, 0x07, 0x01, 
+    0x79, 0x7a, 0x07, 0x01, 0x89, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, 
+    0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 0x07, 
+    0x01, 0x8b, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, 
+    0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 0x22, 
+    0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x0b, 0x7e, 0x04, 0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 
+    0x01, 0x6f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7f, 0x7a, 0x07, 0x01, 0x8f, 0x22, 0xc2, 0x14, 0xc2, 
+    0x1c, 0xc2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x6d, 
+    0x00, 0x7a, 0x07, 0x01, 0x81, 0x7a, 0x07, 0x01, 0x91, 0x22, 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 0x0d, 
+    0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, 0x7a, 0x07, 0x01, 0x73, 0x6d, 0x00, 0x7a, 0x07, 
+    0x01, 0x83, 0x7a, 0x07, 0x01, 0x93, 0x22, 0xc2, 0x16, 0xc2, 0x1e, 0xc2, 0x0e, 0x7e, 0x04, 0x21, 
+    0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x85, 0x7a, 
+    0x07, 0x01, 0x95, 0x22, 0xc2, 0x17, 0xc2, 0x1f, 0xc2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, 
+    0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x87, 0x7a, 0x07, 0x01, 0x97, 
+    0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x42, 0x9c, 0x89, 0x24, 0x42, 0xac, 0x42, 0xc3, 
+    0x42, 0xda, 0x42, 0xf1, 0x43, 0x08, 0x43, 0x1f, 0x43, 0x36, 0x43, 0x4d, 0x30, 0x40, 0x07, 0x20, 
+    0x58, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, 0x50, 0x04, 0xc2, 0x28, 0x80, 0x02, 
+    0xd2, 0x28, 0x22, 0x30, 0x41, 0x07, 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 0x07, 
+    0x20, 0x51, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x42, 0x07, 0x20, 0x5a, 0x04, 
+    0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, 0x07, 0x20, 0x52, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 0x2a, 
+    0x22, 0x30, 0x43, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, 0x4b, 0x07, 0x20, 0x53, 
+    0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x44, 0x07, 0x20, 0x5c, 0x04, 0xc2, 0x2c, 
+    0x80, 0x0c, 0x30, 0x4c, 0x07, 0x20, 0x54, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 0x30, 
+    0x45, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x55, 0x04, 0xc2, 
+    0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x46, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 0x0c, 
+    0x30, 0x4e, 0x07, 0x20, 0x56, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, 0x47, 0x07, 
+    0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x57, 0x04, 0xc2, 0x2f, 0x80, 
+    0x02, 0xd2, 0x2f, 0x22, 0x43, 0xcc, 0x43, 0x79, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 0x0a, 
+    0x5b, 0x49, 0x55, 0x43, 0x64, 0x99, 0x54, 0xd3, 0x22, 0xa9, 0xc5, 0x87, 0x12, 0x43, 0xd7, 0x7e, 
+    0x04, 0x05, 0xcd, 0x7a, 0x07, 0x01, 0xc1, 0x7a, 0x07, 0x01, 0xc3, 0x7e, 0x04, 0x01, 0xcd, 0x7a, 
+    0x07, 0x01, 0xc7, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x04, 0x76, 0xbd, 0x7a, 0x05, 0x4b, 0x75, 0xf1, 
+    0x01, 0x75, 0xe1, 0x1f, 0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x75, 0xf1, 0x02, 0x75, 0xe1, 0x03, 
+    0x75, 0xe4, 0x04, 0x75, 0xf4, 0x04, 0x43, 0xa2, 0x1c, 0x12, 0x40, 0xeb, 0x7e, 0x20, 0x00, 0x12, 
+    0x41, 0x8e, 0x0b, 0x20, 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0xa9, 0xd5, 0x87, 0x12, 
+    0x43, 0xd7, 0xd2, 0x92, 0xc2, 0xa8, 0x22, 0x75, 0xa3, 0x00, 0x53, 0xa2, 0x03, 0x75, 0xc1, 0x00, 
+    0x53, 0xc0, 0x03, 0x7e, 0x00, 0x05, 0x7a, 0x01, 0xf1, 0x43, 0xf4, 0x80, 0x43, 0xe4, 0x80, 0xe5, 
+    0xf2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xf2, 0xe5, 0xe2, 0x54, 0x7f, 0x44, 0x08, 0xf5, 0xe2, 0x75, 
+    0xe1, 0x10, 0xa5, 0xd8, 0xe1, 0x22, 0x12, 0x44, 0x76, 0x12, 0x44, 0x8c, 0x12, 0x45, 0x27, 0x12, 
+    0x45, 0x57, 0x12, 0x49, 0x0f, 0x12, 0x44, 0xd8, 0x80, 0xec, 0xca, 0x09, 0x12, 0x44, 0x58, 0x10, 
+    0x01, 0x12, 0xd5, 0x51, 0x1e, 0x63, 0x53, 0x01, 0x7e, 0x00, 0x54, 0x2e, 0x01, 0x53, 0xa5, 0xe6, 
+    0xf5, 0x51, 0x80, 0x12, 0x20, 0x02, 0x1e, 0x75, 0x53, 0x00, 0x85, 0x54, 0x51, 0xd2, 0x02, 0x74, 
+    0x00, 0x80, 0x0d, 0x30, 0x02, 0x0f, 0xc2, 0x02, 0x7e, 0x00, 0x56, 0x2e, 0x01, 0x53, 0xa5, 0xe6, 
+    0x53, 0x90, 0xcf, 0x42, 0x90, 0xda, 0x09, 0x32, 0xe5, 0x23, 0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, 
+    0x09, 0xb1, 0x01, 0xb9, 0xb4, 0x00, 0x02, 0x80, 0x05, 0x14, 0x19, 0xb1, 0x01, 0xb9, 0xa5, 0x0a, 
+    0xbe, 0x21, 0x2e, 0x78, 0xeb, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 0x3f, 0xf1, 0xb4, 0x01, 0x0a, 0xc0, 
+    0xf1, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xff, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, 
+    0x60, 0x43, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, 
+    0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, 0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, 
+    0x04, 0x0a, 0x32, 0x09, 0x53, 0x6a, 0x93, 0x5e, 0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, 
+    0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, 0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 
+    0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x26, 0x60, 0x36, 0x7e, 0x20, 
+    0x00, 0x7e, 0x30, 0x01, 0xe5, 0x26, 0xa5, 0x5b, 0x68, 0x21, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 
+    0x32, 0x01, 0x79, 0xbe, 0x34, 0x00, 0x00, 0x68, 0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, 
+    0x21, 0xca, 0x19, 0x49, 0x22, 0x45, 0x17, 0x99, 0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, 
+    0x21, 0x2e, 0x78, 0xd0, 0xd2, 0xaf, 0x22, 0x4a, 0x98, 0x4d, 0xcd, 0x51, 0x02, 0x54, 0x37, 0x57, 
+    0x6c, 0x5a, 0xa1, 0x5d, 0xd6, 0x61, 0x0b, 0xc2, 0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, 
+    0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x44, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 
+    0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x12, 0x6a, 0xac, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, 
+    0xb2, 0x6a, 0x93, 0xf4, 0x52, 0x24, 0x22, 0xc2, 0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, 0x00, 
+    0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x45, 0x74, 0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 
+    0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x45, 0x7f, 0x89, 0x24, 0x45, 
+    0x8f, 0x45, 0xff, 0x46, 0x6f, 0x46, 0xdf, 0x47, 0x4f, 0x47, 0xbf, 0x48, 0x2f, 0x48, 0x9f, 0x7e, 
+    0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4d, 
+    0x96, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x89, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x89, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xb9, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xb9, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x18, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xb9, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x50, 
+    0xcb, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x8b, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8b, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xba, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xba, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x19, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xba, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x54, 
+    0x00, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x8d, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8d, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbb, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xbb, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1a, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xbb, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x57, 
+    0x35, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x8f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbc, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xbc, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1b, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xbc, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x81, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5a, 
+    0x6a, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x91, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x91, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbd, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xbd, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1c, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xbd, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x85, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5d, 
+    0x9f, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x93, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x93, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbe, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xbe, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1d, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xbe, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x60, 
+    0xd4, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x95, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x95, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbf, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xbf, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1e, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xbf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0x7e, 
+    0x27, 0x01, 0x87, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x64, 
+    0x09, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 
+    0x97, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x97, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xc0, 0x80, 0x2e, 
+    0x7e, 0x63, 0x01, 0xc0, 0xa5, 0xbe, 0x00, 0x26, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 
+    0xc8, 0x12, 0x65, 0xbf, 0x40, 0x18, 0x75, 0x2f, 0xb3, 0x12, 0x7e, 0x30, 0xc2, 0x1f, 0x6c, 0x00, 
+    0x7a, 0x03, 0x01, 0xc0, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0x22, 0xc2, 
+    0xaf, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0xa9, 0x32, 0xf2, 0x1a, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 
+    0x00, 0x00, 0x78, 0x10, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 0x40, 0x09, 0x85, 0x31, 0x2f, 0x12, 0x7e, 
+    0x30, 0x75, 0xf6, 0x00, 0xd0, 0xf1, 0xd2, 0xaf, 0x22, 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, 
+    0xf0, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xd2, 0x01, 0x75, 0x2f, 0x89, 0x12, 0x7e, 0x30, 0x7e, 
+    0x14, 0x80, 0x00, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xd8, 0x20, 0x70, 0x5a, 
+    0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x49, 0xf0, 0x20, 0x71, 0x4b, 0xa5, 
+    0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x08, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 
+    0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x20, 0x20, 0x72, 0x30, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 
+    0x20, 0xe0, 0x03, 0x02, 0x4a, 0x38, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 
+    0x4a, 0x50, 0xa5, 0x0a, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x68, 0xa5, 0x0a, 
+    0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x03, 0x02, 0x4a, 0x80, 0x30, 0x04, 0x0c, 0xc2, 0x04, 0xc0, 
+    0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, 
+    0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x75, 0x2f, 0x80, 0x12, 0x7e, 0x30, 0x54, 0x3e, 
+    0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 
+    0x75, 0x2f, 0x81, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 
+    0x66, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x82, 0x12, 0x7e, 0x30, 0x54, 0x3e, 
+    0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x66, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 
+    0x75, 0x2f, 0x83, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 
+    0x66, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x84, 0x12, 0x7e, 0x30, 0x54, 0x3e, 
+    0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0x34, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 
+    0x75, 0x2f, 0x85, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 
+    0x67, 0x74, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x75, 0x2f, 0x86, 0x12, 0x7e, 0x30, 0x54, 0x3e, 
+    0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x67, 0xb4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 
+    0x75, 0x2f, 0x87, 0x12, 0x7e, 0x30, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 
+    0x67, 0xf4, 0xca, 0x06, 0x4f, 0x49, 0x89, 0x54, 0x10, 0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, 
+    0x08, 0x22, 0x75, 0x2f, 0xa0, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, 
+    0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 
+    0x03, 0x12, 0x4d, 0x96, 0x30, 0x30, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x08, 0x22, 0x30, 0xe6, 0x02, 
+    0xd2, 0x60, 0x7e, 0x37, 0x01, 0x79, 0x7e, 0x27, 0x01, 0x99, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 
+    0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, 
+    0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, 
+    0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x60, 0xc4, 0x22, 0xc2, 
+    0x60, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 
+    0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x99, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x99, 0x7e, 0x37, 0x01, 
+    0x79, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 
+    0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0d, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 
+    0x59, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 
+    0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x0d, 0xcd, 
+    0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x09, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 
+    0x59, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4b, 0x0b, 0x22, 0xd2, 0x08, 0x7e, 
+    0x04, 0x09, 0xcd, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x75, 0x2f, 0x94, 0x12, 0x7e, 
+    0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 
+    0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 
+    0x7e, 0x27, 0x01, 0xa9, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 
+    0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 
+    0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 
+    0x00, 0x00, 0x2e, 0x27, 0x01, 0xa9, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 
+    0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 
+    0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, 
+    0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0x80, 0x7f, 0x7a, 0x51, 
+    0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x00, 0x00, 0x2e, 0x67, 
+    0x01, 0xa9, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 
+    0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 
+    0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 
+    0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 
+    0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 
+    0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 
+    0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 
+    0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 
+    0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 
+    0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 
+    0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 
+    0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 
+    0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4c, 0x6f, 0x75, 
+    0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 
+    0x38, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0xda, 
+    0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4c, 0x6f, 0xda, 0xb8, 0x02, 
+    0x4d, 0x96, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 
+    0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 
+    0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 
+    0x50, 0x80, 0x02, 0xc2, 0x50, 0x12, 0x42, 0xac, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 
+    0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 
+    0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 
+    0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 
+    0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4c, 0xc3, 0x75, 
+    0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x09, 0x01, 
+    0x22, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x75, 0x2f, 0xa1, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x81, 
+    0x00, 0x80, 0x06, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 
+    0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x50, 0xcb, 0x30, 0x31, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 
+    0x09, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x61, 0x7e, 0x37, 0x01, 0x7b, 0x7e, 0x27, 0x01, 0x9b, 0x9d, 
+    0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 0x37, 0x01, 0x7b, 0x7e, 
+    0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 
+    0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 
+    0x10, 0x61, 0xc4, 0x22, 0xc2, 0x61, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 
+    0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9b, 0x28, 0x04, 0x7e, 0x27, 
+    0x01, 0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 
+    0x7a, 0x37, 0x01, 0x7b, 0x7e, 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x11, 0xcc, 
+    0x38, 0x13, 0x7a, 0x47, 0x01, 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 
+    0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 
+    0x30, 0x9e, 0x44, 0x11, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x0d, 0xcd, 0x7d, 0x24, 
+    0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5b, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4e, 
+    0x40, 0x22, 0xd2, 0x09, 0x7e, 0x04, 0x0d, 0xcd, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 
+    0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 
+    0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 
+    0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xab, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 
+    0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 
+    0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 
+    0x47, 0x01, 0xc9, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, 0x01, 0xab, 0x1b, 0x38, 0x20, 0x0b, 0x35, 
+    0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 
+    0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 
+    0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 
+    0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 
+    0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xab, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 
+    0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 
+    0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 
+    0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, 
+    0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 
+    0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 
+    0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 
+    0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 
+    0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 
+    0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 
+    0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 
+    0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 
+    0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 
+    0xe7, 0x02, 0x4f, 0xa4, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 
+    0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 
+    0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 
+    0x4f, 0xa4, 0xda, 0xb8, 0x02, 0x50, 0xcb, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 
+    0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 
+    0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 
+    0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x12, 0x42, 0xc3, 0x02, 0x65, 0x9c, 
+    0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 
+    0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 
+    0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 
+    0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 
+    0x22, 0x02, 0x4f, 0xf8, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 
+    0x30, 0x22, 0x10, 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x75, 0x2f, 0xa2, 0x12, 
+    0x7e, 0x30, 0x7e, 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, 
+    0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x54, 0x00, 0x30, 0x32, 
+    0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0a, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x62, 0x7e, 0x37, 0x01, 0x7d, 
+    0x7e, 0x27, 0x01, 0x9d, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, 
+    0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x15, 0xcc, 
+    0x38, 0x68, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 
+    0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x62, 0xc4, 0x22, 0xc2, 0x62, 0x2d, 0x23, 0x68, 0x78, 0x6d, 
+    0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 
+    0x9d, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9d, 0x7e, 0x37, 0x01, 0x7d, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 
+    0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 
+    0x42, 0xbe, 0x44, 0x15, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 
+    0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 
+    0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x15, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 
+    0x34, 0x11, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5d, 0x12, 0x68, 0x34, 0xbe, 0x25, 
+    0x20, 0x78, 0x03, 0x02, 0x51, 0x75, 0x22, 0xd2, 0x0a, 0x7e, 0x04, 0x11, 0xcd, 0x7a, 0x07, 0x01, 
+    0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 
+    0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 
+    0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xad, 0x2e, 0x24, 
+    0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 
+    0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 
+    0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xad, 
+    0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 
+    0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 
+    0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 
+    0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 
+    0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x02, 0x00, 0x2e, 0x67, 0x01, 0xad, 0x9e, 0x24, 0x00, 0x02, 
+    0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 
+    0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 
+    0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 
+    0x23, 0x23, 0x44, 0x02, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 
+    0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 
+    0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 
+    0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 
+    0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 
+    0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 
+    0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 
+    0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 
+    0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 
+    0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x52, 0xd9, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 
+    0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 
+    0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 
+    0x68, 0x07, 0xca, 0xb8, 0x12, 0x52, 0xd9, 0xda, 0xb8, 0x02, 0x54, 0x00, 0x09, 0xb1, 0x00, 0x18, 
+    0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 
+    0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x12, 
+    0x42, 0xda, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 
+    0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 
+    0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 
+    0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 
+    0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x53, 0x2d, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 
+    0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, 
+    0x22, 0x75, 0x2f, 0xa3, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, 
+    0xd2, 0x0b, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 
+    0x12, 0x57, 0x35, 0x30, 0x33, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0b, 0x22, 0x30, 0xe6, 0x02, 0xd2, 
+    0x63, 0x7e, 0x37, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x9f, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 
+    0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 0x5f, 0x7d, 0x43, 0x2d, 
+    0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5f, 0x75, 0x2f, 0x94, 0x12, 0x7e, 
+    0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x63, 0xc4, 0x22, 0xc2, 0x63, 
+    0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 
+    0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9f, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9f, 0x7e, 0x37, 0x01, 0x7f, 
+    0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 
+    0x01, 0x5f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x19, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5f, 
+    0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 
+    0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x19, 0xcd, 0x9d, 
+    0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x15, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5f, 
+    0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x54, 0xaa, 0x22, 0xd2, 0x0b, 0x7e, 0x04, 
+    0x15, 0xcd, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 0x01, 0x6f, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 
+    0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 
+    0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 
+    0x27, 0x01, 0xaf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 
+    0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 
+    0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x03, 
+    0x00, 0x2e, 0x27, 0x01, 0xaf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 
+    0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 
+    0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 
+    0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 
+    0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, 
+    0xaf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 
+    0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 
+    0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 
+    0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 
+    0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 
+    0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 
+    0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 
+    0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 
+    0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 
+    0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 
+    0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 
+    0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 
+    0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x56, 0x0e, 0x75, 0x2f, 
+    0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 
+    0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, 
+    0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x56, 0x0e, 0xda, 0xb8, 0x02, 0x57, 
+    0x35, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 
+    0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 
+    0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 
+    0x80, 0x02, 0xc2, 0x53, 0x12, 0x42, 0xf1, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 
+    0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 
+    0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 
+    0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 
+    0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x56, 0x62, 0x75, 0x2f, 
+    0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0c, 0x01, 0x22, 
+    0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x2f, 0xa4, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x84, 0x00, 
+    0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 
+    0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5a, 0x6a, 0x30, 0x34, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0c, 
+    0x22, 0x30, 0xe6, 0x02, 0xd2, 0x64, 0x7e, 0x37, 0x01, 0x81, 0x7e, 0x27, 0x01, 0xa1, 0x9d, 0x32, 
+    0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, 
+    0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x61, 
+    0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 
+    0x64, 0xc4, 0x22, 0xc2, 0x64, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 
+    0x81, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa1, 0x28, 0x04, 0x7e, 0x27, 0x01, 
+    0xa1, 0x7e, 0x37, 0x01, 0x81, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 
+    0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1d, 0xcc, 0x38, 
+    0x13, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 
+    0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 
+    0x9e, 0x44, 0x1d, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x19, 0xcd, 0x7d, 0x24, 0x2d, 
+    0x43, 0x7a, 0x47, 0x01, 0x61, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x57, 0xdf, 
+    0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x19, 0xcd, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x75, 
+    0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 
+    0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 
+    0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb1, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 
+    0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 
+    0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 
+    0x01, 0xc9, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 0xb1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 
+    0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 
+    0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 
+    0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x14, 0x22, 
+    0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 
+    0x04, 0x00, 0x2e, 0x67, 0x01, 0xb1, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 
+    0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 
+    0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 
+    0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x04, 0x7a, 0x69, 
+    0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 
+    0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 
+    0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 
+    0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 
+    0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 
+    0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 
+    0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 
+    0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 
+    0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 
+    0x02, 0x59, 0x43, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 
+    0xb1, 0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 
+    0xd2, 0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x59, 
+    0x43, 0xda, 0xb8, 0x02, 0x5a, 0x6a, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 
+    0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 
+    0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, 
+    0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x12, 0x43, 0x08, 0x02, 0x65, 0x9c, 0x75, 
+    0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 
+    0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 
+    0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 
+    0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 
+    0x02, 0x59, 0x97, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 
+    0x22, 0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x75, 0x2f, 0xa5, 0x12, 0x7e, 
+    0x30, 0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, 
+    0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5d, 0x9f, 0x30, 0x35, 0x06, 
+    0x20, 0xe6, 0x4f, 0xd2, 0x0d, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x65, 0x7e, 0x37, 0x01, 0x83, 0x7e, 
+    0x27, 0x01, 0xa3, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 0x7a, 0x05, 0x3c, 0x7a, 
+    0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x21, 0xcc, 0x38, 
+    0x68, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 
+    0x30, 0x12, 0x68, 0x34, 0x10, 0x65, 0xc4, 0x22, 0xc2, 0x65, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 
+    0x80, 0x1a, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa3, 
+    0x28, 0x04, 0x7e, 0x27, 0x01, 0xa3, 0x7e, 0x37, 0x01, 0x83, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 
+    0x3c, 0x7a, 0x05, 0x3c, 0x7a, 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 
+    0xbe, 0x44, 0x21, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 
+    0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 
+    0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x21, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 
+    0x1d, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x63, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 
+    0x78, 0x03, 0x02, 0x5b, 0x14, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x1d, 0xcd, 0x7a, 0x07, 0x01, 0x63, 
+    0x7a, 0x07, 0x01, 0x73, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 
+    0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 
+    0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb3, 0x2e, 0x24, 0x00, 
+    0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 
+    0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 
+    0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, 0x01, 0xb3, 0x1b, 
+    0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 
+    0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 
+    0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 
+    0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 
+    0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 0x01, 0xb3, 0x9e, 0x24, 0x00, 0x02, 0x40, 
+    0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 
+    0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 
+    0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 
+    0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 
+    0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 
+    0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 
+    0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 
+    0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 
+    0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 
+    0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 
+    0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 
+    0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 
+    0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5c, 0x78, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 
+    0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 
+    0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 
+    0x07, 0xca, 0xb8, 0x12, 0x5c, 0x78, 0xda, 0xb8, 0x02, 0x5d, 0x9f, 0x09, 0xb1, 0x00, 0x18, 0x7e, 
+    0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 
+    0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 
+    0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 0x02, 0xc2, 0x55, 0x12, 0x43, 
+    0x1f, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 
+    0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 
+    0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 
+    0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 
+    0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5c, 0xcc, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 
+    0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0e, 0x01, 0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 
+    0x75, 0x2f, 0xa6, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x86, 0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, 
+    0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 
+    0x60, 0xd4, 0x30, 0x36, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0e, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x66, 
+    0x7e, 0x37, 0x01, 0x85, 0x7e, 0x27, 0x01, 0xa5, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 
+    0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, 
+    0xbe, 0x44, 0x25, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x65, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 
+    0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x66, 0xc4, 0x22, 0xc2, 0x66, 0x2d, 
+    0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x68, 
+    0x6a, 0xbe, 0x27, 0x01, 0xa5, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa5, 0x7e, 0x37, 0x01, 0x85, 0x9d, 
+    0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 
+    0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x25, 0xcc, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x65, 0x75, 
+    0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x02, 0x68, 0x34, 0x75, 0x2f, 
+    0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x25, 0xcd, 0x9d, 0x24, 
+    0x12, 0x68, 0x34, 0x7e, 0x34, 0x21, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x65, 0x12, 
+    0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5e, 0x49, 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x21, 
+    0xcd, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x75, 
+    0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 0x30, 0xd2, 0x04, 0x09, 0xb1, 
+    0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 
+    0x01, 0xb5, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x3c, 0x7d, 0x02, 
+    0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 
+    0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x06, 0x00, 
+    0x2e, 0x27, 0x01, 0xb5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0xbe, 
+    0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 
+    0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 
+    0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 
+    0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x06, 0x00, 0x2e, 0x67, 0x01, 0xb5, 
+    0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x69, 0x04, 0x7e, 0x34, 
+    0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x69, 0x04, 0x7a, 0x39, 0xc0, 
+    0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 
+    0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 
+    0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0xbd, 0x04, 0x68, 0x2b, 
+    0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 
+    0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 
+    0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 0x7e, 0x04, 0x01, 0xcd, 0x80, 
+    0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 
+    0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 
+    0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 
+    0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 
+    0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5f, 0xad, 0x75, 0x2f, 0x99, 
+    0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 
+    0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, 
+    0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5f, 0xad, 0xda, 0xb8, 0x02, 0x60, 0xd4, 
+    0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 
+    0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 
+    0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 
+    0x02, 0xc2, 0x56, 0x12, 0x43, 0x36, 0x02, 0x65, 0x9c, 0x75, 0x2f, 0x91, 0x12, 0x7e, 0x30, 0x09, 
+    0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 
+    0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x65, 0x9c, 0xca, 
+    0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 
+    0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x60, 0x01, 0x75, 0x2f, 0x95, 
+    0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, 
+    0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x75, 0x2f, 0xa7, 0x12, 0x7e, 0x30, 0x7e, 0x14, 0x87, 0x00, 0x80, 
+    0x06, 0x20, 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 
+    0xda, 0xb8, 0x68, 0x03, 0x12, 0x64, 0x09, 0x30, 0x37, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0f, 0x22, 
+    0x30, 0xe6, 0x02, 0xd2, 0x67, 0x7e, 0x37, 0x01, 0x87, 0x7e, 0x27, 0x01, 0xa7, 0x9d, 0x32, 0x40, 
+    0x31, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 0x87, 0x7e, 0x37, 0x01, 
+    0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x67, 0x75, 
+    0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x68, 0x34, 0x10, 0x67, 
+    0xc4, 0x22, 0xc2, 0x67, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x87, 
+    0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa7, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa7, 
+    0x7e, 0x37, 0x01, 0x87, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 
+    0x01, 0x87, 0x7e, 0x37, 0x01, 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x29, 0xcc, 0x38, 0x13, 
+    0x7a, 0x47, 0x01, 0x67, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 
+    0x02, 0x68, 0x34, 0x75, 0x2f, 0x94, 0x12, 0x7e, 0x30, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 
+    0x44, 0x29, 0xcd, 0x9d, 0x24, 0x12, 0x68, 0x34, 0x7e, 0x34, 0x25, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 
+    0x7a, 0x47, 0x01, 0x67, 0x12, 0x68, 0x34, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x61, 0x7e, 0x22, 
+    0xd2, 0x0f, 0x7e, 0x04, 0x25, 0xcd, 0x7a, 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x75, 0x2f, 
+    0x94, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x7e, 
+    0x30, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x70, 0x7e, 
+    0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 
+    0x00, 0x38, 0x3c, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 
+    0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x44, 0x7a, 0x47, 0x01, 
+    0xc9, 0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, 0x01, 0xb7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 
+    0x2f, 0x12, 0x7e, 0x30, 0xbe, 0x50, 0x38, 0x78, 0x03, 0x02, 0x69, 0x1f, 0x02, 0x69, 0x04, 0x75, 
+    0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 
+    0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, 
+    0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x24, 0x7e, 0x64, 0x07, 
+    0x00, 0x2e, 0x67, 0x01, 0xb7, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 
+    0x12, 0x69, 0x04, 0x7e, 0x34, 0x01, 0xcd, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 
+    0x69, 0x04, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x01, 0xcd, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 
+    0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, 
+    0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 
+    0x30, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 
+    0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 
+    0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x28, 0x7e, 0x04, 0x01, 0xcd, 0x80, 0x2a, 
+    0x7e, 0x04, 0x01, 0xcd, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 
+    0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 
+    0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 
+    0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 
+    0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 
+    0x62, 0xe2, 0x75, 0x2f, 0x99, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 
+    0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 
+    0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x62, 0xe2, 
+    0xda, 0xb8, 0x02, 0x64, 0x09, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 
+    0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 
+    0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x12, 0x43, 0x4d, 0x02, 0x65, 0x9c, 0x75, 0x2f, 
+    0x91, 0x12, 0x7e, 0x30, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x20, 0xe0, 
+    0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x65, 0x9c, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 
+    0x80, 0x12, 0x65, 0x9c, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 
+    0x09, 0x61, 0x00, 0x00, 0x12, 0x65, 0xbf, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 
+    0x63, 0x36, 0x75, 0x2f, 0x95, 0x12, 0x7e, 0x30, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x7e, 0x30, 0x22, 
+    0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 
+    0x20, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 
+    0xd2, 0x50, 0x80, 0x02, 0xc2, 0x50, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 
+    0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 
+    0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x02, 
+    0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 
+    0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 
+    0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, 
+    0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, 
+    0x53, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 
+    0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 
+    0x50, 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 
+    0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 
+    0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 
+    0x02, 0xc2, 0x55, 0x02, 0x65, 0x88, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 
+    0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 
+    0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 0x02, 0xc2, 0x56, 0x02, 0x65, 0x88, 0x7c, 
+    0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 
+    0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 
+    0x57, 0x80, 0x02, 0xc2, 0x57, 0x02, 0x65, 0x88, 0x54, 0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, 
+    0x75, 0x2f, 0x90, 0x12, 0x7e, 0x30, 0xf5, 0x2f, 0x12, 0x7e, 0x30, 0x22, 0xca, 0x19, 0x5e, 0x20, 
+    0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 
+    0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, 0x64, 0x00, 0x02, 0x02, 0x65, 0xe7, 0xca, 
+    0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x29, 0xcd, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 
+    0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, 
+    0x7e, 0x64, 0x00, 0x03, 0x02, 0x65, 0xe7, 0xd2, 0x04, 0x7e, 0x27, 0x01, 0xcb, 0x2d, 0x26, 0xbe, 
+    0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x05, 0xcd, 0x7e, 0x79, 0xa0, 
+    0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, 0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, 
+    0x01, 0xcb, 0x7e, 0x25, 0x30, 0x2d, 0x26, 0x7a, 0x25, 0x30, 0x7a, 0x07, 0x01, 0xc9, 0xda, 0x19, 
+    0xc2, 0xd7, 0x22, 0x75, 0x2f, 0x9a, 0x12, 0x7e, 0x30, 0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, 
+    0x01, 0xcd, 0x80, 0xd7, 0x4d, 0x42, 0x4a, 0xae, 0x4b, 0xa8, 0x4d, 0x7b, 0x49, 0x4f, 0x49, 0x4f, 
+    0x4c, 0xa7, 0x49, 0x4f, 0x4d, 0xbf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x4d, 0xc6, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x50, 0x77, 0x4d, 0xe3, 0x4e, 0xdd, 0x50, 0xb0, 0x49, 0x4f, 0x49, 0x4f, 
+    0x4f, 0xdc, 0x49, 0x4f, 0x50, 0xf4, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x50, 0xfb, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x53, 0xac, 0x51, 0x18, 0x52, 0x12, 0x53, 0xe5, 0x49, 0x4f, 0x49, 0x4f, 
+    0x53, 0x11, 0x49, 0x4f, 0x54, 0x29, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x54, 0x30, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x56, 0xe1, 0x54, 0x4d, 0x55, 0x47, 0x57, 0x1a, 0x49, 0x4f, 0x49, 0x4f, 
+    0x56, 0x46, 0x49, 0x4f, 0x57, 0x5e, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x57, 0x65, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x16, 0x57, 0x82, 0x58, 0x7c, 0x5a, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x59, 0x7b, 0x49, 0x4f, 0x5a, 0x93, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x5a, 0x9a, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x5d, 0x4b, 0x5a, 0xb7, 0x5b, 0xb1, 0x5d, 0x84, 0x49, 0x4f, 0x49, 0x4f, 
+    0x5c, 0xb0, 0x49, 0x4f, 0x5d, 0xc8, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x5d, 0xcf, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x60, 0x80, 0x5d, 0xec, 0x5e, 0xe6, 0x60, 0xb9, 0x49, 0x4f, 0x49, 0x4f, 
+    0x5f, 0xe5, 0x49, 0x4f, 0x60, 0xfd, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x61, 0x04, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x63, 0xb5, 0x61, 0x21, 0x62, 0x1b, 0x63, 0xee, 0x49, 0x4f, 0x49, 0x4f, 
+    0x63, 0x1a, 0x49, 0x4f, 0x64, 0x32, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x64, 0x39, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 0x49, 0x4f, 
+    0x49, 0x4f, 0x49, 0x4f, 0xca, 0x29, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x10, 0x9c, 0xb5, 
+    0xa4, 0x2e, 0x54, 0x68, 0x51, 0x89, 0x54, 0x7e, 0x39, 0x00, 0x7a, 0x19, 0x00, 0x0b, 0x34, 0x80, 
+    0xe9, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 
+    0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 
+    0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 
+    0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 
+    0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 
+    0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 
+    0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 
+    0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 
+    0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 
+    0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 
+    0x00, 0x7a, 0x19, 0x10, 0x0b, 0x35, 0x0b, 0x38, 0x00, 0x7a, 0x19, 0x00, 0x7a, 0x19, 0x10, 0x0b, 
+    0x35, 0xda, 0x29, 0x22, 0x1e, 0x50, 0x40, 0x0d, 0x7e, 0x54, 0x0b, 0x1c, 0x9c, 0xb5, 0xa4, 0x2e, 
+    0x54, 0x69, 0x1f, 0x89, 0x54, 0x7e, 0x19, 0x00, 0x7a, 0x39, 0x00, 0x0b, 0x34, 0x80, 0xe9, 0x7e, 
+    0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 
+    0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 
+    0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 
+    0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 
+    0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 
+    0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 
+    0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 
+    0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 
+    0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 
+    0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 
+    0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 
+    0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 
+    0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 
+    0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 
+    0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 
+    0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 
+    0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 
+    0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 
+    0x7e, 0x19, 0x10, 0x1b, 0x38, 0x00, 0x0b, 0x35, 0x7e, 0x19, 0x00, 0x7e, 0x19, 0x10, 0x1b, 0x38, 
+    0x00, 0x0b, 0x35, 0x22, 0x6a, 0x9b, 0x6c, 0x4f, 0x6c, 0x67, 0x6c, 0x82, 0x6d, 0x1d, 0x6d, 0xb5, 
+    0x6d, 0xd0, 0x6e, 0x62, 0x6d, 0xeb, 0x6e, 0x2c, 0x7c, 0xb3, 0xbe, 0xb0, 0x09, 0x28, 0x14, 0x75, 
+    0x2f, 0x09, 0x12, 0x7e, 0x30, 0x75, 0x57, 0x10, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x43, 0xe1, 0xc0, 
+    0xd0, 0xf1, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x6a, 0x54, 0x0b, 0x58, 
+    0x50, 0x89, 0x54, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x2f, 0xb0, 0x12, 0x7e, 
+    0x30, 0x0a, 0x22, 0x09, 0xb2, 0x6a, 0x93, 0x42, 0x24, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 
+    0x3b, 0x49, 0x33, 0x6a, 0xb7, 0x89, 0x34, 0x6a, 0xc7, 0x6a, 0xf5, 0x6b, 0x23, 0x6b, 0x51, 0x6b, 
+    0x7f, 0x6b, 0xad, 0x6b, 0xdb, 0x6c, 0x09, 0x12, 0x41, 0xa9, 0xd2, 0x28, 0xd2, 0x08, 0xc2, 0x40, 
+    0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x7e, 0x04, 0x00, 0x20, 
+    0x7a, 0x07, 0x01, 0x99, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xa9, 0x12, 0x41, 0x16, 0x12, 
+    0x64, 0x40, 0x02, 0x6c, 0x37, 0x12, 0x41, 0xc6, 0xd2, 0x29, 0xd2, 0x09, 0xc2, 0x41, 0xc2, 0x49, 
+    0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xba, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 
+    0x01, 0x9b, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xab, 0x12, 0x41, 0x16, 0x12, 0x64, 0x69, 
+    0x02, 0x6c, 0x37, 0x12, 0x41, 0xe3, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, 0xc2, 0x4a, 0xc2, 0x3a, 
+    0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9d, 
+    0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xad, 0x12, 0x41, 0x16, 0x12, 0x64, 0x92, 0x02, 0x6c, 
+    0x37, 0x12, 0x42, 0x00, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, 0xc2, 0x3b, 0xc2, 0x33, 
+    0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9f, 0x7e, 0x04, 
+    0x00, 0x38, 0x7a, 0x07, 0x01, 0xaf, 0x12, 0x41, 0x16, 0x12, 0x64, 0xbb, 0x02, 0x6c, 0x37, 0x12, 
+    0x42, 0x1d, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, 0xc2, 0x34, 0x6d, 0x00, 
+    0x7a, 0x03, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa1, 0x7e, 0x04, 0x00, 0x38, 
+    0x7a, 0x07, 0x01, 0xb1, 0x12, 0x41, 0x16, 0x12, 0x64, 0xe4, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x3a, 
+    0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, 0x6d, 0x00, 0x7a, 0x03, 
+    0x01, 0xbe, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 
+    0x01, 0xb3, 0x12, 0x41, 0x16, 0x12, 0x65, 0x0d, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x57, 0xd2, 0x2e, 
+    0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbf, 
+    0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb5, 
+    0x12, 0x41, 0x16, 0x12, 0x65, 0x36, 0x02, 0x6c, 0x37, 0x12, 0x42, 0x74, 0xd2, 0x2f, 0xd2, 0x0f, 
+    0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x7e, 0x04, 
+    0x00, 0x20, 0x7a, 0x07, 0x01, 0xa7, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb7, 0x12, 0x41, 
+    0x16, 0x12, 0x65, 0x5f, 0x02, 0x6c, 0x37, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, 0x0f, 0x12, 0x65, 0xbf, 
+    0x40, 0x0c, 0xc0, 0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xc2, 0xd7, 0x22, 0x75, 
+    0x2f, 0xb1, 0x12, 0x7e, 0x30, 0x0a, 0x52, 0x23, 0x6d, 0x00, 0x59, 0x05, 0x00, 0x32, 0x12, 0x41, 
+    0x72, 0x12, 0x41, 0x8e, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb2, 0x12, 0x7e, 0x30, 0x0a, 0x22, 0x09, 
+    0xb2, 0x6a, 0x93, 0x42, 0x23, 0x7e, 0xb0, 0x9c, 0x19, 0xb2, 0x01, 0xb9, 0x12, 0x45, 0x74, 0xd0, 
+    0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 
+    0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 
+    0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, 
+    0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, 
+    0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 0xb8, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, 
+    0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0x3e, 0x20, 
+    0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x20, 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, 
+    0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 0x59, 0x46, 0x01, 0xa9, 0x09, 0xb0, 0x00, 0x10, 0x44, 
+    0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x11, 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, 
+    0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 0x46, 0x01, 0xa9, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, 
+    0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 
+    0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x04, 0x44, 0x80, 0x80, 0x02, 0x54, 0x7f, 
+    0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x02, 0x80, 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, 
+    0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x6a, 0x93, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, 
+    0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xda, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x10, 0xa5, 
+    0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x04, 0xa5, 
+    0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x29, 0x42, 0x26, 
+    0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x15, 0xa5, 0xee, 0x52, 0x29, 0x7c, 0x74, 
+    0x5e, 0x70, 0x02, 0x78, 0x0a, 0x52, 0x26, 0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0x99, 0x12, 
+    0x42, 0x91, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 
+    0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 
+    0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 
+    0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb5, 0x12, 0x7e, 
+    0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, 
+    0x0c, 0xe5, 0x58, 0xb4, 0x07, 0x23, 0x09, 0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, 
+    0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, 
+    0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb6, 0x12, 
+    0x7e, 0x30, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe5, 0x58, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, 
+    0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, 
+    0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, 
+    0xa8, 0x22, 0x75, 0x2f, 0xb4, 0x12, 0x7e, 0x30, 0x7a, 0x21, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, 
+    0x2f, 0x12, 0x7e, 0x30, 0x7e, 0xb0, 0x01, 0x7e, 0xa0, 0xc8, 0x7c, 0x64, 0x12, 0x65, 0xbf, 0xc0, 
+    0xf1, 0x75, 0xf1, 0x01, 0x12, 0x71, 0xe9, 0xd0, 0xf1, 0xd0, 0xa8, 0x22, 0x6e, 0x9c, 0x6e, 0xe3, 
+    0x6f, 0x2a, 0x6f, 0x71, 0x6f, 0xb8, 0x6f, 0xff, 0x70, 0x46, 0x70, 0x8d, 0x75, 0x2f, 0x55, 0x12, 
+    0x7e, 0x30, 0x75, 0x2f, 0x00, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 
+    0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x69, 0x7e, 0x27, 0x01, 0x79, 0x2d, 0x23, 0x7e, 0x09, 
+    0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x0d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 
+    0x78, 0xec, 0x7a, 0x17, 0x01, 0x69, 0x7a, 0x27, 0x01, 0x79, 0x02, 0x4a, 0x98, 0x7e, 0x14, 0x09, 
+    0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x01, 0x12, 0x7e, 0x30, 0x7a, 
+    0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6b, 0x7e, 
+    0x27, 0x01, 0x7b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 
+    0x14, 0x11, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6b, 0x7a, 0x27, 0x01, 
+    0x7b, 0x02, 0x4d, 0xcd, 0x7e, 0x14, 0x0d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 
+    0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 
+    0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6d, 0x7e, 0x27, 0x01, 0x7d, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 
+    0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x15, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 
+    0x7a, 0x17, 0x01, 0x6d, 0x7a, 0x27, 0x01, 0x7d, 0x02, 0x51, 0x02, 0x7e, 0x14, 0x11, 0xcd, 0x80, 
+    0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x03, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 
+    0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x6f, 0x7e, 0x27, 0x01, 
+    0x7f, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x19, 
+    0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6f, 0x7a, 0x27, 0x01, 0x7f, 0x02, 
+    0x54, 0x37, 0x7e, 0x14, 0x15, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 
+    0x04, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 
+    0x7e, 0x17, 0x01, 0x71, 0x7e, 0x27, 0x01, 0x81, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 
+    0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1d, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 
+    0x01, 0x71, 0x7a, 0x27, 0x01, 0x81, 0x02, 0x57, 0x6c, 0x7e, 0x14, 0x19, 0xcd, 0x80, 0xeb, 0x75, 
+    0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x05, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 
+    0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x73, 0x7e, 0x27, 0x01, 0x83, 0x2d, 
+    0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x21, 0xcc, 0x38, 
+    0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x73, 0x7a, 0x27, 0x01, 0x83, 0x02, 0x5a, 0xa1, 
+    0x7e, 0x14, 0x1d, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x7e, 0x30, 0x75, 0x2f, 0x06, 0x12, 
+    0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 
+    0x01, 0x75, 0x7e, 0x27, 0x01, 0x85, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 
+    0x0b, 0x14, 0xbe, 0x14, 0x25, 0xcc, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x75, 
+    0x7a, 0x27, 0x01, 0x85, 0x02, 0x5d, 0xd6, 0x7e, 0x14, 0x21, 0xcd, 0x80, 0xeb, 0x75, 0x2f, 0x55, 
+    0x12, 0x7e, 0x30, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 
+    0x71, 0x2f, 0x12, 0x7e, 0x30, 0x7e, 0x17, 0x01, 0x77, 0x7e, 0x27, 0x01, 0x87, 0x2d, 0x23, 0x7e, 
+    0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x29, 0xcc, 0x38, 0x0f, 0x1b, 
+    0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x77, 0x7a, 0x27, 0x01, 0x87, 0x02, 0x61, 0x0b, 0x7e, 0x14, 
+    0x25, 0xcd, 0x80, 0xeb, 0xca, 0xb8, 0xc0, 0xf1, 0x75, 0x2f, 0x02, 0x12, 0x7e, 0x30, 0xe5, 0xc0, 
+    0x54, 0x03, 0x68, 0x05, 0x12, 0x77, 0xdd, 0x80, 0xf5, 0x30, 0xc2, 0x08, 0x75, 0xf1, 0x01, 0x12, 
+    0x71, 0xe9, 0x80, 0x14, 0x30, 0xc3, 0x08, 0x75, 0xf1, 0x01, 0x12, 0x71, 0x0d, 0x80, 0x09, 0x30, 
+    0xc4, 0x06, 0x75, 0xf1, 0x02, 0x12, 0x72, 0xf9, 0xd0, 0xf1, 0xda, 0xb8, 0x32, 0x75, 0x2f, 0x10, 
+    0x12, 0x7e, 0x30, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x5c, 0xe5, 
+    0xe5, 0x54, 0xc0, 0x68, 0x4f, 0xe5, 0xe6, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xc5, 0x2d, 0x35, 0xbe, 
+    0x34, 0x04, 0x00, 0x38, 0x4a, 0x7a, 0x37, 0x01, 0xc5, 0x7e, 0x37, 0x01, 0xc3, 0x7d, 0x43, 0x2d, 
+    0x45, 0xbe, 0x44, 0x09, 0xcc, 0x38, 0x40, 0x7a, 0x47, 0x01, 0xc3, 0x75, 0x2f, 0x11, 0x12, 0x7e, 
+    0x30, 0x7a, 0xb1, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x73, 0xc8, 0xa9, 0x21, 0xe5, 0x1f, 0xa9, 0xd4, 
+    0xe4, 0xa9, 0x24, 0xe4, 0xfc, 0xc2, 0xc3, 0xa9, 0x21, 0xe2, 0x3b, 0xe5, 0xe5, 0x54, 0xc0, 0x78, 
+    0xb4, 0x12, 0x76, 0x6a, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x80, 0x29, 0x80, 0x58, 0x75, 
+    0x2f, 0x16, 0x12, 0x7e, 0x30, 0x80, 0xed, 0x75, 0x2f, 0x12, 0x12, 0x7e, 0x30, 0x7a, 0xb1, 0x2f, 
+    0x12, 0x7e, 0x30, 0x9e, 0x44, 0x09, 0xcd, 0x9d, 0x54, 0x12, 0x73, 0xc8, 0x7e, 0x34, 0x05, 0xcd, 
+    0x7d, 0x54, 0x2d, 0x43, 0x80, 0xa1, 0xe5, 0xe5, 0x54, 0x03, 0x78, 0x12, 0x75, 0x2f, 0x13, 0x12, 
+    0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xe9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe9, 0x80, 0xa7, 0x75, 0x2f, 
+    0x14, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, 0xed, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xed, 0xa9, 0xd7, 
+    0xe4, 0xa9, 0x27, 0xe4, 0xfc, 0x80, 0x9d, 0x75, 0x2f, 0x15, 0x12, 0x7e, 0x30, 0x7e, 0x0f, 0x29, 
+    0xf1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xf1, 0x80, 0xe5, 0x75, 0x2f, 0x18, 0x12, 0x7e, 0x30, 0xca, 
+    0x09, 0xca, 0x39, 0xca, 0x2b, 0xc2, 0xc2, 0xa9, 0x21, 0xf2, 0x52, 0xe5, 0xf5, 0x33, 0x82, 0xe7, 
+    0x40, 0x44, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x54, 0x00, 0x40, 0x9d, 0x35, 0x40, 0x43, 0x7a, 0x37, 
+    0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc7, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x05, 0xcc, 0x38, 0x52, 
+    0x7a, 0x47, 0x01, 0xc7, 0x7d, 0x45, 0x12, 0x75, 0x26, 0xa9, 0x20, 0xf5, 0x22, 0x75, 0x2f, 0x19, 
+    0x12, 0x7e, 0x30, 0x7a, 0x91, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x81, 0xf7, 0x7a, 0x91, 0xf6, 0xe5, 
+    0xf5, 0x33, 0x82, 0xe7, 0x50, 0xbc, 0xda, 0x2b, 0xda, 0x39, 0xda, 0x09, 0x22, 0x80, 0x41, 0x80, 
+    0x64, 0x2d, 0x53, 0x6d, 0x33, 0x70, 0xb7, 0x7e, 0x04, 0x01, 0xcd, 0x7a, 0x07, 0x01, 0xc9, 0x7a, 
+    0x07, 0x01, 0xc7, 0xa9, 0x32, 0xf2, 0xdf, 0x85, 0x30, 0x2f, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x00, 
+    0x80, 0xd4, 0xca, 0x59, 0x9e, 0x44, 0x05, 0xcd, 0x9d, 0x54, 0x12, 0x75, 0x26, 0x7e, 0x34, 0x01, 
+    0xcd, 0x7d, 0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc7, 0x12, 0x75, 0x26, 0xda, 0x49, 0x80, 0x99, 
+    0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x0f, 0x29, 0xd9, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xd9, 
+    0x80, 0x9d, 0x7e, 0x0f, 0x29, 0xe1, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xe1, 0xa9, 0xd7, 0xf4, 0xa9, 
+    0x27, 0xf4, 0xfc, 0x80, 0x8a, 0x7e, 0x0f, 0x29, 0xdd, 0x0b, 0x0c, 0x7a, 0x0f, 0x29, 0xdd, 0x80, 
+    0xeb, 0xe5, 0xf5, 0x54, 0x03, 0x78, 0x1f, 0x7e, 0x2f, 0x29, 0xf9, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, 
+    0xf9, 0x80, 0x34, 0x7e, 0x2f, 0x2a, 0x01, 0x0b, 0x2c, 0x7a, 0x2f, 0x2a, 0x01, 0xa9, 0xd7, 0xf4, 
+    0xa9, 0x27, 0xf4, 0xfc, 0x80, 0x21, 0x7e, 0x2f, 0x29, 0xfd, 0x0b, 0x2c, 0x7a, 0x2f, 0x29, 0xfd, 
+    0x80, 0xeb, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x2f, 0x28, 0x12, 0x7e, 0x30, 0xca, 
+    0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xc2, 0xc4, 0xa9, 0x21, 0xf2, 0xb6, 0xe5, 0xf5, 0x33, 0x72, 0xe7, 
+    0x40, 0xe0, 0x7e, 0x0d, 0x30, 0x7e, 0x1d, 0x34, 0x7e, 0x2d, 0x38, 0x7e, 0x3d, 0x3c, 0x7e, 0x85, 
+    0x40, 0x7d, 0x90, 0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, 
+    0x97, 0x4d, 0x98, 0x68, 0x72, 0x7a, 0x11, 0xf3, 0x7a, 0x01, 0xf3, 0x7a, 0x31, 0xf3, 0x7a, 0x21, 
+    0xf3, 0x7a, 0x51, 0xf3, 0x7a, 0x41, 0xf3, 0x7a, 0x71, 0xf3, 0x7a, 0x61, 0xf3, 0x7a, 0x91, 0xf3, 
+    0x7a, 0x81, 0xf3, 0x30, 0x73, 0x1a, 0x7a, 0xb1, 0xf3, 0x7a, 0xa1, 0xf3, 0x7a, 0xd1, 0xf3, 0x7a, 
+    0xc1, 0xf3, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, 0x7d, 0x78, 0x7a, 0xf1, 0xf3, 0x7a, 0xe1, 0xf3, 
+    0xa9, 0x30, 0xf5, 0x03, 0x02, 0x72, 0xe6, 0x75, 0x2f, 0x29, 0x12, 0x7e, 0x30, 0x20, 0x73, 0x0b, 
+    0x75, 0x2f, 0x0a, 0x12, 0x7e, 0x30, 0x75, 0xf6, 0x0a, 0x80, 0x09, 0x75, 0x2f, 0x12, 0x12, 0x7e, 
+    0x30, 0x75, 0xf6, 0x12, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x30, 0x7a, 0x0d, 0x34, 0x7a, 0x0d, 
+    0x38, 0x7a, 0x0d, 0x3c, 0x7a, 0x05, 0x40, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x1e, 0xb0, 
+    0x40, 0x0c, 0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x75, 0x0b, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0xa1, 
+    0xe3, 0x7a, 0x39, 0xa0, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 
+    0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 
+    0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 
+    0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 
+    0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 
+    0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 
+    0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 
+    0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 
+    0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 
+    0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 
+    0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 
+    0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 
+    0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 
+    0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 
+    0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 
+    0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 
+    0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 
+    0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 
+    0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 
+    0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 
+    0x35, 0x7e, 0xa1, 0xe3, 0xe5, 0xe3, 0x1b, 0x38, 0x50, 0x0b, 0x35, 0x22, 0x1e, 0xb0, 0x40, 0x0c, 
+    0x7e, 0xa0, 0x0a, 0xa4, 0x7e, 0x04, 0x76, 0x69, 0x9d, 0x05, 0x89, 0x04, 0x7e, 0x39, 0xa0, 0x7a, 
+    0xa1, 0xf3, 0x0b, 0x34, 0x80, 0xea, 0xb4, 0x40, 0xe3, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 
+    0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 
+    0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 
+    0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 
+    0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 
+    0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 
+    0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 
+    0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 
+    0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 
+    0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 
+    0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 
+    0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 
+    0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 
+    0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 
+    0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 
+    0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 
+    0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 
+    0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 
+    0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 
+    0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x0b, 
+    0x38, 0x50, 0x7a, 0xa1, 0xf3, 0xf5, 0xf3, 0x0b, 0x35, 0x22, 0xc2, 0xaf, 0x7e, 0x37, 0x01, 0xc5, 
+    0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xc1, 0x7e, 0x54, 0x09, 0xcd, 0x9d, 0x50, 0xbd, 0x35, 
+    0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x4b, 0x99, 0x64, 0xda, 0x39, 0x7e, 0x07, 0x01, 
+    0xc5, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xc5, 0x2e, 0x37, 0x01, 0xc1, 0x7a, 0x37, 0x01, 0xc1, 0xbe, 
+    0x34, 0x09, 0xcc, 0x28, 0xc7, 0x7e, 0x34, 0x05, 0xcd, 0x7a, 0x37, 0x01, 0xc1, 0x80, 0xbd, 0xd2, 
+    0xaf, 0x22, 0x75, 0x2f, 0x53, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, 0x80, 0x11, 0x75, 0x2f, 0x51, 
+    0x12, 0x7e, 0x30, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 0x7c, 0xb2, 
+    0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x6e, 0x8c, 0x7c, 0xb2, 0x54, 0x78, 
+    0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x4d, 0x7a, 0x25, 
+    0x4f, 0x7e, 0x64, 0x77, 0x47, 0x7a, 0x65, 0x4b, 0x89, 0x24, 0x02, 0x77, 0x55, 0x7e, 0x64, 0x76, 
+    0xbd, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 0x19, 0xca, 
+    0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x4d, 0x7e, 0x64, 
+    0x77, 0x33, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x76, 0xb2, 0x7a, 
+    0x65, 0x4b, 0x22, 0x75, 0x2f, 0x52, 0x12, 0x7e, 0x30, 0x7e, 0x21, 0x4d, 0x7e, 0x09, 0x30, 0x0b, 
+    0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x2f, 0x54, 0x12, 0x7e, 0x30, 0x7e, 0x15, 0x4d, 
+    0x7e, 0x25, 0x4f, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x77, 0xd1, 0x30, 0xe6, 
+    0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 0x6a, 0x68, 
+    0x20, 0xe3, 0x04, 0x7e, 0x44, 0x77, 0xd9, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 0x39, 0xda, 
+    0x09, 0x7e, 0x64, 0x76, 0xbd, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x4d, 0xf5, 0x4f, 
+    0x7e, 0x64, 0x77, 0x96, 0x80, 0x99, 0x7e, 0x15, 0x4d, 0xe5, 0x4f, 0x80, 0xc4, 0xc0, 0xd0, 0xc0, 
+    0xd1, 0xc0, 0xe0, 0xca, 0x19, 0xa9, 0x20, 0xdf, 0x12, 0xa9, 0x21, 0xdf, 0x1b, 0x75, 0x2f, 0x01, 
+    0x12, 0x7e, 0x30, 0x53, 0xdf, 0xf7, 0x12, 0x40, 0xdc, 0x80, 0x0d, 0x75, 0x2f, 0xfe, 0x12, 0x7e, 
+    0x30, 0x7e, 0x14, 0x00, 0x53, 0x02, 0x40, 0x51, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 
+    0x32, 0x03, 0xa5, 0xcb, 0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x02, 0x78, 0x52, 0xca, 0x0b, 0xca, 
+    0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0xc0, 
+    0xf1, 0x7e, 0xb3, 0x2a, 0x1d, 0xb4, 0x00, 0x02, 0x80, 0x19, 0xb4, 0x01, 0x16, 0x30, 0xc0, 0x08, 
+    0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0x80, 0x1f, 0x30, 0xc1, 0x1c, 0x75, 0xf1, 0x00, 0x12, 0x78, 
+    0xcd, 0x80, 0x14, 0x30, 0xc1, 0x08, 0x75, 0xf1, 0x00, 0x12, 0x78, 0xcd, 0x80, 0x09, 0x30, 0xc0, 
+    0x06, 0x75, 0xf1, 0x00, 0x12, 0x78, 0x3c, 0xd0, 0xf1, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 
+    0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0xc2, 0xc0, 0x7e, 0xb3, 
+    0x2a, 0x1d, 0xb4, 0x02, 0x07, 0x12, 0x78, 0x5e, 0x02, 0x78, 0x52, 0x22, 0xb4, 0x01, 0xfc, 0x02, 
+    0x78, 0x98, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2a, 0x1d, 0x7a, 0x03, 0x2a, 0x1e, 0x22, 0x7e, 0xb3, 
+    0x2a, 0x15, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x15, 0x80, 0x13, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 
+    0x05, 0x0c, 0x75, 0x2f, 0x71, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xf5, 0x8f, 0x22, 0x75, 
+    0xf6, 0x00, 0x22, 0xbe, 0x57, 0x2a, 0x1b, 0x28, 0x04, 0x7e, 0x57, 0x2a, 0x1b, 0x7a, 0x0f, 0x2a, 
+    0x20, 0x7a, 0x57, 0x2a, 0x24, 0x02, 0x78, 0x98, 0x7e, 0xef, 0x2a, 0x20, 0x7e, 0xf7, 0x2a, 0x24, 
+    0x7e, 0x07, 0x2a, 0x24, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0x7e, 0xeb, 0xb0, 0xf5, 0xf3, 
+    0xa3, 0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x04, 0xa5, 0xb8, 0x08, 0xf0, 0x7a, 0xef, 0x2a, 0x20, 0x7a, 
+    0xf7, 0x2a, 0x24, 0x75, 0x2f, 0x06, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0xf6, 0x22, 0xc2, 0xc1, 0x75, 
+    0x2f, 0x03, 0x12, 0x7e, 0x30, 0xa9, 0x36, 0xe2, 0x16, 0xe5, 0xf5, 0x54, 0xc0, 0x68, 0x07, 0xa9, 
+    0xd7, 0xf4, 0xa9, 0x27, 0xf4, 0xfc, 0x53, 0xe1, 0x3f, 0x43, 0xf2, 0x88, 0x02, 0x79, 0x44, 0x7e, 
+    0xb3, 0x2a, 0x1e, 0xb4, 0x02, 0x0f, 0xa9, 0xd4, 0xe4, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x2a, 0x1e, 
+    0x7a, 0xb3, 0x2a, 0x1d, 0x22, 0xb4, 0x01, 0x39, 0x7e, 0x21, 0xe6, 0x7c, 0x32, 0x7e, 0x13, 0x2a, 
+    0x1f, 0x2c, 0x21, 0x7a, 0x23, 0x2a, 0x1f, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x2a, 0x26, 0xe5, 0xe3, 
+    0x7a, 0x09, 0xb0, 0x0b, 0x04, 0xa5, 0xdb, 0xf6, 0xa9, 0xd4, 0xe4, 0x75, 0x2f, 0x70, 0x12, 0x7e, 
+    0x30, 0x7e, 0xb3, 0x2a, 0x1f, 0x7e, 0xa3, 0x2a, 0x1c, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x79, 0xdb, 
+    0x22, 0x02, 0x7d, 0x44, 0xe5, 0xe6, 0xb4, 0x08, 0x65, 0xa9, 0xc4, 0xe2, 0x7e, 0x01, 0xe3, 0x7e, 
+    0x11, 0xe3, 0x7e, 0x31, 0xe3, 0x7e, 0x21, 0xe3, 0x7e, 0x51, 0xe3, 0x7e, 0x41, 0xe3, 0x7e, 0x71, 
+    0xe3, 0x7e, 0x61, 0xe3, 0x7a, 0x0f, 0x2a, 0x15, 0x7a, 0x1f, 0x2a, 0x19, 0x75, 0x2f, 0x04, 0x12, 
+    0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x21, 
+    0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x31, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x41, 0x2f, 0x12, 0x7e, 0x30, 
+    0x7a, 0x51, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x61, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x71, 0x2f, 0x12, 
+    0x7e, 0x30, 0xa9, 0xd4, 0xe4, 0xa9, 0xd7, 0xf4, 0xa9, 0xc6, 0xe2, 0x12, 0x79, 0xaf, 0x22, 0x6d, 
+    0x00, 0x7e, 0x14, 0x01, 0x02, 0x7a, 0x07, 0x2a, 0x24, 0x7a, 0x03, 0x2a, 0x1f, 0x7e, 0xb3, 0x2a, 
+    0x15, 0x20, 0xe7, 0x0f, 0x7a, 0x23, 0x2a, 0x1e, 0x7a, 0x33, 0x2a, 0x1d, 0xbe, 0x07, 0x2a, 0x1b, 
+    0x68, 0x09, 0x22, 0x7a, 0x33, 0x2a, 0x1e, 0x7a, 0x23, 0x2a, 0x1d, 0x7e, 0xb3, 0x2a, 0x15, 0x54, 
+    0xe3, 0x23, 0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, 
+    0x30, 0xe4, 0x03, 0x02, 0x7d, 0x44, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, 
+    0x90, 0x7a, 0x07, 0x75, 0x84, 0xff, 0x73, 0x02, 0x7b, 0x5b, 0x02, 0x7a, 0x4f, 0x02, 0x7b, 0xf8, 
+    0x02, 0x7c, 0x13, 0x02, 0x7a, 0xf4, 0x02, 0x7a, 0xb5, 0x02, 0x7c, 0x2c, 0x02, 0x7c, 0x2c, 0x02, 
+    0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 
+    0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x2f, 0x02, 0x7c, 0x35, 0x02, 0x7c, 0xe9, 0x02, 0x7c, 0x32, 
+    0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x02, 0x7c, 0x32, 0x7e, 
+    0xb3, 0x2a, 0x16, 0xb4, 0x06, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, 0x56, 0x7c, 0x0b, 0x7e, 0x13, 
+    0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x72, 0x12, 0x7e, 0x30, 0x7a, 0x01, 0x2f, 0x12, 
+    0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x4e, 0x40, 0x35, 0x02, 0x78, 0x83, 
+    0xb4, 0x08, 0x10, 0x75, 0x2f, 0x74, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf1, 0xf5, 0xf3, 0x75, 
+    0xf6, 0x01, 0x22, 0xb4, 0x00, 0x1c, 0x75, 0x2f, 0x75, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x3f, 0xf2, 
+    0x30, 0xe0, 0x05, 0x75, 0xf3, 0x02, 0x80, 0x03, 0x75, 0xf3, 0x00, 0x75, 0xf3, 0x00, 0x75, 0xf6, 
+    0x02, 0x22, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x00, 0x35, 0x75, 0x2f, 0x76, 0x12, 
+    0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0xf5, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 
+    0x09, 0xe5, 0xe1, 0x30, 0xe7, 0x0d, 0x74, 0x01, 0x80, 0x0b, 0xe5, 0xe1, 0x30, 0xe6, 0x04, 0x74, 
+    0x01, 0x80, 0x02, 0x74, 0x00, 0x53, 0xf1, 0x80, 0xf5, 0xf3, 0x75, 0xf3, 0x00, 0x75, 0xf6, 0x02, 
+    0x22, 0x02, 0x7d, 0x44, 0xc0, 0xf1, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x42, 0xf1, 0x7e, 0xb3, 
+    0x2a, 0x18, 0xb4, 0x00, 0x45, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x01, 0x24, 0x75, 0x2f, 0x77, 0x12, 
+    0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x54, 0x0f, 0x78, 0x05, 0x53, 0xe1, 0x3f, 0x80, 0x37, 0x7e, 
+    0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, 0x53, 0xe1, 0x7f, 0x80, 0x2b, 0x53, 0xe1, 0xbf, 0x80, 0x26, 
+    0xb4, 0x03, 0x17, 0x75, 0x2f, 0x78, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x1a, 0x20, 0xe7, 0x05, 
+    0x43, 0xe1, 0x80, 0x80, 0x11, 0x43, 0xe1, 0x40, 0x80, 0x0c, 0x43, 0xe1, 0xc0, 0xd0, 0xf1, 0x75, 
+    0x2f, 0x07, 0x12, 0x7e, 0x30, 0x22, 0xd0, 0xf1, 0x02, 0x78, 0x7f, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 
+    0x09, 0x23, 0x75, 0x2f, 0x79, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xbe, 0xb3, 0x3f, 0xf1, 
+    0x68, 0x11, 0xca, 0xb8, 0xc0, 0xf1, 0x12, 0x43, 0x68, 0xd0, 0xf1, 0xda, 0xb8, 0x50, 0x76, 0x7a, 
+    0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x2f, 0x7a, 0x12, 0x7e, 0x30, 0x80, 0x62, 
+    0xb4, 0x03, 0x19, 0x75, 0x2f, 0x7b, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x55, 
+    0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 0x75, 
+    0x2f, 0x7c, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 0xf2, 
+    0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x2a, 0x17, 0x60, 
+    0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2a, 0x18, 0x7e, 0x17, 0x2a, 0x19, 0x75, 0x2f, 0x73, 0x12, 0x7e, 
+    0x30, 0x7a, 0x01, 0x2f, 0x12, 0x7e, 0x30, 0x7a, 0x11, 0x2f, 0x12, 0x7e, 0x30, 0x12, 0x7d, 0x7a, 
+    0x40, 0x03, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0b, 0xf6, 0x75, 
+    0x2f, 0x7d, 0x12, 0x7e, 0x30, 0x7e, 0xb3, 0x2a, 0x18, 0x7e, 0xa3, 0x2a, 0x1a, 0x4c, 0xab, 0x78, 
+    0xe4, 0x80, 0xdf, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x0a, 0xdb, 0x75, 0x2f, 0x7e, 0x12, 0x7e, 0x30, 
+    0x7e, 0xb3, 0x2a, 0x18, 0x70, 0xcf, 0xf5, 0xf3, 0x75, 0xf6, 0x01, 0x22, 0x02, 0x7d, 0x44, 0x02, 
+    0x7d, 0x44, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x04, 0x20, 0x75, 0x2f, 0xc3, 0x12, 
+    0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x18, 0x2a, 0x26, 0x7a, 0x1c, 
+    0x00, 0x00, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0x02, 0x7c, 0xe3, 0xb4, 0x06, 0x3a, 0x75, 
+    0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 
+    0xd7, 0x2a, 0x17, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0x75, 
+    0x2f, 0xc1, 0x12, 0x7e, 0x30, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7e, 
+    0x75, 0xd0, 0x87, 0xd0, 0xa8, 0x40, 0x4f, 0x80, 0x4a, 0xb4, 0x00, 0x1c, 0xc2, 0xaf, 0xa9, 0xd5, 
+    0x87, 0x12, 0x78, 0x7f, 0xe4, 0x8d, 0xef, 0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 
+    0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 0x32, 0xb4, 0x09, 0x12, 0x7e, 0x57, 0x2a, 0x17, 0x4d, 
+    0x55, 0x68, 0x05, 0xa9, 0xd2, 0xb1, 0x80, 0x03, 0xa9, 0xc2, 0xb1, 0x80, 0x16, 0xb4, 0x07, 0x16, 
+    0xc2, 0xaf, 0x7e, 0x07, 0x2a, 0x19, 0x7e, 0x17, 0x2a, 0x17, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 
+    0xca, 0x28, 0x32, 0x02, 0x78, 0x7f, 0x02, 0x7d, 0x44, 0x7e, 0xb3, 0x2a, 0x16, 0xb4, 0x03, 0x15, 
+    0x75, 0x2f, 0xc2, 0x12, 0x7e, 0x30, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2a, 0x17, 0x7e, 0x57, 
+    0x2a, 0x1b, 0x02, 0x78, 0x83, 0xb4, 0x05, 0x39, 0x75, 0x2f, 0xc0, 0x12, 0x7e, 0x30, 0xc0, 0xa8, 
+    0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 
+    0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2a, 0x17, 0x7e, 0x47, 0x2a, 0x1b, 0x12, 0x7e, 0x3c, 0xd0, 0x87, 
+    0xd0, 0xa8, 0x7e, 0x08, 0x2a, 0x26, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x2a, 0x1b, 0x02, 0x78, 
+    0x83, 0x02, 0x7d, 0x44, 0x75, 0x2f, 0x07, 0x12, 0x7e, 0x30, 0x43, 0xe1, 0xc0, 0x22, 0xc0, 0xa8, 
+    0xc0, 0x87, 0xc2, 0xaf, 0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x19, 0x7e, 0x08, 0x2a, 0x26, 
+    0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0xca, 0x49, 0x12, 0x7e, 0x3c, 0xda, 0x59, 0xda, 0x0b, 0xd0, 
+    0x87, 0xd0, 0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0x22, 0xc0, 0xa8, 0xc0, 0x87, 0xc2, 0xaf, 
+    0xa9, 0xd5, 0x87, 0x12, 0x7d, 0xb9, 0x40, 0x2b, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 
+    0x7f, 0x61, 0x7e, 0x78, 0x2a, 0x26, 0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2a, 0x1b, 0xbd, 0x74, 
+    0x78, 0x11, 0x75, 0x2f, 0xc1, 0x12, 0x7e, 0x30, 0x12, 0x7e, 0x75, 0x40, 0x06, 0xd0, 0x87, 0xd0, 
+    0xa8, 0xc3, 0x22, 0xd0, 0x87, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x34, 0x7f, 
+    0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 0x87, 0x7e, 0x34, 0x7f, 0xc2, 
+    0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, 0x34, 0x7f, 0xcc, 0x7e, 0x1b, 
+    0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 0x2d, 0x75, 0x0b, 0x3a, 0x30, 
+    0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 0x1b, 0x50, 0x30, 0x3e, 0x10, 
+    0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 0x1a, 0x30, 0xbd, 0x38, 0x50, 
+    0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 0x90, 0x0a, 0x49, 0x4d, 0x44, 
+    0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 0xff, 0xc3, 0x22, 0xd3, 0x22, 
+
+// Segment #15, Start Address 00ff7fc6, Length 4
+0xff,0x00,0xc6,0x7f,0x04,0x00,
+    0x01, 0x0c, 0x03, 0x00, 
+
+// Segment #16, Start Address 00ff7e30, Length 315
+0xff,0x00,0x30,0x7e,0x3b,0x01,
+    0xca, 0x08, 0x7e, 0x01, 0x2f, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, 
+    0x0b, 0xc0, 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 
+    0xfc, 0x7c, 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 
+    0x44, 0x00, 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 
+    0xfa, 0x7f, 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, 
+    0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x7e, 0x9f, 
+    0xda, 0x79, 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x43, 
+    0x90, 0x30, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 
+    0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, 
+    0x6d, 0x77, 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 0x00, 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 
+    0xf3, 0x7f, 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 0x7e, 0x1b, 0x10, 0xbc, 0x10, 0x68, 0x06, 
+    0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2c, 0x6d, 0x00, 0x7c, 0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 
+    0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 0x01, 0x78, 0x16, 0x0b, 0x2c, 0x0b, 0x1c, 
+    0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x03, 0x63, 0x90, 0x30, 0x4d, 0x77, 0x78, 0x93, 0xc2, 
+    0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 
+    0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 
+    0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 
+    0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 0xfe, 0x0b, 0x1a, 0x00, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 
+    0x51, 0x23, 0x7e, 0x18, 0x7f, 0x15, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 
+    0x08, 0xa5, 0xb8, 0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 
+};
+
+static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+	1, 12, 3 };		// Major, Minor, Build
+
+#undef IMAGE_VERSION_NAME
+
+#undef IMAGE_ARRAY_NAME
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_fw_down2.h linux/drivers/usb/serial/io_fw_down2.h
--- v2.4.2/linux/drivers/usb/serial/io_fw_down2.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_fw_down2.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,1135 @@
+//**************************************************************
+//* Edgeport/4 Binary Image
+//* Generated by HEX2C v1.06
+//* Copyright(c) 1998 Inside Out Networks, 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 of the License, or
+//*	(at your option) any later version.
+//**************************************************************
+
+
+//Image structure definition
+#if !defined(DEFINED_EDGE_FIRMWARE_IMAGE_RECORD)
+	#define DEFINED_EDGE_FIRMWARE_IMAGE_RECORD
+	typedef struct _EDGE_FIRMWARE_IMAGE_RECORD
+	{
+		unsigned short ExtAddr;
+		unsigned short Addr;
+		unsigned short Len;
+		unsigned char  Data[0];
+	} EDGE_FIRMWARE_IMAGE_RECORD, *PEDGE_FIRMWARE_IMAGE_RECORD;
+
+	typedef struct _EDGE_FIRMWARE_VERSION_INFO
+	{
+		unsigned char	 MajorVersion;
+		unsigned char  MinorVersion;
+		unsigned short BuildNumber;
+	} EDGE_FIRMWARE_VERSION_INFO, *PEDGE_FIRMWARE_VERSION_INFO;
+
+#endif
+
+#if !defined(IMAGE_ARRAY_NAME)
+	#define IMAGE_ARRAY_NAME	FirmwareImage
+	#define IMAGE_VERSION_NAME	FirmwareImageVersion
+#endif
+
+static unsigned char IMAGE_ARRAY_NAME[] = {
+
+// Segment #1, Start Address 00ff0000, Length 6
+0xff,0x00,0x00,0x00,0x06,0x00,
+    0x02, 0x00, 0x80, 0x02, 0x45, 0x14, 
+
+// Segment #2, Start Address 00ff000b, Length 3
+0xff,0x00,0x0b,0x00,0x03,0x00,
+    0x02, 0x44, 0xa5, 
+
+// Segment #3, Start Address 00ff0013, Length 3
+0xff,0x00,0x13,0x00,0x03,0x00,
+    0x02, 0x63, 0xab, 
+
+// Segment #4, Start Address 00ff001b, Length 3
+0xff,0x00,0x1b,0x00,0x03,0x00,
+    0x02, 0x00, 0x1b, 
+
+// Segment #5, Start Address 00ff0023, Length 3
+0xff,0x00,0x23,0x00,0x03,0x00,
+    0x02, 0x00, 0x23, 
+
+// Segment #6, Start Address 00ff002b, Length 3
+0xff,0x00,0x2b,0x00,0x03,0x00,
+    0x02, 0x00, 0x2b, 
+
+// Segment #7, Start Address 00ff0033, Length 3
+0xff,0x00,0x33,0x00,0x03,0x00,
+    0x02, 0x00, 0x33, 
+
+// Segment #8, Start Address 00ff003b, Length 3
+0xff,0x00,0x3b,0x00,0x03,0x00,
+    0x02, 0x00, 0x3b, 
+
+// Segment #9, Start Address 00ff0043, Length 3
+0xff,0x00,0x43,0x00,0x03,0x00,
+    0x02, 0x00, 0x43, 
+
+// Segment #10, Start Address 00ff004b, Length 3
+0xff,0x00,0x4b,0x00,0x03,0x00,
+    0x02, 0x00, 0x4b, 
+
+// Segment #11, Start Address 00ff0053, Length 3
+0xff,0x00,0x53,0x00,0x03,0x00,
+    0x02, 0x67, 0x5f, 
+
+// Segment #12, Start Address 00ff007b, Length 3
+0xff,0x00,0x7b,0x00,0x03,0x00,
+    0x02, 0x00, 0x7b, 
+
+// Segment #13, Start Address 00ff0080, Length 7
+0xff,0x00,0x80,0x00,0x07,0x00,
+    0x7e, 0x14, 0x00, 0x00, 0x02, 0x40, 0x52, 
+
+// Segment #14, Start Address 00ff3000, Length 2918
+0xff,0x00,0x00,0x30,0x66,0x0b,
+    0x12, 0x30, 0x64, 0x12, 0x30, 0xff, 0x12, 0x31, 0x2f, 0x12, 0x30, 0xb0, 0x80, 0xf2, 0xe5, 0x23, 
+    0x60, 0x19, 0x7e, 0x14, 0x00, 0x00, 0x09, 0xb1, 0x01, 0xb9, 0xb4, 0x00, 0x02, 0x80, 0x05, 0x14, 
+    0x19, 0xb1, 0x01, 0xb9, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xeb, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 
+    0x3f, 0xf1, 0xb4, 0x01, 0x03, 0x12, 0x65, 0x67, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0x7e, 0xb3, 0x3f, 
+    0xf1, 0xb4, 0x01, 0x1d, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x1a, 0x6c, 0xaa, 
+    0x60, 0x0f, 0xca, 0x0b, 0xca, 0x39, 0xca, 0x59, 0x12, 0x64, 0x24, 0xda, 0x59, 0xda, 0x39, 0xda, 
+    0x0b, 0xd2, 0xaf, 0x22, 0xc2, 0xaf, 0xe5, 0x22, 0x60, 0x43, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 
+    0x03, 0x80, 0x38, 0x39, 0x7e, 0x04, 0x80, 0x00, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x21, 0x09, 0xa0, 
+    0x00, 0x04, 0x4e, 0xa0, 0x05, 0x19, 0xa0, 0x00, 0x04, 0x0a, 0x32, 0x09, 0x53, 0x35, 0x33, 0x5e, 
+    0x51, 0x27, 0x68, 0x0b, 0x09, 0xa0, 0x00, 0x10, 0x4e, 0xa0, 0x01, 0x19, 0xa0, 0x00, 0x10, 0x2e, 
+    0x04, 0x01, 0x00, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xd1, 0x75, 0x22, 0x00, 0xd2, 0xaf, 0x22, 
+    0xc2, 0xaf, 0xe5, 0x26, 0x60, 0x36, 0x7e, 0x20, 0x00, 0x7e, 0x30, 0x01, 0xe5, 0x26, 0xa5, 0x5b, 
+    0x68, 0x21, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x32, 0x01, 0x79, 0xbe, 0x34, 0x00, 0x00, 0x68, 
+    0x12, 0x7e, 0xb1, 0x21, 0xa5, 0x4b, 0x7a, 0xb1, 0x21, 0xca, 0x19, 0x49, 0x22, 0x30, 0xef, 0x99, 
+    0x24, 0xda, 0x19, 0x3e, 0x30, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xd0, 0xd2, 0xaf, 0x22, 0x46, 
+    0x4f, 0x49, 0x7c, 0x4c, 0xa9, 0x4f, 0xd6, 0x53, 0x03, 0x56, 0x30, 0x59, 0x5d, 0x5c, 0x8a, 0xc2, 
+    0xaf, 0xe5, 0x24, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, 0x1c, 
+    0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0xca, 0x28, 0x12, 0x35, 
+    0x4c, 0xda, 0x28, 0x40, 0x09, 0x0a, 0x22, 0x09, 0xb2, 0x35, 0x33, 0xf4, 0x52, 0x24, 0x22, 0xc2, 
+    0xaf, 0xe5, 0x23, 0x60, 0x14, 0x7e, 0x20, 0x00, 0x13, 0x50, 0x07, 0xca, 0xb8, 0x12, 0x31, 0x4c, 
+    0xda, 0xb8, 0xa5, 0x0a, 0xbe, 0x21, 0x2e, 0x78, 0xef, 0xd2, 0xaf, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 
+    0x2b, 0x49, 0x22, 0x31, 0x57, 0x89, 0x24, 0x31, 0x67, 0x31, 0xd0, 0x32, 0x39, 0x32, 0xa2, 0x33, 
+    0x0b, 0x33, 0x74, 0x33, 0xdd, 0x34, 0x46, 0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x78, 
+    0x24, 0x7e, 0x24, 0x80, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 
+    0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x49, 0x45, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 
+    0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x89, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x89, 0x7e, 
+    0x60, 0x9c, 0x7a, 0x63, 0x01, 0xb9, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xb9, 0xa5, 0xbe, 0x00, 0x1f, 
+    0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 
+    0xb3, 0x12, 0x73, 0x35, 0xc2, 0x18, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x12, 0x64, 0x86, 0x22, 
+    0x7e, 0x27, 0x01, 0x7b, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x81, 0x00, 0x09, 0xb2, 
+    0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 
+    0x4c, 0x72, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 
+    0x01, 0x8b, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8b, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xba, 0x80, 
+    0x27, 0x7e, 0x63, 0x01, 0xba, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 
+    0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x19, 0x6c, 
+    0x00, 0x7a, 0x03, 0x01, 0xba, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 0x00, 
+    0x00, 0x78, 0x24, 0x7e, 0x24, 0x82, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 
+    0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x4f, 0x9f, 0x7d, 0x21, 0xda, 0x19, 0x30, 
+    0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x8d, 0x68, 0x0d, 0x7a, 0x27, 0x01, 
+    0x8d, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbb, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbb, 0xa5, 0xbe, 
+    0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 
+    0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x1a, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x12, 0x64, 
+    0x86, 0x22, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x83, 0x00, 
+    0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 
+    0x12, 0x12, 0x52, 0xcc, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 
+    0xbe, 0x27, 0x01, 0x8f, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x8f, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 
+    0xbc, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbc, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 
+    0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 
+    0x1b, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x81, 0xbe, 
+    0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x84, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 
+    0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x55, 0xf9, 0x7d, 0x21, 0xda, 
+    0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x91, 0x68, 0x0d, 0x7a, 
+    0x27, 0x01, 0x91, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbd, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbd, 
+    0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 
+    0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x1c, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbd, 
+    0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 
+    0x85, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 
+    0x19, 0x7d, 0x12, 0x12, 0x59, 0x26, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 
+    0x80, 0x1e, 0xbe, 0x27, 0x01, 0x93, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x93, 0x7e, 0x60, 0x9c, 0x7a, 
+    0x63, 0x01, 0xbe, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xbe, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 
+    0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 
+    0x35, 0xc2, 0x1d, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xbe, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 
+    0x85, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 0x7e, 0x24, 0x86, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 
+    0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5c, 0x53, 0x7d, 
+    0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x95, 0x68, 
+    0x0d, 0x7a, 0x27, 0x01, 0x95, 0x7e, 0x60, 0x9c, 0x7a, 0x63, 0x01, 0xbf, 0x80, 0x27, 0x7e, 0x63, 
+    0x01, 0xbf, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 
+    0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 0x12, 0x73, 0x35, 0xc2, 0x1e, 0x6c, 0x00, 0x7a, 0x03, 
+    0x01, 0xbf, 0x12, 0x64, 0x86, 0x22, 0x7e, 0x27, 0x01, 0x87, 0xbe, 0x24, 0x00, 0x00, 0x78, 0x24, 
+    0x7e, 0x24, 0x87, 0x00, 0x09, 0xb2, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 
+    0x0b, 0xca, 0x19, 0x7d, 0x12, 0x12, 0x5f, 0x80, 0x7d, 0x21, 0xda, 0x19, 0x30, 0xe6, 0x18, 0x7e, 
+    0x60, 0x00, 0x80, 0x1e, 0xbe, 0x27, 0x01, 0x97, 0x68, 0x0d, 0x7a, 0x27, 0x01, 0x97, 0x7e, 0x60, 
+    0x9c, 0x7a, 0x63, 0x01, 0xc0, 0x80, 0x27, 0x7e, 0x63, 0x01, 0xc0, 0xa5, 0xbe, 0x00, 0x1f, 0x7e, 
+    0x60, 0x01, 0x7e, 0xb0, 0x00, 0x7e, 0xa0, 0xc8, 0x12, 0x61, 0x36, 0x40, 0x11, 0x75, 0x2f, 0xb3, 
+    0x12, 0x73, 0x35, 0xc2, 0x1f, 0x6c, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x12, 0x64, 0x86, 0x22, 0xc2, 
+    0xaf, 0x7e, 0x07, 0x01, 0xcb, 0xbe, 0x04, 0x00, 0x00, 0x78, 0x28, 0x74, 0x20, 0x7a, 0xb3, 0x91, 
+    0x00, 0x7e, 0xb3, 0x91, 0x15, 0x30, 0xe5, 0x1b, 0x7e, 0xb3, 0x91, 0x1a, 0xbe, 0xb0, 0x3f, 0x38, 
+    0x0c, 0x85, 0x31, 0x2f, 0x12, 0x73, 0x35, 0x74, 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x74, 0x20, 0x7a, 
+    0xb3, 0x91, 0x15, 0xd2, 0xaf, 0x22, 0x35, 0x3b, 0x36, 0xe8, 0x37, 0x00, 0x37, 0x1b, 0x37, 0xb6, 
+    0x38, 0x4e, 0x38, 0x69, 0x38, 0xfb, 0x38, 0x84, 0x38, 0xc5, 0x7c, 0xb3, 0xbe, 0xb0, 0x09, 0x28, 
+    0x22, 0x75, 0x2f, 0x09, 0x12, 0x73, 0x35, 0x75, 0x57, 0x02, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x00, 
+    0x74, 0x01, 0x7a, 0xb3, 0x91, 0x11, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x01, 0x7a, 0xb3, 
+    0x91, 0x11, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x23, 0x6c, 0xaa, 0x2e, 0x54, 0x34, 0xe6, 0x0b, 0x58, 
+    0x50, 0x89, 0x54, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x75, 0x2f, 0xb0, 0x12, 0x73, 
+    0x35, 0x0a, 0x22, 0x09, 0xb2, 0x35, 0x33, 0x42, 0x24, 0xd0, 0xa8, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 
+    0x3b, 0x49, 0x33, 0x35, 0x57, 0x89, 0x34, 0x35, 0x67, 0x35, 0x95, 0x35, 0xc3, 0x35, 0xf1, 0x36, 
+    0x1f, 0x36, 0x4d, 0x36, 0x7b, 0x36, 0xa9, 0x12, 0x41, 0xba, 0xd2, 0x28, 0xd2, 0x08, 0xc2, 0x40, 
+    0xc2, 0x48, 0xc2, 0x38, 0xc2, 0x30, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xb9, 0x7e, 0x04, 0x00, 0x20, 
+    0x7a, 0x07, 0x01, 0x99, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xa9, 0x12, 0x41, 0x27, 0x12, 
+    0x5f, 0xb7, 0x02, 0x36, 0xd7, 0x12, 0x41, 0xd7, 0xd2, 0x29, 0xd2, 0x09, 0xc2, 0x41, 0xc2, 0x49, 
+    0xc2, 0x39, 0xc2, 0x31, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xba, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 
+    0x01, 0x9b, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xab, 0x12, 0x41, 0x27, 0x12, 0x5f, 0xe0, 
+    0x02, 0x36, 0xd7, 0x12, 0x41, 0xf4, 0xd2, 0x2a, 0xd2, 0x0a, 0xc2, 0x42, 0xc2, 0x4a, 0xc2, 0x3a, 
+    0xc2, 0x32, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbb, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9d, 
+    0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xad, 0x12, 0x41, 0x27, 0x12, 0x60, 0x09, 0x02, 0x36, 
+    0xd7, 0x12, 0x42, 0x11, 0xd2, 0x2b, 0xd2, 0x0b, 0xc2, 0x43, 0xc2, 0x4b, 0xc2, 0x3b, 0xc2, 0x33, 
+    0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbc, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0x9f, 0x7e, 0x04, 
+    0x00, 0x38, 0x7a, 0x07, 0x01, 0xaf, 0x12, 0x41, 0x27, 0x12, 0x60, 0x32, 0x02, 0x36, 0xd7, 0x12, 
+    0x42, 0x2e, 0xd2, 0x2c, 0xd2, 0x0c, 0xc2, 0x44, 0xc2, 0x4c, 0xc2, 0x3c, 0xc2, 0x34, 0x6d, 0x00, 
+    0x7a, 0x03, 0x01, 0xbd, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa1, 0x7e, 0x04, 0x00, 0x38, 
+    0x7a, 0x07, 0x01, 0xb1, 0x12, 0x41, 0x27, 0x12, 0x60, 0x5b, 0x02, 0x36, 0xd7, 0x12, 0x42, 0x4b, 
+    0xd2, 0x2d, 0xd2, 0x0d, 0xc2, 0x45, 0xc2, 0x4d, 0xc2, 0x3d, 0xc2, 0x35, 0x6d, 0x00, 0x7a, 0x03, 
+    0x01, 0xbe, 0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa3, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 
+    0x01, 0xb3, 0x12, 0x41, 0x27, 0x12, 0x60, 0x84, 0x02, 0x36, 0xd7, 0x12, 0x42, 0x68, 0xd2, 0x2e, 
+    0xd2, 0x0e, 0xc2, 0x46, 0xc2, 0x4e, 0xc2, 0x3e, 0xc2, 0x36, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xbf, 
+    0x7e, 0x04, 0x00, 0x20, 0x7a, 0x07, 0x01, 0xa5, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb5, 
+    0x12, 0x41, 0x27, 0x12, 0x60, 0xad, 0x02, 0x36, 0xd7, 0x12, 0x42, 0x85, 0xd2, 0x2f, 0xd2, 0x0f, 
+    0xc2, 0x47, 0xc2, 0x4f, 0xc2, 0x3f, 0xc2, 0x37, 0x6d, 0x00, 0x7a, 0x03, 0x01, 0xc0, 0x7e, 0x04, 
+    0x00, 0x20, 0x7a, 0x07, 0x01, 0xa7, 0x7e, 0x04, 0x00, 0x38, 0x7a, 0x07, 0x01, 0xb7, 0x12, 0x41, 
+    0x27, 0x12, 0x60, 0xd6, 0x02, 0x36, 0xd7, 0x7e, 0xa0, 0xd0, 0x7e, 0x60, 0x0f, 0x12, 0x61, 0x36, 
+    0x40, 0x05, 0x12, 0x64, 0x86, 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0xb1, 0x12, 0x73, 0x35, 0x0a, 0x52, 
+    0x23, 0x6d, 0x00, 0x59, 0x05, 0x00, 0x32, 0x12, 0x41, 0x83, 0x12, 0x41, 0x9f, 0xd0, 0xa8, 0x22, 
+    0x75, 0x2f, 0xb2, 0x12, 0x73, 0x35, 0x0a, 0x22, 0x09, 0xb2, 0x35, 0x33, 0x42, 0x23, 0x7e, 0xb0, 
+    0x9c, 0x19, 0xb2, 0x01, 0xb9, 0x12, 0x31, 0x4c, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 
+    0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x19, 
+    0x30, 0x00, 0x0c, 0x7c, 0x74, 0x5e, 0x70, 0x01, 0x68, 0x12, 0x44, 0x40, 0xca, 0xb8, 0x09, 0xb0, 
+    0x00, 0x10, 0x44, 0x02, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 0x80, 0x02, 0x54, 0xbf, 0x7c, 0x74, 
+    0x5e, 0x70, 0x08, 0x68, 0x04, 0x44, 0x08, 0x80, 0x02, 0x54, 0xf7, 0x09, 0x30, 0x00, 0x0c, 0xca, 
+    0xb8, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xda, 0xb8, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 
+    0x0c, 0x0a, 0x62, 0x09, 0xb6, 0x35, 0x33, 0x3e, 0x20, 0x0a, 0x62, 0x7c, 0x74, 0x5e, 0x70, 0x02, 
+    0x68, 0x20, 0x42, 0x27, 0xca, 0xb8, 0x74, 0x61, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x10, 
+    0x59, 0x46, 0x01, 0xa9, 0x09, 0xb0, 0x00, 0x10, 0x44, 0x01, 0x19, 0xb0, 0x00, 0x10, 0xda, 0xb8, 
+    0x80, 0x11, 0xf4, 0x52, 0x27, 0x74, 0xa1, 0x19, 0xb0, 0x00, 0x08, 0x7e, 0x44, 0x00, 0x38, 0x59, 
+    0x46, 0x01, 0xa9, 0xd0, 0xa8, 0x22, 0x7c, 0x74, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 
+    0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x08, 0x7c, 0x74, 0x5e, 0x70, 
+    0x01, 0x68, 0x04, 0x44, 0x80, 0x80, 0x02, 0x54, 0x7f, 0x7c, 0x74, 0x5e, 0x70, 0x08, 0x68, 0x04, 
+    0x44, 0x02, 0x80, 0x02, 0x54, 0xfd, 0x19, 0xb0, 0x00, 0x08, 0x19, 0x30, 0x00, 0x0c, 0x0a, 0x62, 
+    0x09, 0xb6, 0x35, 0x33, 0xa5, 0xfd, 0xf4, 0xa5, 0xfe, 0xca, 0x28, 0x3e, 0x20, 0x0a, 0x62, 0xda, 
+    0x28, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x28, 0x42, 0x26, 0x7e, 0x44, 
+    0x00, 0x08, 0x59, 0x46, 0x01, 0x99, 0x80, 0x04, 0xa5, 0xee, 0x52, 0x28, 0x7c, 0x74, 0x5e, 0x70, 
+    0x04, 0x68, 0x10, 0xa5, 0xed, 0x42, 0x29, 0x42, 0x26, 0x7e, 0x44, 0x00, 0x08, 0x59, 0x46, 0x01, 
+    0x99, 0x80, 0x15, 0xa5, 0xee, 0x52, 0x29, 0x7c, 0x74, 0x5e, 0x70, 0x02, 0x78, 0x0a, 0x52, 0x26, 
+    0x7e, 0x44, 0x00, 0x20, 0x59, 0x46, 0x01, 0x99, 0x12, 0x42, 0xa2, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 
+    0x80, 0x00, 0x4c, 0x02, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 
+    0x00, 0x10, 0x19, 0x30, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x09, 
+    0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x19, 0x40, 0x00, 0x18, 0x19, 0x30, 0x00, 
+    0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb5, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 
+    0x09, 0xb0, 0x00, 0x0c, 0x44, 0x40, 0x19, 0xb0, 0x00, 0x0c, 0xe5, 0x58, 0xb4, 0x07, 0x23, 0x09, 
+    0xb0, 0x00, 0x10, 0x4e, 0xb0, 0x02, 0x19, 0xb0, 0x00, 0x10, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 
+    0x19, 0xb0, 0x00, 0x0c, 0x09, 0xb0, 0x00, 0x04, 0x54, 0xf7, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 
+    0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb6, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x80, 0x00, 0x4c, 
+    0x02, 0xe5, 0x58, 0xb4, 0x07, 0x18, 0x09, 0x30, 0x00, 0x0c, 0x74, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 
+    0x09, 0xb0, 0x00, 0x04, 0x44, 0x08, 0x19, 0xb0, 0x00, 0x04, 0x19, 0x30, 0x00, 0x0c, 0x09, 0xb0, 
+    0x00, 0x0c, 0x54, 0xbf, 0x19, 0xb0, 0x00, 0x0c, 0xd0, 0xa8, 0x22, 0x75, 0x2f, 0xb4, 0x12, 0x73, 
+    0x35, 0x7a, 0x21, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x41, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0xb0, 0x01, 
+    0x7e, 0xa0, 0xc8, 0x7c, 0x64, 0x12, 0x61, 0x36, 0x12, 0x64, 0x86, 0xd0, 0xa8, 0x22, 0x39, 0x2e, 
+    0x39, 0x75, 0x39, 0xbc, 0x3a, 0x03, 0x3a, 0x4a, 0x3a, 0x91, 0x3a, 0xd8, 0x3b, 0x1f, 0x75, 0x2f, 
+    0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 
+    0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x69, 0x7e, 0x27, 0x01, 0x79, 0x2d, 0x23, 
+    0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x08, 0x2c, 0x38, 0x0f, 
+    0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x69, 0x7a, 0x27, 0x01, 0x79, 0x02, 0x46, 0x4f, 0x7e, 
+    0x14, 0x04, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x01, 0x12, 0x73, 
+    0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 
+    0x6b, 0x7e, 0x27, 0x01, 0x7b, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 
+    0x14, 0xbe, 0x14, 0x0c, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6b, 0x7a, 
+    0x27, 0x01, 0x7b, 0x02, 0x49, 0x7c, 0x7e, 0x14, 0x08, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 
+    0x73, 0x35, 0x75, 0x2f, 0x02, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 
+    0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x6d, 0x7e, 0x27, 0x01, 0x7d, 0x2d, 0x23, 0x7e, 0x09, 
+    0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x10, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 
+    0x78, 0xec, 0x7a, 0x17, 0x01, 0x6d, 0x7a, 0x27, 0x01, 0x7d, 0x02, 0x4c, 0xa9, 0x7e, 0x14, 0x0c, 
+    0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x03, 0x12, 0x73, 0x35, 0x7a, 
+    0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x6f, 0x7e, 
+    0x27, 0x01, 0x7f, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 
+    0x14, 0x14, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x6f, 0x7a, 0x27, 0x01, 
+    0x7f, 0x02, 0x4f, 0xd6, 0x7e, 0x14, 0x10, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 
+    0x75, 0x2f, 0x04, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 
+    0x73, 0x35, 0x7e, 0x17, 0x01, 0x71, 0x7e, 0x27, 0x01, 0x81, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 
+    0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x18, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 
+    0x7a, 0x17, 0x01, 0x71, 0x7a, 0x27, 0x01, 0x81, 0x02, 0x53, 0x03, 0x7e, 0x14, 0x14, 0x2d, 0x80, 
+    0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x05, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 
+    0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x73, 0x7e, 0x27, 0x01, 
+    0x83, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x1c, 
+    0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x73, 0x7a, 0x27, 0x01, 0x83, 0x02, 
+    0x56, 0x30, 0x7e, 0x14, 0x18, 0x2d, 0x80, 0xeb, 0x75, 0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 
+    0x06, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 
+    0x7e, 0x17, 0x01, 0x75, 0x7e, 0x27, 0x01, 0x85, 0x2d, 0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 
+    0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x20, 0x2c, 0x38, 0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 
+    0x01, 0x75, 0x7a, 0x27, 0x01, 0x85, 0x02, 0x59, 0x5d, 0x7e, 0x14, 0x1c, 0x2d, 0x80, 0xeb, 0x75, 
+    0x2f, 0x55, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x07, 0x12, 0x73, 0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 
+    0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x7e, 0x17, 0x01, 0x77, 0x7e, 0x27, 0x01, 0x87, 0x2d, 
+    0x23, 0x7e, 0x09, 0xb0, 0x0b, 0x04, 0x7a, 0x19, 0xb0, 0x0b, 0x14, 0xbe, 0x14, 0x24, 0x2c, 0x38, 
+    0x0f, 0x1b, 0x34, 0x78, 0xec, 0x7a, 0x17, 0x01, 0x77, 0x7a, 0x27, 0x01, 0x87, 0x02, 0x5c, 0x8a, 
+    0x7e, 0x14, 0x20, 0x2d, 0x80, 0xeb, 
+
+// Segment #15, Start Address 00ff4000, Length 13109
+0xff,0x00,0x00,0x40,0x35,0x33,
+    0x7e, 0x04, 0x00, 0x01, 0x7e, 0x14, 0x7f, 0xf8, 0x7e, 0x24, 0x00, 0xfe, 0x7d, 0x31, 0x0b, 0x1a, 
+    0x50, 0x1b, 0x0a, 0x50, 0x7e, 0x14, 0x40, 0x1b, 0x02, 0x40, 0x74, 0x7e, 0xf8, 0x00, 0x59, 0x75, 
+    0xb0, 0xdf, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x90, 0x00, 0x7e, 0xf4, 0x40, 0x30, 0x02, 0x40, 0x8b, 
+    0x12, 0x74, 0x4e, 0xf5, 0x2e, 0x7a, 0xa1, 0x2d, 0x7a, 0x11, 0x58, 0x12, 0x6b, 0x02, 0x12, 0x40, 
+    0xeb, 0x7e, 0xb3, 0x3f, 0xf1, 0x60, 0x03, 0x12, 0x43, 0x79, 0x12, 0x6b, 0xde, 0xd2, 0xaf, 0x02, 
+    0x30, 0x00, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x60, 0x7a, 0x1c, 0x00, 0x01, 0x89, 0x18, 
+    0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x2c, 0x35, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 
+    0x93, 0x00, 0x89, 0x08, 0x7e, 0x04, 0x00, 0xff, 0x7e, 0x18, 0x40, 0x82, 0x7a, 0x1c, 0x00, 0x01, 
+    0x89, 0x18, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x93, 0x00, 0x89, 0x08, 0x7e, 0x08, 0x00, 0x20, 0x7e, 
+    0x44, 0x04, 0x00, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0x9d, 0x02, 0x73, 0x50, 0x7e, 0x08, 0x01, 
+    0x59, 0x7e, 0x44, 0x2a, 0xdd, 0x7e, 0x40, 0x00, 0x7e, 0xe4, 0x40, 0xaf, 0x02, 0x73, 0x50, 0x7e, 
+    0x08, 0x00, 0x59, 0x7e, 0x44, 0x01, 0x00, 0x7e, 0x40, 0x53, 0x7e, 0xe4, 0x40, 0xc1, 0x02, 0x73, 
+    0x50, 0x75, 0x57, 0x01, 0x75, 0x56, 0x00, 0x7e, 0x04, 0x00, 0x08, 0x75, 0x54, 0x58, 0x75, 0x55, 
+    0x08, 0x75, 0x51, 0x08, 0x75, 0x53, 0x01, 0x75, 0x89, 0x01, 0x75, 0x8a, 0x01, 0x75, 0x8c, 0x00, 
+    0xd2, 0x8c, 0x7e, 0x04, 0x00, 0x02, 0x7a, 0x05, 0x42, 0x89, 0xf4, 0x75, 0xb7, 0x7f, 0x75, 0xb8, 
+    0x7f, 0x75, 0xb3, 0x01, 0x75, 0xb2, 0x01, 0xd2, 0xa9, 0x22, 0x75, 0xb0, 0xdf, 0xe4, 0xd5, 0xe0, 
+    0xfd, 0x75, 0xb0, 0xef, 0x7e, 0x24, 0x80, 0x00, 0x7e, 0x11, 0x2e, 0x7e, 0xa0, 0x08, 0x19, 0xa2, 
+    0x00, 0x10, 0x2e, 0x24, 0x01, 0x00, 0xa5, 0xd9, 0xf2, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x83, 0x0b, 
+    0x20, 0xbe, 0x21, 0x2e, 0x78, 0xf6, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0x74, 0xbf, 0x19, 
+    0xb0, 0x00, 0x0c, 0x74, 0x10, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x80, 0x19, 0xb0, 0x00, 0x0c, 0x7e, 
+    0x54, 0x00, 0x02, 0x19, 0xa0, 0x00, 0x04, 0x19, 0xb0, 0x00, 0x00, 0x74, 0x03, 0x19, 0xb0, 0x00, 
+    0x0c, 0x74, 0x07, 0x20, 0x68, 0x02, 0x74, 0x0f, 0x19, 0xb0, 0x00, 0x04, 0x30, 0x6b, 0x17, 0x74, 
+    0xbf, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0x28, 0x20, 0x68, 0x02, 0x74, 0x20, 0x19, 0xb0, 0x00, 0x04, 
+    0x74, 0x03, 0x19, 0xb0, 0x00, 0x0c, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x74, 0x0c, 0x19, 0xb0, 
+    0x00, 0x10, 0x22, 0x7e, 0x04, 0x80, 0x00, 0x4c, 0x02, 0xe4, 0x19, 0xb0, 0x00, 0x04, 0x09, 0xb0, 
+    0x00, 0x10, 0x54, 0x08, 0x19, 0xb0, 0x00, 0x10, 0x74, 0xa7, 0x19, 0xb0, 0x00, 0x08, 0x22, 0x7c, 
+    0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x41, 0xaa, 0x89, 0x24, 0x41, 0xba, 0x41, 0xd7, 0x41, 0xf4, 
+    0x42, 0x11, 0x42, 0x2e, 0x42, 0x4b, 0x42, 0x68, 0x42, 0x85, 0xc2, 0x10, 0xc2, 0x18, 0xc2, 0x08, 
+    0x7e, 0x04, 0x04, 0x2d, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 0x01, 0x69, 0x6d, 0x00, 0x7a, 0x07, 
+    0x01, 0x79, 0x7a, 0x07, 0x01, 0x89, 0x22, 0xc2, 0x11, 0xc2, 0x19, 0xc2, 0x09, 0x7e, 0x04, 0x08, 
+    0x2d, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7b, 0x7a, 
+    0x07, 0x01, 0x8b, 0x22, 0xc2, 0x12, 0xc2, 0x1a, 0xc2, 0x0a, 0x7e, 0x04, 0x0c, 0x2d, 0x7a, 0x07, 
+    0x01, 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7d, 0x7a, 0x07, 0x01, 0x8d, 
+    0x22, 0xc2, 0x13, 0xc2, 0x1b, 0xc2, 0x0b, 0x7e, 0x04, 0x10, 0x2d, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 
+    0x07, 0x01, 0x6f, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x7f, 0x7a, 0x07, 0x01, 0x8f, 0x22, 0xc2, 0x14, 
+    0xc2, 0x1c, 0xc2, 0x0c, 0x7e, 0x04, 0x14, 0x2d, 0x7a, 0x07, 0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 
+    0x6d, 0x00, 0x7a, 0x07, 0x01, 0x81, 0x7a, 0x07, 0x01, 0x91, 0x22, 0xc2, 0x15, 0xc2, 0x1d, 0xc2, 
+    0x0d, 0x7e, 0x04, 0x18, 0x2d, 0x7a, 0x07, 0x01, 0x63, 0x7a, 0x07, 0x01, 0x73, 0x6d, 0x00, 0x7a, 
+    0x07, 0x01, 0x83, 0x7a, 0x07, 0x01, 0x93, 0x22, 0xc2, 0x16, 0xc2, 0x1e, 0xc2, 0x0e, 0x7e, 0x04, 
+    0x1c, 0x2d, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x85, 
+    0x7a, 0x07, 0x01, 0x95, 0x22, 0xc2, 0x17, 0xc2, 0x1f, 0xc2, 0x0f, 0x7e, 0x04, 0x20, 0x2d, 0x7a, 
+    0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x6d, 0x00, 0x7a, 0x07, 0x01, 0x87, 0x7a, 0x07, 0x01, 
+    0x97, 0x22, 0x7c, 0xb2, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x42, 0xad, 0x89, 0x24, 0x42, 0xbd, 0x42, 
+    0xd4, 0x42, 0xeb, 0x43, 0x02, 0x43, 0x19, 0x43, 0x30, 0x43, 0x47, 0x43, 0x5e, 0x30, 0x40, 0x07, 
+    0x20, 0x58, 0x04, 0xc2, 0x28, 0x80, 0x0c, 0x30, 0x48, 0x07, 0x20, 0x50, 0x04, 0xc2, 0x28, 0x80, 
+    0x02, 0xd2, 0x28, 0x22, 0x30, 0x41, 0x07, 0x20, 0x59, 0x04, 0xc2, 0x29, 0x80, 0x0c, 0x30, 0x49, 
+    0x07, 0x20, 0x51, 0x04, 0xc2, 0x29, 0x80, 0x02, 0xd2, 0x29, 0x22, 0x30, 0x42, 0x07, 0x20, 0x5a, 
+    0x04, 0xc2, 0x2a, 0x80, 0x0c, 0x30, 0x4a, 0x07, 0x20, 0x52, 0x04, 0xc2, 0x2a, 0x80, 0x02, 0xd2, 
+    0x2a, 0x22, 0x30, 0x43, 0x07, 0x20, 0x5b, 0x04, 0xc2, 0x2b, 0x80, 0x0c, 0x30, 0x4b, 0x07, 0x20, 
+    0x53, 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2b, 0x22, 0x30, 0x44, 0x07, 0x20, 0x5c, 0x04, 0xc2, 
+    0x2c, 0x80, 0x0c, 0x30, 0x4c, 0x07, 0x20, 0x54, 0x04, 0xc2, 0x2c, 0x80, 0x02, 0xd2, 0x2c, 0x22, 
+    0x30, 0x45, 0x07, 0x20, 0x5d, 0x04, 0xc2, 0x2d, 0x80, 0x0c, 0x30, 0x4d, 0x07, 0x20, 0x55, 0x04, 
+    0xc2, 0x2d, 0x80, 0x02, 0xd2, 0x2d, 0x22, 0x30, 0x46, 0x07, 0x20, 0x5e, 0x04, 0xc2, 0x2e, 0x80, 
+    0x0c, 0x30, 0x4e, 0x07, 0x20, 0x56, 0x04, 0xc2, 0x2e, 0x80, 0x02, 0xd2, 0x2e, 0x22, 0x30, 0x47, 
+    0x07, 0x20, 0x5f, 0x04, 0xc2, 0x2f, 0x80, 0x0c, 0x30, 0x4f, 0x07, 0x20, 0x57, 0x04, 0xc2, 0x2f, 
+    0x80, 0x02, 0xd2, 0x2f, 0x22, 0x44, 0x66, 0x43, 0x8a, 0xbe, 0xb0, 0x02, 0x40, 0x01, 0x22, 0x23, 
+    0x0a, 0x5b, 0x49, 0x55, 0x43, 0x75, 0x99, 0x54, 0xd3, 0x22, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x94, 
+    0x00, 0x7a, 0xb3, 0x2c, 0x35, 0x12, 0x44, 0x7a, 0x7e, 0x04, 0x28, 0x2d, 0x7a, 0x07, 0x01, 0xc1, 
+    0x7a, 0x07, 0x01, 0xc3, 0x7e, 0x04, 0x24, 0x2d, 0x7a, 0x07, 0x01, 0xc7, 0x7a, 0x07, 0x01, 0xc9, 
+    0x7e, 0x04, 0x66, 0x7f, 0x7a, 0x05, 0x4b, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 
+    0xb3, 0x91, 0x1c, 0x74, 0x12, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x07, 0x74, 
+    0x1e, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x48, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x10, 0x7a, 0xb3, 0x91, 
+    0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 
+    0xb3, 0x91, 0x1c, 0x74, 0x14, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x07, 0x74, 
+    0x16, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x08, 0x7a, 0xb3, 0x91, 0x11, 0x74, 0x20, 0x7a, 0xb3, 0x91, 
+    0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 
+    0xb3, 0x91, 0x1c, 0x74, 0x16, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x07, 0x74, 
+    0x2f, 0x7a, 0xb3, 0x91, 0x10, 0x74, 0x48, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x10, 0x7a, 0xb3, 0x91, 
+    0x13, 0x74, 0x3f, 0x7a, 0xb3, 0x91, 0x14, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 0x74, 0x0f, 0x7a, 
+    0xb3, 0x91, 0x07, 0x12, 0x40, 0xfa, 0x7e, 0x20, 0x00, 0x12, 0x41, 0x9f, 0x0b, 0x20, 0xbe, 0x21, 
+    0x2e, 0x78, 0xf6, 0xd2, 0xa8, 0x22, 0x7e, 0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x2c, 
+    0x35, 0x12, 0x44, 0x7a, 0x75, 0xb0, 0xdf, 0xc2, 0xa8, 0x22, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 
+    0x74, 0x01, 0x7a, 0xb3, 0x91, 0x07, 0x7e, 0x20, 0x04, 0x7c, 0xb2, 0xc2, 0xd7, 0x13, 0x13, 0x13, 
+    0x13, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x74, 0x02, 0x7a, 0xb3, 0x91, 
+    0x12, 0xa5, 0xda, 0xe5, 0x22, 0xca, 0x09, 0x12, 0x30, 0x0e, 0x10, 0x01, 0x34, 0xd5, 0x51, 0x40, 
+    0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 
+    0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0xb3, 0x91, 0x07, 0x7e, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 
+    0x91, 0x04, 0x63, 0x53, 0x01, 0x7e, 0x00, 0x54, 0x2e, 0x01, 0x53, 0xa5, 0xe6, 0xf5, 0x51, 0x80, 
+    0x12, 0x20, 0x02, 0x1d, 0x75, 0x53, 0x00, 0x85, 0x54, 0x51, 0xd2, 0x02, 0x74, 0x03, 0x80, 0x0d, 
+    0x30, 0x02, 0x0e, 0xc2, 0x02, 0x7e, 0x00, 0x56, 0x2e, 0x01, 0x53, 0xa5, 0xe6, 0x7a, 0xb3, 0x90, 
+    0x00, 0xda, 0x09, 0x32, 0x45, 0x6f, 0x45, 0x8b, 0x45, 0xa7, 0x45, 0xc3, 0x45, 0xdf, 0x45, 0xfb, 
+    0x46, 0x17, 0x46, 0x33, 0xc0, 0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xc0, 0xf0, 0xca, 0x0b, 0xca, 0x1b, 
+    0xca, 0x2b, 0xd2, 0x01, 0x75, 0x2f, 0x89, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x90, 0x00, 0x60, 0x28, 
+    0x7e, 0x14, 0x80, 0x00, 0x7e, 0x00, 0x00, 0x13, 0x50, 0x13, 0xca, 0x0b, 0xca, 0x59, 0x7c, 0xb0, 
+    0x23, 0x0a, 0x2b, 0x49, 0x22, 0x45, 0x04, 0x99, 0x24, 0xda, 0x59, 0xda, 0x0b, 0xa5, 0x0a, 0xa5, 
+    0x08, 0xbe, 0x01, 0x2e, 0x78, 0xe1, 0x80, 0xd2, 0x30, 0x04, 0x05, 0xc2, 0x04, 0x12, 0x64, 0x86, 
+    0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0xd0, 0xf0, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x09, 
+    0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x80, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 
+    0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x61, 0xab, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 
+    0xe0, 0x14, 0x75, 0x2f, 0x81, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 
+    0x69, 0x52, 0x61, 0xeb, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 
+    0x82, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x62, 0x2b, 
+    0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x83, 0x12, 0x73, 0x35, 
+    0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x62, 0x6b, 0x89, 0x54, 0x22, 0x09, 
+    0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x84, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 
+    0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x62, 0xab, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 
+    0xe0, 0x14, 0x75, 0x2f, 0x85, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 
+    0x69, 0x52, 0x62, 0xeb, 0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 
+    0x86, 0x12, 0x73, 0x35, 0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0x2b, 
+    0x89, 0x54, 0x22, 0x09, 0xb1, 0x00, 0x08, 0x20, 0xe0, 0x14, 0x75, 0x2f, 0x87, 0x12, 0x73, 0x35, 
+    0x54, 0x3e, 0x0a, 0x5b, 0x7e, 0x44, 0x00, 0xff, 0x69, 0x52, 0x63, 0x6b, 0x89, 0x54, 0x22, 0x10, 
+    0x08, 0x01, 0x22, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x75, 0x2f, 0xa0, 0x12, 0x73, 0x35, 0x7e, 
+    0x14, 0x80, 0x00, 0x80, 0x06, 0x20, 0x28, 0x03, 0xd2, 0x08, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 
+    0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x49, 0x45, 0x30, 0x30, 0x06, 0x20, 0xe6, 
+    0x4f, 0xd2, 0x08, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x60, 0x7e, 0x37, 0x01, 0x79, 0x7e, 0x27, 0x01, 
+    0x99, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 0x05, 0x32, 0x7a, 0x37, 0x01, 
+    0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x08, 0x2c, 0x38, 0x68, 0x7a, 
+    0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 
+    0x69, 0xf0, 0x10, 0x60, 0xc4, 0x22, 0xc2, 0x60, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 
+    0x7e, 0x27, 0x01, 0x79, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x99, 0x28, 0x04, 
+    0x7e, 0x27, 0x01, 0x99, 0x7e, 0x37, 0x01, 0x79, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x32, 0x7a, 
+    0x05, 0x32, 0x7a, 0x37, 0x01, 0x79, 0x7e, 0x37, 0x01, 0x59, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 
+    0x08, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x59, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 
+    0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 
+    0x12, 0x73, 0x35, 0x9e, 0x44, 0x08, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x04, 0x2d, 
+    0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x59, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 
+    0x02, 0x46, 0xc2, 0x22, 0xd2, 0x08, 0x7e, 0x04, 0x04, 0x2d, 0x7a, 0x07, 0x01, 0x59, 0x7a, 0x07, 
+    0x01, 0x69, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 
+    0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 
+    0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xa9, 0x2e, 0x24, 0x00, 0x02, 0x2d, 
+    0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 
+    0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 
+    0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x00, 0x00, 0x2e, 0x27, 0x01, 0xa9, 0x1b, 0x38, 0x20, 
+    0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 
+    0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 0x0a, 0x09, 0xb1, 
+    0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 
+    0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x00, 0x00, 0x2e, 0x67, 0x01, 
+    0xa9, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 
+    0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 
+    0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 
+    0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x00, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 
+    0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 
+    0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 
+    0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 
+    0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 
+    0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 
+    0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 
+    0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 
+    0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 
+    0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x48, 0x1e, 0x75, 0x2f, 
+    0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x38, 
+    0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x10, 0x22, 0xda, 0xb8, 
+    0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x48, 0x1e, 0xda, 0xb8, 0x02, 0x49, 
+    0x45, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 
+    0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 
+    0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x50, 
+    0x80, 0x02, 0xc2, 0x50, 0x12, 0x42, 0xbd, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 
+    0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 
+    0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 
+    0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 
+    0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x48, 0x72, 0x75, 0x2f, 
+    0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x09, 0x01, 0x22, 
+    0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x75, 0x2f, 0xa1, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x81, 0x00, 
+    0x80, 0x06, 0x20, 0x29, 0x03, 0xd2, 0x09, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 
+    0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x4c, 0x72, 0x30, 0x31, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x09, 
+    0x22, 0x30, 0xe6, 0x02, 0xd2, 0x61, 0x7e, 0x37, 0x01, 0x7b, 0x7e, 0x27, 0x01, 0x9b, 0x9d, 0x32, 
+    0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 0x37, 0x01, 0x7b, 0x7e, 0x37, 
+    0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0c, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5b, 
+    0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 
+    0x61, 0xc4, 0x22, 0xc2, 0x61, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 
+    0x7b, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9b, 0x28, 0x04, 0x7e, 0x27, 0x01, 
+    0x9b, 0x7e, 0x37, 0x01, 0x7b, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x34, 0x7a, 0x05, 0x34, 0x7a, 
+    0x37, 0x01, 0x7b, 0x7e, 0x37, 0x01, 0x5b, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x0c, 0x2c, 0x38, 
+    0x13, 0x7a, 0x47, 0x01, 0x5b, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 
+    0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 
+    0x9e, 0x44, 0x0c, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x08, 0x2d, 0x7d, 0x24, 0x2d, 
+    0x43, 0x7a, 0x47, 0x01, 0x5b, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x49, 0xef, 
+    0x22, 0xd2, 0x09, 0x7e, 0x04, 0x08, 0x2d, 0x7a, 0x07, 0x01, 0x5b, 0x7a, 0x07, 0x01, 0x6b, 0x75, 
+    0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 
+    0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 
+    0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xab, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 
+    0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 
+    0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 
+    0x01, 0xc9, 0x7e, 0x24, 0x01, 0x00, 0x2e, 0x27, 0x01, 0xab, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 
+    0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 
+    0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 
+    0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 
+    0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x01, 0x00, 0x2e, 0x67, 0x01, 0xab, 0x9e, 0x24, 
+    0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 
+    0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 
+    0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 
+    0x0f, 0x23, 0x23, 0x23, 0x44, 0x01, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 
+    0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 
+    0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 
+    0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 
+    0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 
+    0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 
+    0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 
+    0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 
+    0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 
+    0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4b, 0x4b, 0x75, 0x2f, 0x99, 0x12, 0x73, 
+    0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x39, 0x0a, 0x09, 0xb1, 
+    0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x11, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 
+    0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x4b, 0x4b, 0xda, 0xb8, 0x02, 0x4c, 0x72, 0x09, 0xb1, 
+    0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 
+    0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x59, 
+    0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x51, 0x80, 0x02, 0xc2, 
+    0x51, 0x12, 0x42, 0xd4, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 
+    0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 
+    0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 
+    0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 
+    0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4b, 0x9f, 0x75, 0x2f, 0x95, 0x12, 0x73, 
+    0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0a, 0x01, 0x22, 0x20, 0x2a, 0x03, 
+    0xd2, 0x0a, 0x22, 0x75, 0x2f, 0xa2, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x82, 0x00, 0x80, 0x06, 0x20, 
+    0x2a, 0x03, 0xd2, 0x0a, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 
+    0x68, 0x03, 0x12, 0x4f, 0x9f, 0x30, 0x32, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0a, 0x22, 0x30, 0xe6, 
+    0x02, 0xd2, 0x62, 0x7e, 0x37, 0x01, 0x7d, 0x7e, 0x27, 0x01, 0x9d, 0x9d, 0x32, 0x40, 0x31, 0x7d, 
+    0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 0x7e, 0x37, 0x01, 0x5d, 0x7d, 
+    0x43, 0x2d, 0x42, 0xbe, 0x44, 0x10, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5d, 0x75, 0x2f, 0x94, 
+    0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x62, 0xc4, 0x22, 
+    0xc2, 0x62, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7d, 0xbe, 0x24, 
+    0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0x9d, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9d, 0x7e, 0x37, 
+    0x01, 0x7d, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x36, 0x7a, 0x05, 0x36, 0x7a, 0x37, 0x01, 0x7d, 
+    0x7e, 0x37, 0x01, 0x5d, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x10, 0x2c, 0x38, 0x13, 0x7a, 0x47, 
+    0x01, 0x5d, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 
+    0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x10, 
+    0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x0c, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 
+    0x01, 0x5d, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x4d, 0x1c, 0x22, 0xd2, 0x0a, 
+    0x7e, 0x04, 0x0c, 0x2d, 0x7a, 0x07, 0x01, 0x5d, 0x7a, 0x07, 0x01, 0x6d, 0x75, 0x2f, 0x94, 0x12, 
+    0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 
+    0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 
+    0xcb, 0x7e, 0x27, 0x01, 0xad, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 
+    0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 
+    0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 
+    0x24, 0x02, 0x00, 0x2e, 0x27, 0x01, 0xad, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 
+    0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 
+    0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 
+    0x00, 0x10, 0xd2, 0x12, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 
+    0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x02, 0x00, 0x2e, 0x67, 0x01, 0xad, 0x9e, 0x24, 0x00, 0x02, 0x40, 
+    0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 
+    0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 
+    0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 
+    0x23, 0x44, 0x02, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 
+    0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 
+    0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 
+    0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 
+    0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 
+    0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 
+    0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 
+    0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 
+    0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 
+    0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x4e, 0x78, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 
+    0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3a, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 
+    0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x12, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 
+    0x07, 0xca, 0xb8, 0x12, 0x4e, 0x78, 0xda, 0xb8, 0x02, 0x4f, 0x9f, 0x09, 0xb1, 0x00, 0x18, 0x7e, 
+    0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 
+    0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 0xc2, 
+    0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x12, 0x42, 
+    0xeb, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 
+    0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 
+    0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 
+    0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 
+    0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x4e, 0xcc, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 
+    0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0b, 0x01, 0x22, 0x20, 0x2b, 0x03, 0xd2, 0x0b, 0x22, 
+    0x75, 0x2f, 0xa3, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x83, 0x00, 0x80, 0x06, 0x20, 0x2b, 0x03, 0xd2, 
+    0x0b, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 
+    0x52, 0xcc, 0x30, 0x33, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0b, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x63, 
+    0x7e, 0x37, 0x01, 0x7f, 0x7e, 0x27, 0x01, 0x9f, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 
+    0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 0x5f, 0x7d, 0x43, 0x2d, 0x42, 
+    0xbe, 0x44, 0x14, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x5f, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 
+    0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x63, 0xc4, 0x22, 0xc2, 0x63, 0x2d, 
+    0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x7f, 0xbe, 0x24, 0x00, 0x00, 0x68, 
+    0x6a, 0xbe, 0x27, 0x01, 0x9f, 0x28, 0x04, 0x7e, 0x27, 0x01, 0x9f, 0x7e, 0x37, 0x01, 0x7f, 0x9d, 
+    0x32, 0x7d, 0x02, 0x2e, 0x05, 0x38, 0x7a, 0x05, 0x38, 0x7a, 0x37, 0x01, 0x7f, 0x7e, 0x37, 0x01, 
+    0x5f, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x14, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x5f, 0x75, 
+    0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 
+    0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x14, 0x2d, 0x9d, 0x24, 
+    0x12, 0x69, 0xf0, 0x7e, 0x34, 0x10, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x5f, 0x12, 
+    0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x50, 0x49, 0x22, 0xd2, 0x0b, 0x7e, 0x04, 0x10, 
+    0x2d, 0x7a, 0x07, 0x01, 0x5f, 0x7a, 0x07, 0x01, 0x6f, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 
+    0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 
+    0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 
+    0x01, 0xaf, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 
+    0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 
+    0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x03, 0x00, 
+    0x2e, 0x27, 0x01, 0xaf, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 
+    0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 
+    0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 
+    0x13, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 
+    0x7e, 0x64, 0x03, 0x00, 0x2e, 0x67, 0x01, 0xaf, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 
+    0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 
+    0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 
+    0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x03, 
+    0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 
+    0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 
+    0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 
+    0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 
+    0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 
+    0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 
+    0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 
+    0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 
+    0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 
+    0x78, 0xe7, 0x02, 0x51, 0xa5, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 
+    0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3b, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 
+    0x00, 0x10, 0xd2, 0x13, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 
+    0x12, 0x51, 0xa5, 0xda, 0xb8, 0x02, 0x52, 0xcc, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 
+    0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 
+    0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, 0x53, 0x12, 0x43, 0x02, 0x02, 0x61, 
+    0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 
+    0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 
+    0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 
+    0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 
+    0xdb, 0x22, 0x02, 0x51, 0xf9, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 
+    0x73, 0x35, 0x22, 0x10, 0x0c, 0x01, 0x22, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x75, 0x2f, 0xa4, 
+    0x12, 0x73, 0x35, 0x7e, 0x14, 0x84, 0x00, 0x80, 0x06, 0x20, 0x2c, 0x03, 0xd2, 0x0c, 0x22, 0x09, 
+    0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x55, 0xf9, 0x30, 
+    0x34, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0c, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x64, 0x7e, 0x37, 0x01, 
+    0x81, 0x7e, 0x27, 0x01, 0xa1, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3a, 0x7a, 0x05, 
+    0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x18, 
+    0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 
+    0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x64, 0xc4, 0x22, 0xc2, 0x64, 0x2d, 0x23, 0x68, 0x78, 
+    0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x81, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 
+    0x01, 0xa1, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa1, 0x7e, 0x37, 0x01, 0x81, 0x9d, 0x32, 0x7d, 0x02, 
+    0x2e, 0x05, 0x3a, 0x7a, 0x05, 0x3a, 0x7a, 0x37, 0x01, 0x81, 0x7e, 0x37, 0x01, 0x61, 0x7d, 0x43, 
+    0x2d, 0x42, 0xbe, 0x44, 0x18, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x61, 0x75, 0x2f, 0x94, 0x12, 
+    0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 
+    0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x18, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 
+    0x7e, 0x34, 0x14, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x61, 0x12, 0x69, 0xf0, 0xbe, 
+    0x25, 0x20, 0x78, 0x03, 0x02, 0x53, 0x76, 0x22, 0xd2, 0x0c, 0x7e, 0x04, 0x14, 0x2d, 0x7a, 0x07, 
+    0x01, 0x61, 0x7a, 0x07, 0x01, 0x71, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 
+    0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 
+    0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb1, 0x2e, 
+    0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 
+    0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 
+    0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x04, 0x00, 0x2e, 0x27, 0x01, 
+    0xb1, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 
+    0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 
+    0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x14, 0x22, 0x80, 
+    0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x04, 
+    0x00, 0x2e, 0x67, 0x01, 0xb1, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 
+    0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 
+    0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 
+    0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x04, 0x7a, 0x69, 0xb0, 
+    0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 
+    0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 
+    0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 
+    0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 
+    0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 
+    0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 
+    0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 
+    0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 
+    0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 
+    0x54, 0xd2, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 
+    0x00, 0x04, 0x30, 0x3c, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 
+    0x14, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x54, 0xd2, 
+    0xda, 0xb8, 0x02, 0x55, 0xf9, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 
+    0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 
+    0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 0x54, 0x12, 0x43, 0x19, 0x02, 0x61, 0x13, 0x75, 0x2f, 
+    0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 
+    0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 
+    0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 
+    0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 
+    0x55, 0x26, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 
+    0x10, 0x0d, 0x01, 0x22, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x75, 0x2f, 0xa5, 0x12, 0x73, 0x35, 
+    0x7e, 0x14, 0x85, 0x00, 0x80, 0x06, 0x20, 0x2d, 0x03, 0xd2, 0x0d, 0x22, 0x09, 0xb1, 0x00, 0x14, 
+    0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x59, 0x26, 0x30, 0x35, 0x06, 0x20, 
+    0xe6, 0x4f, 0xd2, 0x0d, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x65, 0x7e, 0x37, 0x01, 0x83, 0x7e, 0x27, 
+    0x01, 0xa3, 0x9d, 0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 0x7a, 0x05, 0x3c, 0x7a, 0x37, 
+    0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x1c, 0x2c, 0x38, 0x68, 
+    0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 
+    0x12, 0x69, 0xf0, 0x10, 0x65, 0xc4, 0x22, 0xc2, 0x65, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 
+    0x1a, 0x7e, 0x27, 0x01, 0x83, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa3, 0x28, 
+    0x04, 0x7e, 0x27, 0x01, 0xa3, 0x7e, 0x37, 0x01, 0x83, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3c, 
+    0x7a, 0x05, 0x3c, 0x7a, 0x37, 0x01, 0x83, 0x7e, 0x37, 0x01, 0x63, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 
+    0x44, 0x1c, 0x2c, 0x38, 0x13, 0x7a, 0x47, 0x01, 0x63, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 
+    0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 
+    0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x1c, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x18, 
+    0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0x63, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 
+    0x03, 0x02, 0x56, 0xa3, 0x22, 0xd2, 0x0d, 0x7e, 0x04, 0x18, 0x2d, 0x7a, 0x07, 0x01, 0x63, 0x7a, 
+    0x07, 0x01, 0x73, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 
+    0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 
+    0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb3, 0x2e, 0x24, 0x00, 0x02, 
+    0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 
+    0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 
+    0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 0x7e, 0x24, 0x05, 0x00, 0x2e, 0x27, 0x01, 0xb3, 0x1b, 0x38, 
+    0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 
+    0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3d, 0x0a, 0x09, 
+    0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0x80, 0x7f, 0x7a, 0x51, 
+    0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x05, 0x00, 0x2e, 0x67, 
+    0x01, 0xb3, 0x9e, 0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 
+    0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 
+    0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 
+    0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x05, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 
+    0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 
+    0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 
+    0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 
+    0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 
+    0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 
+    0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 
+    0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 
+    0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 
+    0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x57, 0xff, 0x75, 
+    0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 
+    0x3d, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x15, 0x22, 0xda, 
+    0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x57, 0xff, 0xda, 0xb8, 0x02, 
+    0x59, 0x26, 0x09, 0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 
+    0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 
+    0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 
+    0x55, 0x80, 0x02, 0xc2, 0x55, 0x12, 0x43, 0x30, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 
+    0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 
+    0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 
+    0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 
+    0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x58, 0x53, 0x75, 
+    0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0e, 0x01, 
+    0x22, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x75, 0x2f, 0xa6, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x86, 
+    0x00, 0x80, 0x06, 0x20, 0x2e, 0x03, 0xd2, 0x0e, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 
+    0xb0, 0x1e, 0xda, 0xb8, 0x68, 0x03, 0x12, 0x5c, 0x53, 0x30, 0x36, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 
+    0x0e, 0x22, 0x30, 0xe6, 0x02, 0xd2, 0x66, 0x7e, 0x37, 0x01, 0x85, 0x7e, 0x27, 0x01, 0xa5, 0x9d, 
+    0x32, 0x40, 0x31, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 0x7a, 0x37, 0x01, 0x85, 0x7e, 
+    0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x20, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 
+    0x65, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 
+    0x10, 0x66, 0xc4, 0x22, 0xc2, 0x66, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 
+    0x01, 0x85, 0xbe, 0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa5, 0x28, 0x04, 0x7e, 0x27, 
+    0x01, 0xa5, 0x7e, 0x37, 0x01, 0x85, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x3e, 0x7a, 0x05, 0x3e, 
+    0x7a, 0x37, 0x01, 0x85, 0x7e, 0x37, 0x01, 0x65, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x20, 0x2c, 
+    0x38, 0x13, 0x7a, 0x47, 0x01, 0x65, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 
+    0x73, 0x35, 0x02, 0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 
+    0x35, 0x9e, 0x44, 0x20, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x1c, 0x2d, 0x7d, 0x24, 
+    0x2d, 0x43, 0x7a, 0x47, 0x01, 0x65, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x59, 
+    0xd0, 0x22, 0xd2, 0x0e, 0x7e, 0x04, 0x1c, 0x2d, 0x7a, 0x07, 0x01, 0x65, 0x7a, 0x07, 0x01, 0x75, 
+    0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 
+    0x12, 0x73, 0x35, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 
+    0x68, 0x7e, 0x37, 0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb5, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 
+    0x34, 0x04, 0x00, 0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 
+    0xcb, 0x7e, 0x37, 0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 
+    0x47, 0x01, 0xc9, 0x7e, 0x24, 0x06, 0x00, 0x2e, 0x27, 0x01, 0xb5, 0x1b, 0x38, 0x20, 0x0b, 0x35, 
+    0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 
+    0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 0xb1, 0x00, 0x10, 
+    0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 
+    0x35, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x06, 0x00, 0x2e, 0x67, 0x01, 0xb5, 0x9e, 
+    0x24, 0x00, 0x02, 0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 
+    0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 
+    0x34, 0x24, 0x2d, 0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 
+    0x54, 0x0f, 0x23, 0x23, 0x23, 0x44, 0x06, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 
+    0x2f, 0x93, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 
+    0x07, 0x01, 0xc9, 0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 
+    0x7a, 0x35, 0x30, 0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 
+    0x24, 0x2d, 0x80, 0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 
+    0x7e, 0x07, 0x01, 0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 
+    0x7e, 0x44, 0x28, 0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 
+    0xbd, 0x04, 0x68, 0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 
+    0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 
+    0x7a, 0x09, 0xb0, 0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5b, 0x2c, 0x75, 0x2f, 0x99, 0x12, 
+    0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3e, 0x0a, 0x09, 
+    0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x16, 0x22, 0xda, 0xb8, 0x30, 0xe0, 
+    0xd8, 0xbd, 0x32, 0x68, 0x07, 0xca, 0xb8, 0x12, 0x5b, 0x2c, 0xda, 0xb8, 0x02, 0x5c, 0x53, 0x09, 
+    0xb1, 0x00, 0x18, 0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 
+    0x35, 0xa5, 0xfd, 0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 
+    0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 0x02, 
+    0xc2, 0x56, 0x12, 0x43, 0x47, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 
+    0x00, 0x14, 0x7a, 0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 
+    0x02, 0x61, 0x13, 0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 
+    0x5e, 0xb0, 0x1c, 0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 
+    0x36, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5b, 0x80, 0x75, 0x2f, 0x95, 0x12, 
+    0x73, 0x35, 0x22, 0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x10, 0x0f, 0x01, 0x22, 0x20, 0x2f, 
+    0x03, 0xd2, 0x0f, 0x22, 0x75, 0x2f, 0xa7, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x87, 0x00, 0x80, 0x06, 
+    0x20, 0x2f, 0x03, 0xd2, 0x0f, 0x22, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x5e, 0xb0, 0x1e, 0xda, 
+    0xb8, 0x68, 0x03, 0x12, 0x5f, 0x80, 0x30, 0x37, 0x06, 0x20, 0xe6, 0x4f, 0xd2, 0x0f, 0x22, 0x30, 
+    0xe6, 0x02, 0xd2, 0x67, 0x7e, 0x37, 0x01, 0x87, 0x7e, 0x27, 0x01, 0xa7, 0x9d, 0x32, 0x40, 0x31, 
+    0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 0x87, 0x7e, 0x37, 0x01, 0x67, 
+    0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x24, 0x2c, 0x38, 0x68, 0x7a, 0x47, 0x01, 0x67, 0x75, 0x2f, 
+    0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x69, 0xf0, 0x10, 0x67, 0xc4, 
+    0x22, 0xc2, 0x67, 0x2d, 0x23, 0x68, 0x78, 0x6d, 0x33, 0x80, 0x1a, 0x7e, 0x27, 0x01, 0x87, 0xbe, 
+    0x24, 0x00, 0x00, 0x68, 0x6a, 0xbe, 0x27, 0x01, 0xa7, 0x28, 0x04, 0x7e, 0x27, 0x01, 0xa7, 0x7e, 
+    0x37, 0x01, 0x87, 0x9d, 0x32, 0x7d, 0x02, 0x2e, 0x05, 0x40, 0x7a, 0x05, 0x40, 0x7a, 0x37, 0x01, 
+    0x87, 0x7e, 0x37, 0x01, 0x67, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x24, 0x2c, 0x38, 0x13, 0x7a, 
+    0x47, 0x01, 0x67, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x02, 
+    0x69, 0xf0, 0x75, 0x2f, 0x94, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 
+    0x24, 0x2d, 0x9d, 0x24, 0x12, 0x69, 0xf0, 0x7e, 0x34, 0x20, 0x2d, 0x7d, 0x24, 0x2d, 0x43, 0x7a, 
+    0x47, 0x01, 0x67, 0x12, 0x69, 0xf0, 0xbe, 0x25, 0x20, 0x78, 0x03, 0x02, 0x5c, 0xfd, 0x22, 0xd2, 
+    0x0f, 0x7e, 0x04, 0x20, 0x2d, 0x7a, 0x07, 0x01, 0x67, 0x7a, 0x07, 0x01, 0x77, 0x75, 0x2f, 0x94, 
+    0x12, 0x73, 0x35, 0x75, 0x2f, 0x00, 0x12, 0x73, 0x35, 0x22, 0x75, 0x2f, 0x92, 0x12, 0x73, 0x35, 
+    0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0xca, 0xb8, 0x54, 0x82, 0xda, 0xb8, 0x78, 0x68, 0x7e, 0x37, 
+    0x01, 0xcb, 0x7e, 0x27, 0x01, 0xb7, 0x2e, 0x24, 0x00, 0x02, 0x2d, 0x32, 0xbe, 0x34, 0x04, 0x00, 
+    0x38, 0x34, 0x7d, 0x02, 0x2e, 0x05, 0x30, 0x7a, 0x05, 0x30, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 
+    0x01, 0xc9, 0x7d, 0x43, 0x2d, 0x42, 0xbe, 0x44, 0x28, 0x2c, 0x38, 0x3c, 0x7a, 0x47, 0x01, 0xc9, 
+    0x7e, 0x24, 0x07, 0x00, 0x2e, 0x27, 0x01, 0xb7, 0x1b, 0x38, 0x20, 0x0b, 0x35, 0x7a, 0x51, 0x2f, 
+    0x12, 0x73, 0x35, 0x02, 0x6a, 0x63, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x04, 
+    0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 0x54, 0xfe, 0x19, 
+    0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0x80, 0x7f, 0x7a, 0x51, 0x2f, 0x12, 0x73, 0x35, 0x9e, 0x44, 
+    0x28, 0x2d, 0x9d, 0x24, 0x7e, 0x64, 0x07, 0x00, 0x2e, 0x67, 0x01, 0xb7, 0x9e, 0x24, 0x00, 0x02, 
+    0x40, 0x17, 0x1b, 0x38, 0x60, 0x0b, 0x35, 0x12, 0x6a, 0x63, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 0x24, 
+    0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc9, 0x02, 0x6a, 0x63, 0x7a, 0x39, 0xc0, 0x7e, 0x34, 0x24, 0x2d, 
+    0x7a, 0x39, 0xd0, 0x0b, 0x34, 0x1b, 0x44, 0x80, 0xe5, 0x9d, 0x32, 0x7c, 0xb6, 0x54, 0x0f, 0x23, 
+    0x23, 0x23, 0x44, 0x07, 0x7a, 0x69, 0xb0, 0x7a, 0x79, 0x70, 0x0b, 0x35, 0x75, 0x2f, 0x93, 0x12, 
+    0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0xbd, 0x04, 0x68, 0x2b, 0x7a, 0x07, 0x01, 0xc9, 
+    0x7e, 0x47, 0x01, 0xcb, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xcb, 0x2e, 0x35, 0x30, 0x7a, 0x35, 0x30, 
+    0x22, 0xd2, 0x04, 0x09, 0xb1, 0x00, 0x14, 0x20, 0xe0, 0x13, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 
+    0x28, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0x2a, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xcf, 0x7e, 0x07, 0x01, 
+    0xcb, 0x7e, 0x24, 0x03, 0xfe, 0x9d, 0x20, 0x28, 0x40, 0x7e, 0x07, 0x01, 0xc9, 0x7e, 0x44, 0x28, 
+    0x2d, 0x7d, 0x60, 0x0b, 0x04, 0xbd, 0x04, 0x68, 0xd2, 0x7d, 0x70, 0x0b, 0x04, 0xbd, 0x04, 0x68, 
+    0xd0, 0x7d, 0x54, 0x9d, 0x50, 0xbd, 0x25, 0x40, 0x02, 0x7d, 0x25, 0x7d, 0x32, 0x09, 0xb1, 0x00, 
+    0x14, 0xca, 0xb8, 0x54, 0x1f, 0xb4, 0x01, 0x31, 0xda, 0xb8, 0x7e, 0x19, 0xb0, 0x7a, 0x09, 0xb0, 
+    0x0b, 0x04, 0x1b, 0x24, 0x78, 0xe7, 0x02, 0x5e, 0x59, 0x75, 0x2f, 0x99, 0x12, 0x73, 0x35, 0x09, 
+    0xb1, 0x00, 0x04, 0x54, 0xfa, 0x19, 0xb1, 0x00, 0x04, 0x30, 0x3f, 0x0a, 0x09, 0xb1, 0x00, 0x10, 
+    0x54, 0xfe, 0x19, 0xb1, 0x00, 0x10, 0xd2, 0x17, 0x22, 0xda, 0xb8, 0x30, 0xe0, 0xd8, 0xbd, 0x32, 
+    0x68, 0x07, 0xca, 0xb8, 0x12, 0x5e, 0x59, 0xda, 0xb8, 0x02, 0x5f, 0x80, 0x09, 0xb1, 0x00, 0x18, 
+    0x7e, 0xa0, 0x88, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 0x73, 0x35, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x0a, 0x68, 0x1d, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 
+    0xc2, 0x5f, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x12, 
+    0x43, 0x5e, 0x02, 0x61, 0x13, 0x75, 0x2f, 0x91, 0x12, 0x73, 0x35, 0x09, 0xb1, 0x00, 0x14, 0x7a, 
+    0xb1, 0x2f, 0x12, 0x73, 0x35, 0x20, 0xe0, 0x08, 0xd2, 0x04, 0x7e, 0xa0, 0x80, 0x02, 0x61, 0x13, 
+    0xd2, 0x04, 0x30, 0xe1, 0x06, 0x7e, 0xa0, 0x80, 0x12, 0x61, 0x13, 0xca, 0xb8, 0x5e, 0xb0, 0x1c, 
+    0xda, 0xb8, 0x68, 0x12, 0x7e, 0xa0, 0xc0, 0x09, 0x61, 0x00, 0x00, 0x12, 0x61, 0x36, 0x09, 0xb1, 
+    0x00, 0x14, 0x20, 0xe0, 0xdb, 0x22, 0x02, 0x5e, 0xad, 0x75, 0x2f, 0x95, 0x12, 0x73, 0x35, 0x22, 
+    0x75, 0x2f, 0x96, 0x12, 0x73, 0x35, 0x22, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 
+    0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x58, 0x80, 0x02, 0xc2, 0x58, 
+    0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x50, 0x80, 0x02, 0xc2, 0x50, 0x02, 0x60, 0xff, 
+    0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 
+    0x20, 0x68, 0x04, 0xd2, 0x59, 0x80, 0x02, 0xc2, 0x59, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 
+    0xd2, 0x51, 0x80, 0x02, 0xc2, 0x51, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 
+    0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5a, 0x80, 0x02, 
+    0xc2, 0x5a, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x52, 0x80, 0x02, 0xc2, 0x52, 0x02, 
+    0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 
+    0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5b, 0x80, 0x02, 0xc2, 0x5b, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 
+    0x68, 0x04, 0xd2, 0x53, 0x80, 0x02, 0xc2, 0x53, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 
+    0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5c, 
+    0x80, 0x02, 0xc2, 0x5c, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x54, 0x80, 0x02, 0xc2, 
+    0x54, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 
+    0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5d, 0x80, 0x02, 0xc2, 0x5d, 0xa5, 0xfd, 0x5e, 
+    0x50, 0x80, 0x68, 0x04, 0xd2, 0x55, 0x80, 0x02, 0xc2, 0x55, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 
+    0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 
+    0xd2, 0x5e, 0x80, 0x02, 0xc2, 0x5e, 0xa5, 0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x56, 0x80, 
+    0x02, 0xc2, 0x56, 0x02, 0x60, 0xff, 0x7c, 0x02, 0x7e, 0x14, 0x80, 0x00, 0x4c, 0x20, 0x09, 0xb1, 
+    0x00, 0x18, 0xa5, 0xfd, 0x5e, 0x50, 0x20, 0x68, 0x04, 0xd2, 0x5f, 0x80, 0x02, 0xc2, 0x5f, 0xa5, 
+    0xfd, 0x5e, 0x50, 0x80, 0x68, 0x04, 0xd2, 0x57, 0x80, 0x02, 0xc2, 0x57, 0x02, 0x60, 0xff, 0x54, 
+    0xf0, 0xc4, 0xa5, 0xff, 0xc4, 0xa5, 0x4f, 0x75, 0x2f, 0x90, 0x12, 0x73, 0x35, 0xf5, 0x2f, 0x12, 
+    0x73, 0x35, 0x22, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x2c, 0x2d, 0xca, 0x79, 
+    0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x02, 0x7e, 
+    0x64, 0x00, 0x02, 0x02, 0x61, 0x5e, 0xca, 0x19, 0x5e, 0x20, 0x07, 0x4c, 0xa2, 0x7e, 0x74, 0x2c, 
+    0x2d, 0xca, 0x79, 0x7a, 0x79, 0xa0, 0x0b, 0x74, 0x7a, 0x79, 0xb0, 0x0b, 0x74, 0x7a, 0x79, 0x60, 
+    0x0b, 0x74, 0xda, 0x79, 0x7e, 0x30, 0x03, 0x7e, 0x64, 0x00, 0x03, 0x02, 0x61, 0x5e, 0xd2, 0x04, 
+    0x7e, 0x27, 0x01, 0xcb, 0x2d, 0x26, 0xbe, 0x24, 0x04, 0x00, 0x38, 0x2e, 0x7e, 0x07, 0x01, 0xc9, 
+    0x7e, 0x44, 0x28, 0x2d, 0x7e, 0x79, 0xa0, 0x7a, 0x09, 0xa0, 0x0b, 0x04, 0x0b, 0x74, 0xbd, 0x04, 
+    0x68, 0x23, 0xa5, 0xdb, 0xef, 0x7a, 0x27, 0x01, 0xcb, 0x7e, 0x25, 0x30, 0x2d, 0x26, 0x7a, 0x25, 
+    0x30, 0x7a, 0x07, 0x01, 0xc9, 0xda, 0x19, 0xc2, 0xd7, 0x22, 0x75, 0x2f, 0x9a, 0x12, 0x73, 0x35, 
+    0xda, 0x19, 0xd2, 0xd7, 0x22, 0x7e, 0x04, 0x24, 0x2d, 0x80, 0xd7, 0x48, 0xf1, 0x46, 0x65, 0x47, 
+    0x5f, 0x49, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x48, 0x56, 0x45, 0x2a, 0x49, 0x6e, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x49, 0x75, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4c, 0x1e, 0x49, 0x92, 0x4a, 
+    0x8c, 0x4c, 0x57, 0x45, 0x2a, 0x45, 0x2a, 0x4b, 0x83, 0x45, 0x2a, 0x4c, 0x9b, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4c, 0xa2, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4f, 0x4b, 0x4c, 0xbf, 0x4d, 
+    0xb9, 0x4f, 0x84, 0x45, 0x2a, 0x45, 0x2a, 0x4e, 0xb0, 0x45, 0x2a, 0x4f, 0xc8, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x4f, 0xcf, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x52, 0x78, 0x4f, 0xec, 0x50, 
+    0xe6, 0x52, 0xb1, 0x45, 0x2a, 0x45, 0x2a, 0x51, 0xdd, 0x45, 0x2a, 0x52, 0xf5, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x52, 0xfc, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x55, 0xa5, 0x53, 0x19, 0x54, 
+    0x13, 0x55, 0xde, 0x45, 0x2a, 0x45, 0x2a, 0x55, 0x0a, 0x45, 0x2a, 0x56, 0x22, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x56, 0x29, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x58, 0xd2, 0x56, 0x46, 0x57, 
+    0x40, 0x59, 0x0b, 0x45, 0x2a, 0x45, 0x2a, 0x58, 0x37, 0x45, 0x2a, 0x59, 0x4f, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x59, 0x56, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5b, 0xff, 0x59, 0x73, 0x5a, 
+    0x6d, 0x5c, 0x38, 0x45, 0x2a, 0x45, 0x2a, 0x5b, 0x64, 0x45, 0x2a, 0x5c, 0x7c, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5c, 0x83, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5f, 0x2c, 0x5c, 0xa0, 0x5d, 
+    0x9a, 0x5f, 0x65, 0x45, 0x2a, 0x45, 0x2a, 0x5e, 0x91, 0x45, 0x2a, 0x5f, 0xa9, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x5f, 0xb0, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 
+    0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0x45, 0x2a, 0xca, 0xb8, 0x75, 0x2f, 0x02, 
+    0x12, 0x73, 0x35, 0x7e, 0xb3, 0x91, 0x03, 0x20, 0xe5, 0x20, 0x30, 0xe0, 0x05, 0x12, 0x6b, 0x05, 
+    0x80, 0x30, 0x30, 0xe1, 0x05, 0x12, 0x64, 0x86, 0x80, 0x28, 0x30, 0xe2, 0x05, 0x12, 0x63, 0xf5, 
+    0x80, 0x20, 0x30, 0xe3, 0x1d, 0x12, 0x65, 0x61, 0x80, 0x18, 0x7e, 0xb3, 0x91, 0x04, 0x30, 0xe1, 
+    0x03, 0x02, 0x67, 0x5f, 0x30, 0xe6, 0x05, 0x12, 0x6c, 0x6a, 0x80, 0x06, 0x20, 0xe2, 0x03, 0x02, 
+    0x00, 0x80, 0xda, 0xb8, 0x32, 0x75, 0x2f, 0x10, 0x12, 0x73, 0x35, 0xca, 0x0b, 0xca, 0x39, 0xca, 
+    0x59, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x1a, 0x6c, 0xaa, 0xbe, 0xb0, 0x40, 
+    0x28, 0x0a, 0x12, 0x64, 0x24, 0xda, 0x59, 0xda, 0x39, 0xda, 0x0b, 0x22, 0x74, 0x20, 0x7a, 0xb3, 
+    0x91, 0x14, 0x80, 0xf1, 0x7e, 0x37, 0x01, 0xc5, 0x2d, 0x35, 0xbe, 0x34, 0x04, 0x00, 0x38, 0x2f, 
+    0x7a, 0x37, 0x01, 0xc5, 0x7e, 0x37, 0x01, 0xc3, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 0x44, 0x2c, 0x2c, 
+    0x38, 0x25, 0x7a, 0x47, 0x01, 0xc3, 0x75, 0x2f, 0x11, 0x12, 0x73, 0x35, 0x7a, 0xb1, 0x2f, 0x12, 
+    0x73, 0x35, 0x12, 0x67, 0x9f, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x12, 0x66, 0x30, 0x22, 0x75, 
+    0x2f, 0x16, 0x12, 0x73, 0x35, 0x80, 0xf4, 0x75, 0x2f, 0x12, 0x12, 0x73, 0x35, 0x7a, 0xb1, 0x2f, 
+    0x12, 0x73, 0x35, 0x9e, 0x44, 0x2c, 0x2d, 0x9d, 0x54, 0x12, 0x67, 0x9f, 0x7e, 0x34, 0x28, 0x2d, 
+    0x7d, 0x54, 0x2d, 0x43, 0x80, 0xbc, 0x75, 0x2f, 0x18, 0x12, 0x73, 0x35, 0xca, 0x09, 0xca, 0x39, 
+    0xca, 0x2b, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0x63, 0x91, 0x1a, 0x74, 0x10, 0x7a, 0xb3, 
+    0x91, 0x14, 0x7e, 0xb0, 0x80, 0x9c, 0xb6, 0x60, 0x38, 0x6c, 0xaa, 0x7e, 0x37, 0x01, 0xcb, 0x9d, 
+    0x35, 0x40, 0x37, 0x7a, 0x37, 0x01, 0xcb, 0x7e, 0x37, 0x01, 0xc7, 0x7d, 0x43, 0x2d, 0x45, 0xbe, 
+    0x44, 0x28, 0x2c, 0x38, 0x3b, 0x7a, 0x47, 0x01, 0xc7, 0x7d, 0x45, 0x12, 0x68, 0xd4, 0x7e, 0xb3, 
+    0x91, 0x1e, 0x20, 0xe5, 0x13, 0x75, 0x2f, 0x19, 0x12, 0x73, 0x35, 0x7a, 0x91, 0x2f, 0x12, 0x73, 
+    0x35, 0xda, 0x2b, 0xda, 0x39, 0xda, 0x09, 0x22, 0x80, 0x34, 0x2d, 0x53, 0x6d, 0x33, 0x60, 0x02, 
+    0x80, 0xc1, 0x7e, 0x04, 0x24, 0x2d, 0x7a, 0x07, 0x01, 0xc9, 0x7a, 0x07, 0x01, 0xc7, 0x80, 0xe1, 
+    0xca, 0x59, 0x9e, 0x44, 0x28, 0x2d, 0x9d, 0x54, 0x12, 0x68, 0xd4, 0x7e, 0x34, 0x24, 0x2d, 0x7d, 
+    0x54, 0x2d, 0x43, 0x7a, 0x47, 0x01, 0xc7, 0x12, 0x68, 0xd4, 0xda, 0x49, 0x80, 0xb0, 0x7e, 0x0f, 
+    0x2c, 0x3e, 0x0b, 0x0c, 0x7a, 0x0f, 0x2c, 0x3e, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x1e, 0x74, 0x60, 
+    0x7a, 0xb3, 0x91, 0x1c, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0xa5, 0x7e, 0x2f, 0x2c, 0x5e, 
+    0x0b, 0x2c, 0x7a, 0x2f, 0x2c, 0x5e, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x1e, 0x74, 0x60, 0x7a, 0xb3, 
+    0x91, 0x1c, 0x74, 0x02, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0x1f, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 
+    0x22, 0x75, 0x2f, 0x28, 0x12, 0x73, 0x35, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0x74, 0x60, 0x7a, 
+    0xb3, 0x91, 0x00, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 0x91, 0x1a, 0x70, 0xdb, 0x7e, 
+    0x0d, 0x30, 0x7e, 0x1d, 0x34, 0x7e, 0x2d, 0x38, 0x7e, 0x3d, 0x3c, 0x7e, 0x85, 0x40, 0x7d, 0x90, 
+    0x4d, 0x91, 0x4d, 0x92, 0x4d, 0x93, 0x4d, 0x94, 0x4d, 0x95, 0x4d, 0x96, 0x4d, 0x97, 0x4d, 0x98, 
+    0x68, 0xb8, 0x7a, 0x13, 0x91, 0x17, 0x7a, 0x03, 0x91, 0x17, 0x7a, 0x33, 0x91, 0x17, 0x7a, 0x23, 
+    0x91, 0x17, 0x7a, 0x53, 0x91, 0x17, 0x7a, 0x43, 0x91, 0x17, 0x7a, 0x73, 0x91, 0x17, 0x7a, 0x63, 
+    0x91, 0x17, 0x7a, 0x93, 0x91, 0x17, 0x7a, 0x83, 0x91, 0x17, 0x30, 0x73, 0x22, 0x7a, 0xb3, 0x91, 
+    0x17, 0x7a, 0xa3, 0x91, 0x17, 0x7a, 0xd3, 0x91, 0x17, 0x7a, 0xc3, 0x91, 0x17, 0x7a, 0xf3, 0x91, 
+    0x17, 0x7a, 0xe3, 0x91, 0x17, 0x7d, 0x78, 0x7a, 0xf3, 0x91, 0x17, 0x7a, 0xe3, 0x91, 0x17, 0x7e, 
+    0xb3, 0x91, 0x1e, 0x30, 0xe5, 0x03, 0x02, 0x65, 0x3c, 0x75, 0x2f, 0x29, 0x12, 0x73, 0x35, 0x20, 
+    0x73, 0x08, 0x75, 0x2f, 0x0a, 0x12, 0x73, 0x35, 0x80, 0x06, 0x75, 0x2f, 0x12, 0x12, 0x73, 0x35, 
+    0x74, 0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x6d, 0x00, 0x7d, 0x10, 0x7a, 0x0d, 0x30, 0x7a, 0x0d, 0x34, 
+    0x7a, 0x0d, 0x38, 0x7a, 0x0d, 0x3c, 0x7a, 0x05, 0x40, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 
+    0x7e, 0x37, 0x01, 0xc5, 0x4d, 0x33, 0x68, 0x3b, 0x7e, 0x07, 0x01, 0xc1, 0x7e, 0x54, 0x2c, 0x2d, 
+    0x9d, 0x50, 0xbd, 0x35, 0x40, 0x02, 0x7d, 0x35, 0xca, 0x39, 0x7e, 0x65, 0x4b, 0x99, 0x64, 0xda, 
+    0x39, 0x7e, 0x07, 0x01, 0xc5, 0x9d, 0x03, 0x7a, 0x07, 0x01, 0xc5, 0x2e, 0x37, 0x01, 0xc1, 0x7a, 
+    0x37, 0x01, 0xc1, 0xbe, 0x34, 0x2c, 0x2c, 0x28, 0xc7, 0x7e, 0x34, 0x28, 0x2d, 0x7a, 0x37, 0x01, 
+    0xc1, 0x80, 0xbd, 0x22, 0x75, 0x2f, 0x53, 0x12, 0x73, 0x35, 0x7e, 0x15, 0x4d, 0x80, 0x11, 0x75, 
+    0x2f, 0x51, 0x12, 0x73, 0x35, 0x0b, 0x08, 0x10, 0x0b, 0x05, 0x9e, 0x34, 0x00, 0x02, 0x28, 0x4d, 
+    0x7c, 0xb2, 0x20, 0xe7, 0x27, 0x54, 0x07, 0x23, 0x0a, 0x2b, 0x49, 0x22, 0x39, 0x1e, 0x7c, 0xb2, 
+    0x54, 0x78, 0x03, 0x03, 0x03, 0x7c, 0x2b, 0x9d, 0x13, 0x40, 0x1a, 0x68, 0x12, 0x7a, 0x15, 0x4d, 
+    0x7a, 0x25, 0x4f, 0x7e, 0x64, 0x67, 0x09, 0x7a, 0x65, 0x4b, 0x89, 0x24, 0x02, 0x67, 0x17, 0x7e, 
+    0x64, 0x66, 0x7f, 0x80, 0xf2, 0x2d, 0x13, 0x9d, 0x31, 0xca, 0x39, 0x7d, 0x31, 0x2d, 0x10, 0xca, 
+    0x19, 0xca, 0x29, 0x99, 0x24, 0xda, 0x29, 0xda, 0x09, 0xda, 0x39, 0x80, 0xa2, 0x7a, 0x15, 0x4d, 
+    0x7e, 0x64, 0x66, 0xf5, 0x4d, 0x33, 0x78, 0x09, 0x7c, 0xb2, 0x20, 0xe7, 0x2a, 0x7e, 0x64, 0x66, 
+    0x74, 0x7a, 0x65, 0x4b, 0x22, 0x75, 0x2f, 0x52, 0x12, 0x73, 0x35, 0x7e, 0x21, 0x4d, 0x7e, 0x09, 
+    0x30, 0x0b, 0x04, 0x1b, 0x34, 0x78, 0x89, 0x80, 0xd4, 0x75, 0x2f, 0x54, 0x12, 0x73, 0x35, 0x7e, 
+    0x15, 0x4d, 0x7e, 0x25, 0x4f, 0x80, 0x90, 0x5e, 0x20, 0x07, 0x54, 0x78, 0x7e, 0x44, 0x67, 0x7d, 
+    0x30, 0xe6, 0x16, 0x4d, 0x33, 0x68, 0x26, 0x1b, 0x34, 0x7e, 0x09, 0x40, 0x0b, 0x04, 0x7e, 0x44, 
+    0x34, 0xfa, 0x20, 0xe3, 0x04, 0x7e, 0x44, 0x67, 0x85, 0xca, 0x09, 0xca, 0x39, 0x99, 0x44, 0xda, 
+    0x39, 0xda, 0x09, 0x7e, 0x64, 0x66, 0x7f, 0x4d, 0x33, 0x68, 0xa6, 0x89, 0x64, 0x7a, 0x15, 0x4d, 
+    0xf5, 0x4f, 0x7e, 0x64, 0x67, 0x58, 0x80, 0x99, 0x7e, 0x15, 0x4d, 0xe5, 0x4f, 0x80, 0xc4, 0xc0, 
+    0xd0, 0xc0, 0xd1, 0xc0, 0xe0, 0xca, 0x19, 0x75, 0x2f, 0xfe, 0x12, 0x73, 0x35, 0x7e, 0x14, 0x00, 
+    0x53, 0x02, 0x40, 0x52, 0xda, 0x19, 0xd0, 0xe0, 0xd0, 0xd1, 0xd0, 0xd0, 0x32, 0x03, 0xa5, 0xcb, 
+    0x19, 0xb1, 0x80, 0x00, 0x22, 0x22, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0x7e, 0xa0, 0x02, 0xa4, 
+    0x7e, 0x04, 0x68, 0xb1, 0x9d, 0x05, 0x7e, 0xb0, 0x28, 0x7a, 0xb3, 0x95, 0x00, 0x89, 0x04, 0xca, 
+    0x29, 0xb4, 0x80, 0xe2, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0x7e, 0x00, 0x28, 0x7a, 0x03, 0x95, 
+    0x00, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 0x29, 0x22, 0x7e, 0x24, 0x00, 0x00, 0x7f, 
+    0xe1, 0x7e, 0xa0, 0x02, 0xa4, 0x7e, 0x04, 0x69, 0xe6, 0x9d, 0x05, 0x7e, 0xb0, 0x38, 0x7a, 0xb3, 
+    0x95, 0x00, 0x89, 0x04, 0xca, 0x29, 0xb4, 0x80, 0xe2, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0x7e, 
+    0x00, 0x38, 0x7a, 0x03, 0x95, 0x00, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 0x29, 0x22, 
+    0xca, 0x29, 0xca, 0x19, 0xca, 0x58, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0xda, 0x58, 0x7e, 0x54, 
+    0x02, 0x20, 0x9c, 0xb5, 0xa4, 0x7e, 0x50, 0x30, 0x5e, 0x20, 0x07, 0x2c, 0x52, 0x7a, 0x53, 0x95, 
+    0x00, 0x2e, 0x54, 0x6a, 0x17, 0x89, 0x54, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 
+    0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 0x19, 
+    0xda, 0x29, 0x22, 0xca, 0x19, 0xca, 0x58, 0x7e, 0x24, 0x00, 0x00, 0x7f, 0xe1, 0xda, 0x58, 0x7e, 
+    0x54, 0x02, 0x38, 0x9c, 0xb5, 0xa4, 0x7e, 0x50, 0x20, 0x5e, 0x20, 0x07, 0x2c, 0x52, 0x7a, 0x53, 
+    0x95, 0x00, 0x2e, 0x54, 0x6a, 0x88, 0x89, 0x54, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 
+    0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0xe0, 0xa3, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x95, 0x00, 0xda, 
+    0x19, 0x22, 0x02, 0x6b, 0xa8, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 0xca, 0x3b, 0xca, 0x4b, 0xca, 
+    0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x2c, 
+    0x7f, 0xb4, 0x00, 0x02, 0x80, 0x1c, 0xb4, 0x01, 0x19, 0x7e, 0xb3, 0x91, 0x14, 0x54, 0x14, 0x68, 
+    0x05, 0x12, 0x6b, 0x6c, 0x80, 0x23, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x1c, 0x12, 0x6c, 0xaa, 
+    0x80, 0x17, 0x7e, 0xb3, 0x91, 0x14, 0x30, 0xe5, 0x05, 0x12, 0x6c, 0xaa, 0x80, 0x0b, 0x7e, 0xb3, 
+    0x91, 0x14, 0x54, 0x14, 0x68, 0x03, 0x12, 0x6b, 0x6c, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 
+    0x5b, 0xda, 0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x20, 0xe4, 0x19, 0x75, 
+    0x2f, 0x0a, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x7e, 0x70, 0x0a, 0x7e, 0xb3, 0x2c, 0x7f, 0xb4, 
+    0x01, 0x1f, 0x02, 0x6c, 0x04, 0x02, 0x71, 0xf2, 0x75, 0x2f, 0x0b, 0x12, 0x73, 0x35, 0x74, 0x14, 
+    0x7a, 0xb3, 0x91, 0x14, 0x7e, 0xb3, 0x2c, 0x7f, 0xb4, 0x02, 0x0c, 0x12, 0x6b, 0xb4, 0x02, 0x6b, 
+    0xa8, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0x7e, 0x00, 0x00, 0x7a, 0x03, 0x2c, 0x7f, 0x7a, 
+    0x03, 0x2c, 0x80, 0x22, 0x7e, 0xb3, 0x2c, 0x76, 0x54, 0x60, 0x60, 0x05, 0xb4, 0x40, 0x1e, 0x80, 
+    0x1c, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x05, 0x15, 0x75, 0x2f, 0x71, 0x12, 0x73, 0x35, 0x7e, 0xb3, 
+    0x2c, 0x79, 0x7e, 0xa0, 0x01, 0x7a, 0xa3, 0x91, 0x06, 0x7a, 0xb3, 0x91, 0x07, 0x22, 0x74, 0x00, 
+    0x7a, 0xb3, 0x91, 0x00, 0x74, 0x10, 0x7a, 0xb3, 0x91, 0x12, 0x22, 0xbe, 0x57, 0x2c, 0x7c, 0x28, 
+    0x04, 0x7e, 0x57, 0x2c, 0x7c, 0x7a, 0x0f, 0x2c, 0x82, 0x7a, 0x57, 0x2c, 0x86, 0x74, 0x10, 0x7a, 
+    0xb3, 0x91, 0x12, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x1a, 0x70, 0x53, 
+    0x7e, 0xb3, 0x91, 0x14, 0x20, 0xe4, 0x4c, 0x7e, 0xef, 0x2c, 0x82, 0x7e, 0xf7, 0x2c, 0x86, 0x7e, 
+    0x07, 0x2c, 0x86, 0x4d, 0x00, 0x68, 0x21, 0x7e, 0x00, 0x00, 0xe0, 0x7a, 0xb3, 0x91, 0x17, 0xa3, 
+    0xa5, 0x08, 0x1b, 0xf4, 0x68, 0x06, 0xa5, 0xb8, 0x10, 0xf0, 0x80, 0x19, 0x7e, 0xb0, 0x00, 0x7a, 
+    0xb3, 0x2c, 0x7f, 0xbe, 0x00, 0x10, 0x68, 0x0d, 0x7e, 0xb0, 0x00, 0x7a, 0xb3, 0x2c, 0x7f, 0x74, 
+    0x80, 0x7a, 0xb3, 0x91, 0x1e, 0x7a, 0xef, 0x2c, 0x82, 0x7a, 0xf7, 0x2c, 0x86, 0x75, 0x2f, 0x06, 
+    0x12, 0x73, 0x35, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xca, 0x0b, 0xca, 0x1b, 0xca, 0x2b, 
+    0xca, 0x3b, 0xca, 0x4b, 0xca, 0x5b, 0xca, 0x6b, 0xca, 0x7b, 0xca, 0xeb, 0x75, 0x2f, 0x03, 0x12, 
+    0x73, 0x35, 0x74, 0x00, 0x7a, 0xb3, 0x2c, 0x7e, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x01, 
+    0x7a, 0xb3, 0x91, 0x12, 0x12, 0x6d, 0x19, 0xda, 0xeb, 0xda, 0x7b, 0xda, 0x6b, 0xda, 0x5b, 0xda, 
+    0x4b, 0xda, 0x3b, 0xda, 0x2b, 0xda, 0x1b, 0xda, 0x0b, 0x22, 0x75, 0x2f, 0x03, 0x12, 0x73, 0x35, 
+    0x7e, 0xb3, 0x2c, 0x80, 0xb4, 0x02, 0x11, 0x74, 0x00, 0x7a, 0xb3, 0x2c, 0x80, 0x7a, 0xb3, 0x2c, 
+    0x7f, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x22, 0xb4, 0x01, 0x46, 0x7e, 0xb3, 0x91, 0x04, 0x20, 
+    0xe6, 0x42, 0x7e, 0x23, 0x91, 0x1a, 0x7c, 0x32, 0x7e, 0x13, 0x2c, 0x81, 0x2c, 0x21, 0x7a, 0x23, 
+    0x2c, 0x81, 0x7e, 0x00, 0x00, 0x2e, 0x04, 0x2c, 0x88, 0x7e, 0xb3, 0x91, 0x16, 0x7a, 0x09, 0xb0, 
+    0x0b, 0x04, 0xa5, 0xdb, 0xf4, 0x74, 0x20, 0x7a, 0xb3, 0x91, 0x14, 0x75, 0x2f, 0x70, 0x12, 0x73, 
+    0x35, 0x7e, 0xb3, 0x2c, 0x81, 0x7e, 0xa3, 0x2c, 0x7d, 0xbc, 0xab, 0x78, 0x03, 0x12, 0x6d, 0xb9, 
+    0x22, 0x02, 0x71, 0xf2, 0xda, 0x59, 0x02, 0x6c, 0x7c, 0x74, 0xe0, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 
+    0x03, 0x91, 0x10, 0x7e, 0x13, 0x91, 0x11, 0x7e, 0x33, 0x91, 0x12, 0x7e, 0x23, 0x91, 0x13, 0x7e, 
+    0x53, 0x91, 0x14, 0x7e, 0x43, 0x91, 0x15, 0x7e, 0x73, 0x91, 0x16, 0x7e, 0x63, 0x91, 0x17, 0x7a, 
+    0x0f, 0x2c, 0x76, 0x7a, 0x1f, 0x2c, 0x7a, 0x75, 0x2f, 0x04, 0x12, 0x73, 0x35, 0x7a, 0x01, 0x2f, 
+    0x12, 0x73, 0x35, 0x7a, 0x11, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x21, 0x2f, 0x12, 0x73, 0x35, 0x7a, 
+    0x31, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x41, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x51, 0x2f, 0x12, 0x73, 
+    0x35, 0x7a, 0x61, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x71, 0x2f, 0x12, 0x73, 0x35, 0x74, 0x00, 0x7a, 
+    0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x04, 0x12, 0x6d, 0x8d, 0x22, 0x6d, 0x00, 0x7e, 
+    0x14, 0x01, 0x02, 0x7a, 0x07, 0x2c, 0x86, 0x7a, 0x03, 0x2c, 0x81, 0x7e, 0xb3, 0x2c, 0x76, 0x20, 
+    0xe7, 0x0f, 0x7a, 0x23, 0x2c, 0x80, 0x7a, 0x33, 0x2c, 0x7f, 0xbe, 0x07, 0x2c, 0x7c, 0x68, 0x09, 
+    0x22, 0x7a, 0x33, 0x2c, 0x80, 0x7a, 0x23, 0x2c, 0x7f, 0x7e, 0xb3, 0x2c, 0x76, 0x54, 0xe3, 0x23, 
+    0x23, 0x30, 0xe0, 0x02, 0xd2, 0xe5, 0x30, 0xe7, 0x02, 0xd2, 0xe4, 0x30, 0xe5, 0x06, 0x30, 0xe4, 
+    0x03, 0x02, 0x71, 0xf2, 0x54, 0x3e, 0xf5, 0xf0, 0x03, 0x54, 0x1f, 0xc3, 0x25, 0xf0, 0x90, 0x6d, 
+    0xe5, 0x75, 0x84, 0xff, 0x73, 0x02, 0x6f, 0xa0, 0x02, 0x6e, 0x2d, 0x02, 0x70, 0x39, 0x02, 0x70, 
+    0x54, 0x02, 0x6f, 0x37, 0x02, 0x6e, 0xc2, 0x02, 0x70, 0x85, 0x02, 0x70, 0x85, 0x02, 0x70, 0x88, 
+    0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 
+    0x70, 0x88, 0x02, 0x70, 0x88, 0x02, 0x70, 0x8e, 0x02, 0x71, 0x60, 0x02, 0x70, 0x8b, 0x02, 0x70, 
+    0x8b, 0x02, 0x70, 0x8b, 0x02, 0x70, 0x8b, 0x02, 0x70, 0x8b, 0x02, 0x70, 0x8b, 0x74, 0x00, 0x7a, 
+    0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x06, 0x2a, 
+    0x7e, 0xb3, 0x2c, 0x78, 0x60, 0x79, 0x7c, 0x0b, 0x7e, 0x13, 0x2c, 0x79, 0x7e, 0x17, 0x2c, 0x7a, 
+    0x75, 0x2f, 0x72, 0x12, 0x73, 0x35, 0x7a, 0x01, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x11, 0x2f, 0x12, 
+    0x73, 0x35, 0x12, 0x72, 0x37, 0x40, 0x58, 0x02, 0x6b, 0xeb, 0xb4, 0x08, 0x1c, 0x75, 0x2f, 0x74, 
+    0x12, 0x73, 0x35, 0x7e, 0xb3, 0x3f, 0xf1, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0x7a, 
+    0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x01, 0x02, 0x6b, 0xeb, 0xb4, 0x00, 0x33, 0x75, 0x2f, 0x75, 0x12, 
+    0x73, 0x35, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7e, 0xb3, 0x3f, 0xf2, 
+    0x30, 0xe0, 0x07, 0x74, 0x02, 0x7a, 0x0b, 0xb0, 0x80, 0x05, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x0b, 
+    0x14, 0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 0x00, 0x02, 0xda, 0x0b, 0x02, 0x6b, 0xeb, 0x02, 
+    0x71, 0xf2, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 
+    0x2c, 0x77, 0xb4, 0x00, 0x5f, 0x75, 0x2f, 0x76, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x7b, 0x54, 
+    0x0f, 0xb4, 0x02, 0x05, 0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 0xb0, 0x00, 0x80, 
+    0x0f, 0x7e, 0xb3, 0x2c, 0x7b, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 0x7e, 0xb0, 0x20, 
+    0x7a, 0xb3, 0x91, 0x00, 0x7e, 0xb3, 0x91, 0x11, 0x30, 0xe0, 0x04, 0x74, 0x01, 0x80, 0x02, 0x74, 
+    0x00, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0xca, 0x0b, 0x7a, 0x0b, 0xb0, 0x0b, 0x14, 
+    0x74, 0x00, 0x7a, 0x0b, 0xb0, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x7e, 0x54, 0x00, 0x02, 0xda, 
+    0x0b, 0x02, 0x6b, 0xeb, 0x02, 0x71, 0xf2, 0x7e, 0xb3, 0x2c, 0x7b, 0x54, 0x0f, 0xb4, 0x02, 0x05, 
+    0x7e, 0xb0, 0x60, 0x80, 0x17, 0xb4, 0x00, 0x05, 0x7e, 0xb0, 0x00, 0x80, 0x0f, 0x7e, 0xb3, 0x2c, 
+    0x7b, 0x20, 0xe7, 0x05, 0x7e, 0xb0, 0x40, 0x80, 0x03, 0x7e, 0xb0, 0x20, 0x7a, 0xb3, 0x91, 0x00, 
+    0x7e, 0xb3, 0x2c, 0x79, 0xb4, 0x00, 0x26, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x01, 0x0e, 0x75, 0x2f, 
+    0x77, 0x12, 0x73, 0x35, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x80, 0x1b, 0xb4, 0x03, 0x0e, 0x75, 
+    0x2f, 0x78, 0x12, 0x73, 0x35, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x11, 0x80, 0x0a, 0x74, 0x00, 0x7a, 
+    0xb3, 0x91, 0x00, 0x12, 0x71, 0xf2, 0x22, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x02, 0x6b, 0xde, 
+    0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x09, 0x1f, 0x75, 0x2f, 0x79, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 
+    0x79, 0xbe, 0xb3, 0x3f, 0xf1, 0x68, 0x0d, 0xca, 0xb8, 0x12, 0x43, 0x79, 0xda, 0xb8, 0x50, 0x76, 
+    0x7a, 0xb3, 0x3f, 0xf1, 0x80, 0x6d, 0xb4, 0x05, 0x08, 0x75, 0x2f, 0x7a, 0x12, 0x73, 0x35, 0x80, 
+    0x62, 0xb4, 0x03, 0x19, 0x75, 0x2f, 0x7b, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x79, 0xb4, 0x01, 
+    0x55, 0x7e, 0xb3, 0x3f, 0xf2, 0x44, 0x01, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x46, 0xb4, 0x01, 0x19, 
+    0x75, 0x2f, 0x7c, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x79, 0xb4, 0x01, 0x39, 0x7e, 0xb3, 0x3f, 
+    0xf2, 0x54, 0xfe, 0x7a, 0xb3, 0x3f, 0xf2, 0x80, 0x2a, 0xb4, 0x07, 0x2a, 0x7e, 0xb3, 0x2c, 0x78, 
+    0x60, 0x24, 0x7c, 0x0b, 0x7e, 0x13, 0x2c, 0x79, 0x7e, 0x17, 0x2c, 0x7a, 0x75, 0x2f, 0x73, 0x12, 
+    0x73, 0x35, 0x7a, 0x01, 0x2f, 0x12, 0x73, 0x35, 0x7a, 0x11, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x72, 
+    0x71, 0x40, 0x03, 0x02, 0x6b, 0xde, 0x02, 0x71, 0xf2, 0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x0b, 0xf6, 
+    0x75, 0x2f, 0x7d, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 0x79, 0x7e, 0xa3, 0x2c, 0x7b, 0x4c, 0xab, 
+    0x78, 0xe4, 0x80, 0xdf, 0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 
+    0x7e, 0xb3, 0x2c, 0x77, 0xb4, 0x0a, 0xcf, 0x75, 0x2f, 0x7e, 0x12, 0x73, 0x35, 0x7e, 0xb3, 0x2c, 
+    0x79, 0x70, 0xc3, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0x7a, 0x0b, 0xb0, 0x7e, 0x54, 
+    0x00, 0x01, 0x02, 0x6b, 0xeb, 0x02, 0x71, 0xf2, 0x02, 0x71, 0xf2, 0x02, 0x71, 0xf2, 0x7e, 0xb3, 
+    0x2c, 0x77, 0xb4, 0x04, 0x20, 0x75, 0x2f, 0xc3, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x00, 0x01, 0x7e, 
+    0x17, 0x2c, 0x78, 0x7e, 0x18, 0x2c, 0x88, 0x7a, 0x1c, 0x00, 0x00, 0x7e, 0x47, 0x2c, 0x7c, 0x12, 
+    0x73, 0x41, 0x02, 0x71, 0x5a, 0xb4, 0x06, 0x42, 0x75, 0x2f, 0xc1, 0x12, 0x73, 0x35, 0x7e, 0x58, 
+    0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7d, 0xca, 0x7e, 0xd7, 0x2c, 0x78, 0x7e, 0x78, 0x2c, 0x88, 
+    0x7a, 0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2c, 0x7c, 0x75, 0x2f, 0xc1, 0x12, 0x73, 0x35, 0xc0, 0xa8, 
+    0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x73, 0x7a, 0x7e, 0x43, 0x2c, 0x35, 
+    0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0x40, 0x65, 0x80, 0x60, 0xb4, 0x00, 0x24, 0xc2, 0xaf, 0x7e, 
+    0xb0, 0x01, 0x7a, 0xb3, 0x94, 0x00, 0x7a, 0xb3, 0x2c, 0x35, 0x12, 0x6b, 0xde, 0xe4, 0x8d, 0xef, 
+    0x8d, 0xef, 0x8d, 0xef, 0xd5, 0xe0, 0xf7, 0xc0, 0xd1, 0xca, 0x02, 0xff, 0xca, 0x06, 0x00, 0x00, 
+    0x32, 0xb4, 0x09, 0x20, 0x74, 0x03, 0x7a, 0xb3, 0x91, 0x06, 0x7e, 0x23, 0x91, 0x07, 0x7e, 0x57, 
+    0x2c, 0x78, 0x4d, 0x55, 0x68, 0x05, 0x4e, 0x20, 0x02, 0x80, 0x03, 0x5e, 0x20, 0xfd, 0x7a, 0x23, 
+    0x91, 0x07, 0x80, 0x16, 0xb4, 0x07, 0x16, 0xc2, 0xaf, 0x7e, 0x07, 0x2c, 0x7a, 0x7e, 0x17, 0x2c, 
+    0x78, 0xc0, 0xd1, 0xca, 0x18, 0xca, 0x38, 0xca, 0x28, 0x32, 0x02, 0x6b, 0xde, 0x02, 0x71, 0xf2, 
+    0x74, 0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x60, 0x7a, 0xb3, 0x91, 0x1c, 0x7e, 0xb3, 0x2c, 0x77, 
+    0xb4, 0x03, 0x15, 0x75, 0x2f, 0xc2, 0x12, 0x73, 0x35, 0x7e, 0x04, 0x00, 0x01, 0x7e, 0x17, 0x2c, 
+    0x78, 0x7e, 0x57, 0x2c, 0x7c, 0x02, 0x6b, 0xeb, 0xb4, 0x05, 0x41, 0x75, 0x2f, 0xc0, 0x12, 0x73, 
+    0x35, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x7e, 0x08, 0x2c, 0x88, 
+    0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x24, 0x00, 0xfe, 0x7e, 0x37, 0x2c, 0x78, 0x7e, 0x47, 0x2c, 0x7c, 
+    0x12, 0x73, 0x41, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0x7e, 0x08, 0x2c, 
+    0x88, 0x7a, 0x0c, 0x00, 0x00, 0x7e, 0x57, 0x2c, 0x7c, 0x02, 0x6b, 0xeb, 0xb4, 0x01, 0x20, 0x7e, 
+    0x00, 0x00, 0x7e, 0x10, 0x01, 0x75, 0x2f, 0x72, 0x12, 0x73, 0x35, 0x7a, 0x01, 0x2f, 0x12, 0x73, 
+    0x35, 0x7a, 0x11, 0x2f, 0x12, 0x73, 0x35, 0x12, 0x72, 0x37, 0x40, 0x03, 0x02, 0x6b, 0xeb, 0x02, 
+    0x71, 0xf2, 0x75, 0x2f, 0x07, 0x12, 0x73, 0x35, 0x7e, 0xb0, 0x02, 0x7a, 0xb3, 0x90, 0x00, 0x74, 
+    0x00, 0x7a, 0xb3, 0x91, 0x00, 0x74, 0x40, 0x7a, 0xb3, 0x91, 0x15, 0x74, 0x01, 0x7a, 0xb3, 0x91, 
+    0x11, 0x7e, 0xb3, 0x91, 0x15, 0x54, 0x60, 0xbe, 0xb0, 0x40, 0x68, 0x08, 0x74, 0x20, 0x7a, 0xb3, 
+    0x91, 0x15, 0x80, 0xed, 0x74, 0x01, 0x7a, 0xb3, 0x91, 0x12, 0x74, 0x04, 0x7a, 0xb3, 0x91, 0x14, 
+    0x74, 0xff, 0x7a, 0xb3, 0x2c, 0x7e, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 
+    0x94, 0x00, 0x12, 0x72, 0xbe, 0x40, 0x1f, 0x7e, 0x08, 0x2c, 0x88, 0x7a, 0x0c, 0x00, 0x00, 0xca, 
+    0x0b, 0xca, 0x49, 0x12, 0x73, 0x41, 0xda, 0x59, 0xda, 0x0b, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 
+    0x94, 0x00, 0xd0, 0xa8, 0xc3, 0x22, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 
+    0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0x7e, 0x40, 0x01, 0x7a, 0x43, 0x94, 0x00, 0x12, 0x72, 0xbe, 0x40, 
+    0x31, 0x7e, 0x58, 0x00, 0x00, 0x7a, 0x5c, 0x00, 0xfe, 0x7f, 0x61, 0x7e, 0x78, 0x2c, 0x88, 0x7a, 
+    0x7c, 0x00, 0x00, 0x7e, 0x77, 0x2c, 0x7c, 0xbd, 0x74, 0x78, 0x17, 0x75, 0x2f, 0xc1, 0x12, 0x73, 
+    0x35, 0x12, 0x73, 0x7a, 0x40, 0x0c, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 
+    0xc3, 0x22, 0x7e, 0x43, 0x2c, 0x35, 0x7a, 0x43, 0x94, 0x00, 0xd0, 0xa8, 0xd3, 0x22, 0x7e, 0x24, 
+    0x00, 0xfe, 0x7e, 0x34, 0x7f, 0xca, 0x0b, 0x1a, 0x50, 0xc5, 0xf0, 0x7d, 0x62, 0x7d, 0x75, 0x7d, 
+    0x87, 0x7e, 0x34, 0x7f, 0xc2, 0x7e, 0x1b, 0xb0, 0x7e, 0x34, 0x7f, 0x03, 0xb4, 0x01, 0x04, 0x7e, 
+    0x34, 0x7f, 0xcc, 0x7e, 0x1b, 0xb0, 0xbc, 0x0b, 0x50, 0x49, 0x3e, 0x00, 0x3e, 0x00, 0x0a, 0x50, 
+    0x2d, 0x75, 0x0b, 0x3a, 0x30, 0x69, 0x53, 0x00, 0x02, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbc, 
+    0x1b, 0x50, 0x30, 0x3e, 0x10, 0x3e, 0x10, 0x0a, 0x51, 0x2d, 0x35, 0x69, 0x41, 0x00, 0x02, 0x0b, 
+    0x1a, 0x30, 0xbd, 0x38, 0x50, 0x02, 0x2d, 0x38, 0xbe, 0x44, 0xff, 0xff, 0x78, 0x05, 0x7e, 0x1b, 
+    0x90, 0x0a, 0x49, 0x4d, 0x44, 0x68, 0x0c, 0xbe, 0x44, 0x00, 0xff, 0x28, 0x04, 0x7e, 0x44, 0x00, 
+    0xff, 0xc3, 0x22, 0xd3, 0x22, 
+
+// Segment #16, Start Address 00ff7fc6, Length 4
+0xff,0x00,0xc6,0x7f,0x04,0x00,
+    0x02, 0x00, 0x03, 0x00, 
+
+// Segment #17, Start Address 00ff7335, Length 328
+0xff,0x00,0x35,0x73,0x48,0x01,
+    0xca, 0x08, 0x7e, 0x01, 0x2f, 0x7a, 0x03, 0x3f, 0xf0, 0xda, 0x08, 0x22, 0x7e, 0x1b, 0xc0, 0x7a, 
+    0x0b, 0xc0, 0x0b, 0x14, 0x0b, 0x34, 0x1b, 0x44, 0x78, 0xf2, 0x22, 0x7f, 0x6f, 0x7f, 0xf0, 0x1b, 
+    0xfc, 0x7c, 0x54, 0x7d, 0x32, 0x80, 0x08, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0xca, 0x1b, 0x9e, 
+    0x44, 0x00, 0x10, 0x50, 0xf2, 0x2e, 0x44, 0x00, 0x10, 0x68, 0x06, 0xca, 0x48, 0x1b, 0x44, 0x78, 
+    0xfa, 0x7f, 0xf6, 0x89, 0xe4, 0xca, 0x6b, 0x5e, 0xd4, 0x00, 0x3f, 0x68, 0x20, 0x7e, 0x84, 0x00, 
+    0x40, 0x9d, 0x8d, 0xda, 0x6b, 0xbd, 0x87, 0x38, 0x16, 0xca, 0x79, 0x7d, 0x78, 0x12, 0x73, 0xa4, 
+    0xda, 0x79, 0x40, 0x08, 0x9d, 0x78, 0x68, 0x02, 0x80, 0x05, 0xc2, 0xd7, 0x22, 0xda, 0x6b, 0x7e, 
+    0xc0, 0x03, 0x7e, 0xd0, 0x00, 0x7a, 0xd3, 0x90, 0x00, 0x74, 0xaa, 0x39, 0xb5, 0x55, 0x55, 0x74, 
+    0x55, 0x39, 0xb5, 0x2a, 0xaa, 0x74, 0xa0, 0x39, 0xb5, 0x55, 0x55, 0x7e, 0x04, 0x00, 0x40, 0x9d, 
+    0x70, 0x50, 0x06, 0x2d, 0x70, 0x7d, 0x07, 0x6d, 0x77, 0x7c, 0x31, 0x7e, 0x7b, 0x00, 0x7a, 0x6b, 
+    0x00, 0x0b, 0x7c, 0x0b, 0x6c, 0xa5, 0xd9, 0xf3, 0x7f, 0x16, 0x1b, 0x1c, 0x7e, 0x54, 0x27, 0x10, 
+    0x7e, 0x1b, 0x10, 0xbc, 0x10, 0x68, 0x06, 0x1b, 0x54, 0x78, 0xf5, 0x80, 0x2f, 0x6d, 0x00, 0x7c, 
+    0x20, 0x7f, 0x16, 0x9f, 0x10, 0x7f, 0x27, 0x9f, 0x20, 0x7e, 0x2b, 0x00, 0x7e, 0x1b, 0x10, 0xbc, 
+    0x01, 0x78, 0x19, 0x0b, 0x2c, 0x0b, 0x1c, 0xa5, 0xdb, 0xef, 0x7c, 0xb6, 0x20, 0xe0, 0x06, 0x6c, 
+    0xdc, 0x7a, 0xd3, 0x90, 0x00, 0x4d, 0x77, 0x78, 0x90, 0xc2, 0xd7, 0x22, 0xd2, 0xd7, 0x22, 0x00, 
+    0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x04, 0x02, 0x04, 0x00, 0x02, 0x01, 0x04, 0x01, 0x02, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x08, 0x10, 
+    0x02, 0x10, 0x04, 0x02, 0x08, 0x00, 0x01, 0x01, 0x08, 0x7e, 0x18, 0x7f, 0xbd, 0x7a, 0x1c, 0x00, 
+    0xfe, 0x0b, 0x1a, 0x00, 0x5e, 0x10, 0x1f, 0xbe, 0x10, 0x14, 0x38, 0x1a, 0x0a, 0x51, 0x23, 0x7e, 
+    0x18, 0x74, 0x24, 0x7a, 0x1c, 0x00, 0xff, 0x2d, 0x35, 0x0b, 0x1a, 0x50, 0x60, 0x08, 0xa5, 0xb8, 
+    0x02, 0x03, 0x4e, 0xa0, 0x08, 0x22, 0x80, 0xfe, 
+};
+
+static EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME = {
+	2, 0, 3 };		// Major, Minor, Build
+
+#undef IMAGE_VERSION_NAME
+
+#undef IMAGE_ARRAY_NAME
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_ionsp.h linux/drivers/usb/serial/io_ionsp.h
--- v2.4.2/linux/drivers/usb/serial/io_ionsp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_ionsp.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,454 @@
+/************************************************************************
+ *
+ *	IONSP.H		Definitions for I/O Networks Serial Protocol
+ *
+ *	Copyright (c) 1997-1998 Inside Out Networks, Inc.
+ *
+ *	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.
+ *
+ *	These definitions are used by both kernel-mode driver and the
+ *	peripheral firmware and MUST be kept in sync.
+ *
+ ************************************************************************/
+
+/************************************************************************
+
+The data to and from all ports on the peripheral is multiplexed
+through a single endpoint pair (EP1 since it supports 64-byte
+MaxPacketSize). Therefore, the data, commands, and status for
+each port must be preceeded by a short header identifying the
+destination port. The header also identifies the bytes that follow
+as data or as command/status info.
+
+Header format, first byte:
+
+    CLLLLPPP
+    --------
+    | |	 |------ Port Number:	0-7
+    | |--------- Length:	MSB bits of length
+    |----------- Data/Command:	0 = Data header
+				1 = Cmd / Status (Cmd if OUT, Status if IN)
+
+This gives 2 possible formats:
+
+
+    Data header:		0LLLLPPP	LLLLLLLL
+    ============
+
+    Where (LLLL,LLLLLLL) is 12-bit length of data that follows for
+    port number (PPP). The length is 0-based (0-FFF means 0-4095
+    bytes). The ~4K limit allows the host driver (which deals in
+    transfer requests instead of individual packets) to write a
+    large chunk of data in a single request. Note, however, that
+    the length must always be <= the current TxCredits for a given
+    port due to buffering limitations on the peripheral.
+
+
+    Cmd/Status header:		1ccccPPP	[ CCCCCCCC,	 Params ]...
+    ==================
+
+    Where (cccc) or (cccc,CCCCCCCC) is the cmd or status identifier.
+    Frequently-used values are encoded as (cccc), longer ones using
+    (cccc,CCCCCCCC). Subsequent bytes are optional parameters and are
+    specific to the cmd or status code. This may include a length
+    for command and status codes that need variable-length parameters.
+
+
+In addition, we use another interrupt pipe (endpoint) which the host polls
+periodically for flow control information. The peripheral, when there has
+been a change, sends the following 10-byte packet:
+
+	RRRRRRRRRRRRRRRR
+	T0T0T0T0T0T0T0T0
+	T1T1T1T1T1T1T1T1
+	T2T2T2T2T2T2T2T2
+	T3T3T3T3T3T3T3T3
+
+The first field is the 16-bit RxBytesAvail field, which indicates the
+number of bytes which may be read by the host from EP1. This is necessary:
+(a) because OSR2.1 has a bug which causes data loss if the peripheral returns
+fewer bytes than the host expects to read, and (b) because, on Microsoft
+platforms at least, an outstanding read posted on EP1 consumes about 35% of
+the CPU just polling the device for data.
+
+The next 4 fields are the 16-bit TxCredits for each port, which indicate how
+many bytes the host is allowed to send on EP1 for transmit to a given port.
+After an OPEN_PORT command, the Edgeport sends the initial TxCredits for that
+port.
+
+All 16-bit fields are sent in little-endian (Intel) format.
+
+************************************************************************/
+
+//
+// Define format of InterruptStatus packet returned from the
+// Interrupt pipe
+//
+
+typedef struct _INT_STATUS_PKT {
+	__u16      RxBytesAvail;		    // Additional bytes available to
+						    // be read from Bulk IN pipe
+	__u16      TxCredits[ MAX_RS232_PORTS ];   // Additional space available in
+						    // given port's TxBuffer
+} INT_STATUS_PKT, *PINT_STATUS_PKT;
+
+
+#define GET_INT_STATUS_SIZE(NumPorts) (sizeof(__u16) + (sizeof(__u16) * (NumPorts)))
+
+
+
+//
+// Define cmd/status header values and macros to extract them.
+//
+//	Data:		0LLLLPPP LLLLLLLL
+//	Cmd/Stat:	1ccccPPP CCCCCCCC
+
+#define	IOSP_DATA_HDR_SIZE		2
+#define	IOSP_CMD_HDR_SIZE		2
+
+#define	IOSP_MAX_DATA_LENGTH		0x0FFF		// 12 bits -> 4K
+
+#define	IOSP_PORT_MASK			0x07		// Mask to isolate port number
+#define	IOSP_CMD_STAT_BIT		0x80		// If set, this is command/status header
+
+#define IS_CMD_STAT_HDR(Byte1)		((Byte1) & IOSP_CMD_STAT_BIT)
+#define IS_DATA_HDR(Byte1)		(! IS_CMD_STAT_HDR(Byte1))
+
+#define	IOSP_GET_HDR_PORT(Byte1)		((__u8) ((Byte1) & IOSP_PORT_MASK))
+#define	IOSP_GET_HDR_DATA_LEN(Byte1, Byte2)	((__u16) ( ((__u16)((Byte1) & 0x78)) << 5) | (Byte2))
+#define	IOSP_GET_STATUS_CODE(Byte1)		((__u8) (((Byte1) &  0x78) >> 3))
+
+
+//
+// These macros build the 1st and 2nd bytes for a data header
+//
+#define	IOSP_BUILD_DATA_HDR1(Port, Len)		((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78 ))))
+#define	IOSP_BUILD_DATA_HDR2(Port, Len)		((__u8) (Len))
+
+
+//
+// These macros build the 1st and 2nd bytes for a command header
+//
+#define	IOSP_BUILD_CMD_HDR1(Port, Cmd)		((__u8) ( IOSP_CMD_STAT_BIT | (Port) |	((__u8) ((Cmd) << 3)) ))
+
+
+//--------------------------------------------------------------
+//
+//	Define values for commands and command parameters
+//	(sent from Host to Edgeport)
+//
+//	1ccccPPP P1P1P1P1 [ P2P2P2P2P2 ]...
+//
+//	cccc:	00-07	2-byte commands. Write UART register 0-7 with
+//					value in P1. See 16650.H for definitions of
+//					UART register numbers and contents.
+//
+//		08-0B	3-byte commands:					==== P1 ====	==== P2 ====
+//					08	available for expansion
+//					09	1-param commands		Command Code	Param
+//					0A	available for expansion
+//					0B	available for expansion
+//
+//		0C-0D	4-byte commands.	P1 = extended cmd and P2,P3 = params
+//						Currently unimplemented.
+//
+//		0E-0F	N-byte commands:	P1 = num bytes after P1 (ie, TotalLen - 2)
+//						P2 = extended cmd, P3..Pn = parameters.
+//						Currently unimplemented.
+//
+
+#define	IOSP_WRITE_UART_REG(n)	((n) & 0x07)	// UartReg[ n ] := P1
+
+// Register numbers and contents
+// defined in 16554.H.
+
+//					0x08		// Available for expansion.
+#define	IOSP_EXT_CMD			0x09		// P1 = Command code (defined below)
+
+// P2 = Parameter
+
+//
+// Extended Command values, used with IOSP_EXT_CMD, may
+// or may not use parameter P2.
+//
+
+#define	IOSP_CMD_OPEN_PORT		0x00		// Enable ints, init UART. (NO PARAM)
+#define	IOSP_CMD_CLOSE_PORT		0x01		// Disable ints, flush buffers. (NO PARAM)
+#define	IOSP_CMD_CHASE_PORT		0x02		// Wait for Edgeport TX buffers to empty. (NO PARAM)
+#define IOSP_CMD_SET_RX_FLOW		0x03		// Set Rx Flow Control in Edgeport
+#define IOSP_CMD_SET_TX_FLOW		0x04		// Set Tx Flow Control in Edgeport
+#define IOSP_CMD_SET_XON_CHAR		0x05		// Set XON Character in Edgeport
+#define IOSP_CMD_SET_XOFF_CHAR		0x06		// Set XOFF Character in Edgeport
+#define IOSP_CMD_RX_CHECK_REQ		0x07		// Request Edgeport to insert a Checkpoint into
+
+// the receive data stream (Parameter = 1 byte sequence number)
+
+#define IOSP_CMD_SET_BREAK		0x08		// Turn on the BREAK (LCR bit 6)
+#define IOSP_CMD_CLEAR_BREAK		0x09		// Turn off the BREAK (LCR bit 6)
+
+
+//
+// Define macros to simplify building of IOSP cmds
+//
+
+#define	MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val)						\
+	do {											\
+		(*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_WRITE_UART_REG(Reg) );	\
+		(*(ppBuf))[1] = (Val);								\
+												\
+		*ppBuf += 2;									\
+		*pLen  += 2;									\
+	} while (0)
+
+#define	MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param)					\
+	do {											\
+		(*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1( (Port), IOSP_EXT_CMD );			\
+		(*(ppBuf))[1] = (ExtCmd);							\
+		(*(ppBuf))[2] = (Param);							\
+												\
+		*ppBuf += 3;									\
+		*pLen  += 3;									\
+	} while (0)
+
+
+
+//--------------------------------------------------------------
+//
+//	Define format of flow control commands
+//	(sent from Host to Edgeport)
+//
+//	11001PPP FlowCmd FlowTypes
+//
+//	Note that the 'FlowTypes' parameter is a bit mask; that is,
+//	more than one flow control type can be active at the same time.
+//	FlowTypes = 0 means 'no flow control'.
+//
+
+//
+//	IOSP_CMD_SET_RX_FLOW
+//
+//	Tells Edgeport how it can stop incoming UART data
+//
+//  Example for Port 0
+//	P0 = 11001000
+//  P1 = IOSP_CMD_SET_RX_FLOW
+//  P2 = Bit mask as follows:
+
+#define IOSP_RX_FLOW_RTS		0x01	// Edgeport drops RTS to stop incoming data
+#define IOSP_RX_FLOW_DTR		0x02	// Edgeport drops DTR to stop incoming data
+#define IOSP_RX_FLOW_DSR_SENSITIVITY	0x04	// Ignores Rx data unless DSR high
+
+// Not currently implemented by firmware.
+#define IOSP_RX_FLOW_XON_XOFF		0x08	// Edgeport sends XOFF char to stop incoming data.
+
+// Host must have previously programmed the
+// XON/XOFF values with SET_XON/SET_XOFF
+// before enabling this bit.
+
+//
+//	IOSP_CMD_SET_TX_FLOW
+//
+//	Tells Edgeport what signal(s) will stop it from transmitting UART data
+//
+//  Example for Port 0
+//	P0 = 11001000
+//  P1 = IOSP_CMD_SET_TX_FLOW
+//  P2 = Bit mask as follows:
+
+#define IOSP_TX_FLOW_CTS		0x01	// Edgeport stops Tx if CTS low
+#define IOSP_TX_FLOW_DSR		0x02	// Edgeport stops Tx if DSR low
+#define IOSP_TX_FLOW_DCD		0x04	// Edgeport stops Tx if DCD low
+#define IOSP_TX_FLOW_XON_XOFF		0x08	// Edgeport stops Tx upon receiving XOFF char.
+
+// Host must have previously programmed the
+// XON/XOFF values with SET_XON/SET_XOFF
+// before enabling this bit.
+#define IOSP_TX_FLOW_XOFF_CONTINUE	0x10	// If not set, Edgeport stops Tx when
+
+// sending XOFF in order to fix broken
+// systems that interpret the next
+// received char as XON.
+// If set, Edgeport continues Tx
+// normally after transmitting XOFF.
+// Not currently implemented by firmware.
+#define IOSP_TX_TOGGLE_RTS		0x20	// Edgeport drives RTS as a true half-duplex
+
+// Request-to-Send signal: it is raised before
+// beginning transmission and lowered after
+// the last Tx char leaves the UART.
+// Not currently implemented by firmware.
+
+//
+//	IOSP_CMD_SET_XON_CHAR
+//
+//	Sets the character which Edgeport transmits/interprets as XON.
+//	Note: This command MUST be sent before sending a SET_RX_FLOW or
+//	SET_TX_FLOW with the XON_XOFF bit set.
+//
+//  Example for Port 0
+//	P0 = 11001000
+//  P1 = IOSP_CMD_SET_XON_CHAR
+//  P2 = 0x11
+
+
+//
+//	IOSP_CMD_SET_XOFF_CHAR
+//
+//	Sets the character which Edgeport transmits/interprets as XOFF.
+//	Note: This command must be sent before sending a SET_RX_FLOW or
+//	SET_TX_FLOW with the XON_XOFF bit set.
+//
+//  Example for Port 0
+//	P0 = 11001000
+//  P1 = IOSP_CMD_SET_XOFF_CHAR
+//  P2 = 0x13
+
+
+//
+//	IOSP_CMD_RX_CHECK_REQ
+//
+//  This command is used to assist in the implementation of the 
+//  IOCTL_SERIAL_PURGE Windows IOCTL.  
+//  This IOSP command tries to place a marker at the end of the RX 
+//  queue in the Edgeport. If the Edgeport RX queue is full then 
+//  the Check will be discarded.  
+//  It is up to the device driver to timeout waiting for the 
+//  RX_CHECK_RSP.  If a RX_CHECK_RSP is received, the driver is 
+//	sure that all data has been received from the edgeport and 
+//	may now purge any internal RX buffers.
+//  Note tat the sequence numbers may be used to detect lost 
+//  CHECK_REQs.
+
+//  Example for Port 0
+//	P0 = 11001000
+//  P1 = IOSP_CMD_RX_CHECK_REQ
+//  P2 = Sequence number
+
+
+//  Response will be:
+//  P1 = IOSP_EXT_RX_CHECK_RSP
+//  P2 = Request Sequence number
+
+
+
+//--------------------------------------------------------------
+//
+//	Define values for status and status parameters
+//	(received by Host from Edgeport)
+//
+//	1ssssPPP P1P1P1P1 [ P2P2P2P2P2 ]...
+//
+// 	ssss:	00-07	2-byte status.	ssss identifies which UART register
+//					has changed value, and the new value is in P1.
+//					Note that the ssss values do not correspond to the
+//					16554 register numbers given in 16554.H. Instead,
+//					see below for definitions of the ssss numbers
+//					used in this status message.
+//
+//		08-0B	3-byte status:					==== P1 ====	==== P2 ====
+//					08	LSR_DATA:		New LSR		Errored byte
+//					09	1-param responses	Response Code	Param
+//					0A	OPEN_RSP:		InitialMsr	TxBufferSize
+//					0B	available for expansion
+//
+//		0C-0D	4-byte status.	P1 = extended status code and P2,P3 = params
+//					Not currently implemented.
+//
+//		0E-0F	N-byte status:	P1 = num bytes after P1 (ie, TotalLen - 2)
+//					P2 = extended status, P3..Pn = parameters.
+//					Not currently implemented.
+//
+
+/****************************************************
+ *	SSSS values for 2-byte status messages (0-8)
+ ****************************************************/
+
+#define	IOSP_STATUS_LSR			0x00	// P1 is new value of LSR register.
+
+// Bits defined in 16554.H. Edgeport
+// returns this in order to report
+// line status errors (overrun,
+// parity, framing, break). This form
+// is used when a errored receive data
+// character was NOT present in the
+// UART when the LSR error occurred
+// (ie, when LSR bit 0 = 0).
+
+#define	IOSP_STATUS_MSR			0x01	// P1 is new value of MSR register.
+
+// Bits defined in 16554.H. Edgeport
+// returns this in order to report
+// changes in modem status lines
+// (CTS, DSR, RI, CD)
+// 
+
+//					0x02	// Available for future expansion
+//					0x03	// 
+//					0x04	// 
+//					0x05	// 
+//					0x06	// 
+//					0x07	// 
+
+
+/****************************************************
+ *	SSSS values for 3-byte status messages (8-A)
+ ****************************************************/
+
+#define	IOSP_STATUS_LSR_DATA		0x08	// P1 is new value of LSR register (same as STATUS_LSR)
+
+// P2 is errored character read from
+//    RxFIFO after LSR reported an error.													
+
+#define	IOSP_EXT_STATUS			0x09	// P1 is status/response code, param in P2.
+
+
+// Response Codes (P1 values) for 3-byte status messages
+
+#define	IOSP_EXT_STATUS_CHASE_RSP	0	// Reply to CHASE_PORT cmd. P2 is outcome:
+#define	IOSP_EXT_STATUS_CHASE_PASS	0	// 	P2 = 0: All Tx data drained successfully
+#define	IOSP_EXT_STATUS_CHASE_FAIL	1	//	P2 = 1: Timed out (stuck due to flow
+
+//			control from remote device).
+
+#define	IOSP_EXT_STATUS_RX_CHECK_RSP	1	// Reply to RX_CHECK cmd. P2 is sequence number
+
+
+#define IOSP_STATUS_OPEN_RSP		0x0A	// Reply to OPEN_PORT cmd.
+
+// P1 is Initial MSR value
+// P2 is encoded TxBuffer Size:
+//	TxBufferSize = (P2 + 1) * 64
+
+//					0x0B	// Available for future expansion
+
+#define GET_TX_BUFFER_SIZE(P2) (((P2) + 1) * 64)
+
+
+
+
+/****************************************************
+ *	SSSS values for 4-byte status messages
+ ****************************************************/
+
+#define IOSP_EXT4_STATUS		0x0C	// Extended status code in P1,
+
+// Params in P2, P3
+// Currently unimplemented.
+
+//					0x0D	// Currently unused, available.
+
+
+
+//
+// Macros to parse status messages
+//
+
+#define	IOSP_GET_STATUS_LEN(code)	( (code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4) )
+
+#define	IOSP_STATUS_IS_2BYTE(code)	( (code) < 0x08 )
+#define	IOSP_STATUS_IS_3BYTE(code)	( ((code) >= 0x08) && ((code) <= 0x0B) )
+#define	IOSP_STATUS_IS_4BYTE(code)	( ((code) >= 0x0C) && ((code) <= 0x0D) )
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_tables.h linux/drivers/usb/serial/io_tables.h
--- v2.4.2/linux/drivers/usb/serial/io_tables.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_tables.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,444 @@
+/*
+ * IO Edgeport Driver tables
+ *
+ *	Copyright (C) 2001
+ *	    Greg Kroah-Hartman (greg@kroah.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.
+ * 
+ */
+
+static __devinitdata struct usb_device_id edgeport_4_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4)}, {} };
+static __devinitdata struct usb_device_id rapidport_4_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, {} };
+static __devinitdata struct usb_device_id edgeport_4t_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, {} };
+static __devinitdata struct usb_device_id edgeport_2_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, {} };
+static __devinitdata struct usb_device_id edgeport_4i_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, {} };
+static __devinitdata struct usb_device_id edgeport_2i_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, {} };
+static __devinitdata struct usb_device_id edgeport_prl_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) }, {} };
+static __devinitdata struct usb_device_id edgeport_421_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, {} };
+static __devinitdata struct usb_device_id edgeport_21_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, {} };
+static __devinitdata struct usb_device_id edgeport_8dual_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, {} };
+static __devinitdata struct usb_device_id edgeport_8_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, {} };
+static __devinitdata struct usb_device_id edgeport_2din_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, {} };
+static __devinitdata struct usb_device_id edgeport_4din_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, {} };
+static __devinitdata struct usb_device_id edgeport_16dual_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, {} };
+static __devinitdata struct usb_device_id edgeport_compat_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, {} };
+static __devinitdata struct usb_device_id edgeport_8i_id_table [] =	{{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, {} };
+
+
+/* Devices that this driver supports */
+static __devinitdata struct usb_device_id id_table_combined [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_RAPIDPORT_4) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_4T) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_2) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_4I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_2I) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_421) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_21) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_2_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_4_DIN) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
+	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_8I) },
+	{ }							/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table_combined);
+
+
+/* build up the list of devices that this driver supports */
+struct usb_serial_device_type edgeport_4_device = {
+	name:			"Edgeport 4",
+	id_table:		edgeport_4_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type rapidport_4_device = {
+	name:			"Rapidport 4",
+	id_table:		rapidport_4_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_4t_device = {
+	name:			"Edgeport 4t",
+	id_table:		edgeport_4t_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_2_device = {
+	name:			"Edgeport 2",
+	id_table:		edgeport_2_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_4i_device = {
+	name:			"Edgeport 4i",
+	id_table:		edgeport_4i_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_2i_device = {
+	name:			"Edgeport 2i",
+	id_table:		edgeport_2i_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_prl_device = {
+	name:			"Edgeport Parallel",
+	id_table:		edgeport_prl_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_421_device = {
+	name:			"Edgeport 421",
+	id_table:		edgeport_421_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_21_device = {
+	name:			"Edgeport 21",
+	id_table:		edgeport_21_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_8dual_device = {
+	name:			"Edgeport 8 dual cpu",
+	id_table:		edgeport_8dual_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_8_device = {
+	name:			"Edgeport 8",
+	id_table:		edgeport_8_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		8,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_2din_device = {
+	name:			"Edgeport 2din",
+	id_table:		edgeport_2din_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		2,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_4din_device = {
+	name:			"Edgeport 4din",
+	id_table:		edgeport_4din_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_16dual_device = {
+	name:			"Edgeport 16 dual cpu",
+	id_table:		edgeport_16dual_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		8,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+struct usb_serial_device_type edgeport_compat_id_device = {
+	name:			"Edgeport Compatible",
+	id_table:		edgeport_compat_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		4,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+
+struct usb_serial_device_type edgeport_8i_device = {
+	name:			"Edgeport 8i",
+	id_table:		edgeport_8i_id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		8,
+	open:			edge_open,
+	close:			edge_close,
+	throttle:		edge_throttle,
+	unthrottle:		edge_unthrottle,
+	startup:		edge_startup,
+	shutdown:		edge_shutdown,
+	ioctl:			edge_ioctl,
+	set_termios:		edge_set_termios,
+	write:			edge_write,
+	write_room:		edge_write_room,
+	chars_in_buffer:	edge_chars_in_buffer,
+	break_ctl:		edge_break,
+};
+
+
+
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/io_usbvend.h linux/drivers/usb/serial/io_usbvend.h
--- v2.4.2/linux/drivers/usb/serial/io_usbvend.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/io_usbvend.h	Mon Mar 19 17:21:54 2001
@@ -0,0 +1,374 @@
+/************************************************************************
+ *
+ *	USBVEND.H		Vendor-specific USB definitions
+ *
+ *	NOTE: This must be kept in sync with the Edgeport firmware and
+ *	must be kept backward-compatible with older firmware.
+ *
+ ************************************************************************
+ *
+ *	Copyright (c) 1998 Inside Out Networks, Inc.
+ *	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.
+ *
+ ************************************************************************/
+
+#if !defined(_USBVEND_H)
+#define	_USBVEND_H
+
+#ifndef __KERNEL__
+#include "ionprag.h"	/* Extra I/O Networks pragmas */
+
+#include <usbdi.h>
+
+#include "iondef.h"	/* Standard I/O Networks definitions */
+#endif
+
+/************************************************************************
+ *
+ *		D e f i n e s   /   T y p e d e f s
+ *
+ ************************************************************************/
+
+//
+// Definitions of USB product IDs
+// 
+
+#define	USB_VENDOR_ID_ION	0x1608		// Our VID
+
+//
+// Definitions of USB product IDs (PID)
+// We break the USB-defined PID into an OEM Id field (upper 6 bits)
+// and a Device Id (bottom 10 bits). The Device Id defines what
+// device this actually is regardless of what the OEM wants to
+// call it.
+//
+
+// ION-device OEM IDs
+#define	ION_OEM_ID_ION		0		// 00h Inside Out Networks
+#define	ION_OEM_ID_NLYNX	1		// 01h NLynx Systems	  
+#define	ION_OEM_ID_GENERIC	2		// 02h Generic OEM
+#define	ION_OEM_ID_MAC		3		// 03h Mac Version
+#define	ION_OEM_ID_MEGAWOLF	4		// 04h Lupusb OEM Mac version (MegaWolf)
+#define	ION_OEM_ID_MULTITECH	5		// 05h Multitech Rapidports
+
+	
+// ION-device Device IDs
+// Product IDs - assigned to match middle digit of serial number
+
+
+// The ION_DEVICE_ID_GENERATION_2 bit (0x20) will be ORed into the existing edgeport
+// PIDs to identify 80251+Netchip hardware.  This will guarantee that if a second
+// generation edgeport device is plugged into a PC with an older (pre 2.0) driver,
+// it will not enumerate.
+
+#define ION_DEVICE_ID_GENERATION_2	0x020	// This bit is set in the PID if this edgeport hardware
+															// is based on the 80251+Netchip.  
+
+#define EDGEPORT_DEVICE_ID_MASK			0x3df	// Not including GEN_2 bit
+
+#define	ION_DEVICE_ID_UNCONFIGURED_EDGE_DEVICE	0x000	// In manufacturing only
+#define ION_DEVICE_ID_EDGEPORT_4		0x001	// Edgeport/4 RS232
+//	ION_DEVICE_ID_HUBPORT_7			0x002	// Hubport/7 (Placeholder, not used by software)
+#define ION_DEVICE_ID_RAPIDPORT_4		0x003	// Rapidport/4
+#define ION_DEVICE_ID_EDGEPORT_4T		0x004	// Edgeport/4 RS232 for Telxon (aka "Fleetport")
+#define ION_DEVICE_ID_EDGEPORT_2		0x005	// Edgeport/2 RS232
+#define ION_DEVICE_ID_EDGEPORT_4I		0x006	// Edgeport/4 RS422
+#define ION_DEVICE_ID_EDGEPORT_2I		0x007	// Edgeport/2 RS422/RS485
+//	ION_DEVICE_ID_HUBPORT_4			0x008	// Hubport/4 (Placeholder, not used by software)
+//	ION_DEVICE_ID_EDGEPORT_8_HANDBUILT	0x009	// Hand-built Edgeport/8 (Placeholder, used in middle digit of serial number only!)
+//	ION_DEVICE_ID_MULTIMODEM_4X56		0x00A	// MultiTech version of RP/4 (Placeholder, used in middle digit of serial number only!)
+#define	ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT	0x00B	// Edgeport/(4)21 Parallel port (USS720)
+#define	ION_DEVICE_ID_EDGEPORT_421		0x00C	// Edgeport/421 Hub+RS232+Parallel
+#define	ION_DEVICE_ID_EDGEPORT_21		0x00D	// Edgeport/21  RS232+Parallel
+#define ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU	0x00E	// Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB)
+#define ION_DEVICE_ID_EDGEPORT_8		0x00F	// Edgeport/8 (single-CPU)
+#define ION_DEVICE_ID_EDGEPORT_2_DIN		0x010	// Edgeport/2 RS232 with Apple DIN connector
+#define ION_DEVICE_ID_EDGEPORT_4_DIN		0x011	// Edgeport/4 RS232 with Apple DIN connector
+#define ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU	0x012	// Half of an Edgeport/16 (the kind with 2 EP/8s)
+#define ION_DEVICE_ID_EDGEPORT_COMPATIBLE	0x013	// Edgeport Compatible, for NCR, Axiohm etc. testing
+#define ION_DEVICE_ID_EDGEPORT_8I		0x014	// Edgeport/8 RS422 (single-CPU)
+
+// These IDs are used by the Edgeport.exe program for uninstalling.
+// 
+#define EDGEPORT_DEVICE_IDS	{0x001, 0x003, 0x004, 0x005, 0x006, 0x007, 0x00B, \
+				 0x00C, 0x00D, 0x00E, 0x00F, 0x010, 0x011, 0x012, \
+				 0x013, 0x014 }
+
+
+#define	MAKE_USB_PRODUCT_ID( OemId, DeviceId )					\
+			( (__u16) (((OemId) << 10) || (DeviceId)) )
+
+#define	DEVICE_ID_FROM_USB_PRODUCT_ID( ProductId )				\
+			( (__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK)) )
+
+#define	OEM_ID_FROM_USB_PRODUCT_ID( ProductId )					\
+			( (__u16) (((ProductId) >> 10) & 0x3F) )
+
+//
+// Definitions of parameters for download code. Note that these are
+// specific to a given version of download code and must change if the
+// corresponding download code changes.
+//
+
+// TxCredits value below which driver won't bother sending (to prevent too many small writes).
+// Send only if above 25%
+#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit)	(max( ((InitialCredit) / 4), EDGE_FW_BULK_MAX_PACKET_SIZE ))
+
+#define	EDGE_FW_BULK_MAX_PACKET_SIZE		64	// Max Packet Size for Bulk In Endpoint (EP1)
+#define EDGE_FW_BULK_READ_BUFFER_SIZE		1024	// Size to use for Bulk reads
+
+#define	EDGE_FW_INT_MAX_PACKET_SIZE		32	// Max Packet Size for Interrupt In Endpoint
+							// Note that many units were shipped with MPS=16, we
+							// force an upgrade to this value).
+#define EDGE_FW_INT_INTERVAL			2	// 2ms polling on IntPipe
+
+
+//
+// Definitions of I/O Networks vendor-specific requests
+// for default endpoint
+//
+//	bmRequestType = 00100000	Set vendor-specific, to device
+//	bmRequestType = 10100000	Get vendor-specific, to device
+//
+// These are the definitions for the bRequest field for the
+// above bmRequestTypes.
+//
+// For the read/write Edgeport memory commands, the parameters
+// are as follows:
+//		wValue = 16-bit address
+//		wIndex = unused (though we could put segment 00: or FF: here)
+//		wLength = # bytes to read/write (max 64)
+//							
+
+#define USB_REQUEST_ION_RESET_DEVICE	0	// Warm reboot Edgeport, retaining USB address
+#define USB_REQUEST_ION_GET_EPIC_DESC	1	// Get Edgeport Compatibility Descriptor
+// unused				2	// Unused, available
+#define USB_REQUEST_ION_READ_RAM	3	// Read  EdgePort RAM at specified addr
+#define USB_REQUEST_ION_WRITE_RAM	4	// Write EdgePort RAM at specified addr
+#define USB_REQUEST_ION_READ_ROM	5	// Read  EdgePort ROM at specified addr
+#define USB_REQUEST_ION_WRITE_ROM	6	// Write EdgePort ROM at specified addr
+#define USB_REQUEST_ION_EXEC_DL_CODE	7	// Begin execution of RAM-based download
+						// code by jumping to address in wIndex:wValue
+//					8	// Unused, available
+#define USB_REQUEST_ION_ENABLE_SUSPEND	9	// Enable/Disable suspend feature
+						// (wValue != 0: Enable; wValue = 0: Disable)
+
+
+//
+// Define parameter values for our vendor-specific commands
+//
+
+
+// Values for iDownloadFile
+#define	EDGE_DOWNLOAD_FILE_NONE		0	// No download requested
+#define	EDGE_DOWNLOAD_FILE_INTERNAL	0xFF	// Download the file compiled into driver (930 version)
+#define	EDGE_DOWNLOAD_FILE_I930		0xFF	// Download the file compiled into driver (930 version)
+#define	EDGE_DOWNLOAD_FILE_80251	0xFE	// Download the file compiled into driver (80251 version)
+
+
+
+/*
+ *	Special addresses for READ/WRITE_RAM/ROM
+ */
+
+// Version 1 (original) format of DeviceParams
+#define	EDGE_MANUF_DESC_ADDR_V1		0x00FF7F00
+#define	EDGE_MANUF_DESC_LEN_V1		sizeof(EDGE_MANUF_DESCRIPTOR_V1)
+
+// Version 2 format of DeviceParams. This format is longer (3C0h)
+// and starts lower in memory, at the uppermost 1K in ROM.
+#define	EDGE_MANUF_DESC_ADDR		0x00FF7C00
+#define	EDGE_MANUF_DESC_LEN		sizeof(EDGE_MANUF_DESCRIPTOR)
+
+// Boot params descriptor
+#define	EDGE_BOOT_DESC_ADDR		0x00FF7FC0
+#define	EDGE_BOOT_DESC_LEN		sizeof(EDGE_BOOT_DESCRIPTOR)
+
+// Define the max block size that may be read or written
+// in a read/write RAM/ROM command.
+#define	MAX_SIZE_REQ_ION_READ_MEM	( (__u16) 64 )
+#define	MAX_SIZE_REQ_ION_WRITE_MEM	( (__u16) 64 )
+
+
+//
+// Notes for the following two ION vendor-specific param descriptors:
+//
+//	1.	These have a standard USB descriptor header so they look like a
+//		normal descriptor.
+//	2.	Any strings in the structures are in USB-defined string
+//		descriptor format, so that they may be separately retrieved,
+//		if necessary, with a minimum of work on the 930. This also
+//		requires them to be in UNICODE format, which, for English at
+//		least, simply means extending each UCHAR into a USHORT.
+//	3.	For all fields, 00 means 'uninitialized'.
+//	4.	All unused areas should be set to 00 for future expansion.
+//
+
+// This structure is ver 2 format. It contains ALL USB descriptors as
+// well as the configuration parameters that were in the original V1
+// structure. It is NOT modified when new boot code is downloaded; rather,
+// these values are set or modified by manufacturing. It is located at
+// xC00-xFBF (length 3C0h) in the ROM.
+// This structure is a superset of the v1 structure and is arranged so
+// that all of the v1 fields remain at the same address. We are just
+// adding more room to the front of the structure to hold the descriptors.
+//
+// The actual contents of this structure are defined in a 930 assembly
+// file, converted to a binary image, and then written by the serialization
+// program. The C definition of this structure just defines a dummy
+// area for general USB descriptors and the descriptor tables (the root
+// descriptor starts at xC00). At the bottom of the structure are the
+// fields inherited from the v1 structure.
+
+#define MAX_SERIALNUMBER_LEN	12
+#define MAX_ASSEMBLYNUMBER_LEN	14
+
+typedef struct _EDGE_MANUF_DESCRIPTOR {
+
+	__u16	RootDescTable[0x10];			// C00 Root of descriptor tables (just a placeholder)
+	__u8	DescriptorArea[0x2E0];			// C20 Descriptors go here, up to 2E0h (just a placeholder)
+
+							//     Start of v1-compatible section
+	__u8	Length;					// F00 Desc length for what follows, per USB (= C0h )
+	__u8	DescType;				// F01 Desc type, per USB (=DEVICE type)
+	__u8	DescVer;				// F02 Desc version/format (currently 2)
+	__u8	NumRootDescEntries;			// F03 # entries in RootDescTable
+
+	__u8	RomSize;				// F04 Size of ROM/E2PROM in K
+	__u8	RamSize;				// F05 Size of external RAM in K
+	__u8	CpuRev;					// F06 CPU revision level (chg only if s/w visible)
+	__u8	BoardRev;				// F07 PCB revision level (chg only if s/w visible)
+
+	__u8	NumPorts;				// F08 Number of ports
+	__u8	DescDate[3];				// F09 MM/DD/YY when descriptor template was compiler,
+							//	   so host can track changes to USB-only descriptors.
+
+	__u8	SerNumLength;				// F0C USB string descriptor len
+	__u8	SerNumDescType;				// F0D USB descriptor type (=STRING type)
+	__u16	SerialNumber[MAX_SERIALNUMBER_LEN];	// F0E "01-01-000100" Unicode Serial Number
+
+	__u8	AssemblyNumLength;			// F26 USB string descriptor len
+	__u8	AssemblyNumDescType;			// F27 USB descriptor type (=STRING type)
+	__u16	AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN];	// F28 "350-1000-01-A " assembly number
+
+	__u8	OemAssyNumLength;			// F44 USB string descriptor len
+	__u8	OemAssyNumDescType;			// F45 USB descriptor type (=STRING type)
+	__u16	OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN];	// F46 "xxxxxxxxxxxxxx" OEM assembly number
+
+	__u8	ManufDateLength;			// F62 USB string descriptor len
+	__u8	ManufDateDescType;			// F63 USB descriptor type (=STRING type)
+	__u16	ManufDate[6];				// F64 "MMDDYY" manufacturing date
+
+	__u8	Reserved3[0x4D];			// F70 -- unused, set to 0 --
+
+	__u8	UartType;				// FBD Uart Type
+	__u8	IonPid;					// FBE Product ID, == LSB of USB DevDesc.PID
+							//     (Note: Edgeport/4s before 11/98 will have
+							//		00 here instead of 01)
+	__u8	IonConfig;				// FBF Config byte for ION manufacturing use
+							// FBF end of structure, total len = 3C0h
+
+} EDGE_MANUF_DESCRIPTOR, *PEDGE_MANUF_DESCRIPTOR;
+
+
+#define MANUF_DESC_VER_1	1	// Original definition of MANUF_DESC
+#define MANUF_DESC_VER_2	2	// Ver 2, starts at xC00h len 3C0h
+
+
+// Uart Types
+// Note: Since this field was added only recently, all Edgeport/4 units
+// shipped before 11/98 will have 00 in this field. Therefore,
+// both 00 and 01 values mean '654.
+#define MANUF_UART_EXAR_654_EARLY	0	// Exar 16C654 in Edgeport/4s before 11/98
+#define MANUF_UART_EXAR_654		1	// Exar 16C654
+#define MANUF_UART_EXAR_2852		2	// Exar 16C2852 
+
+//
+// Note: The CpuRev and BoardRev values do not conform to manufacturing
+// revisions; they are to be incremented only when the CPU or hardware
+// changes in a software-visible way, such that the 930 software or
+// the host driver needs to handle the hardware differently.
+//
+
+// Values of bottom 5 bits of CpuRev & BoardRev for
+// Implementation 0 (ie, 930-based)
+#define	MANUF_CPU_REV_AD4		1	// 930 AD4, with EP1 Rx bug (needs RXSPM)
+#define	MANUF_CPU_REV_AD5		2	// 930 AD5, with above bug (supposedly) fixed
+#define	MANUF_CPU_80251			0x20	// Intel 80251
+
+
+#define MANUF_BOARD_REV_A		1	// Original version, == Manuf Rev A
+#define MANUF_BOARD_REV_B		2	// Manuf Rev B, wakeup interrupt works
+#define MANUF_BOARD_REV_C		3	// Manuf Rev C, 2/4 ports, rs232/rs422
+#define MANUF_BOARD_REV_GENERATION_2	0x20	// Second generaiton edgeport
+
+
+
+
+// Values of bottom 5 bits of CpuRev & BoardRev for
+// Implementation 1 (ie, 251+Netchip-based)
+#define	MANUF_CPU_REV_1			1	// C251TB Rev 1 (Need actual Intel rev here)
+
+#define MANUF_BOARD_REV_A		1	// First rev of 251+Netchip design
+
+
+
+#define	MANUF_SERNUM_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->SerialNumber)
+#define	MANUF_ASSYNUM_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->AssemblyNumber)
+#define	MANUF_OEMASSYNUM_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->OemAssyNumber)
+#define	MANUF_MANUFDATE_LENGTH		sizeof(((PEDGE_MANUF_DESCRIPTOR)0)->ManufDate)
+
+#define	MANUF_ION_CONFIG_MASTER		0x80	// 1=Master mode, 0=Normal
+#define	MANUF_ION_CONFIG_DIAG		0x40	// 1=Run h/w diags, 0=norm
+#define	MANUF_ION_CONFIG_DIAG_NO_LOOP	0x20	// As above but no ext loopback test
+
+
+//
+// This structure describes parameters for the boot code, and
+// is programmed along with new boot code. These are values
+// which are specific to a given build of the boot code. It
+// is exactly 64 bytes long and is fixed at address FF:xFC0
+// - FF:xFFF. Note that the 930-mandated UCONFIG bytes are
+// included in this structure.
+//
+typedef struct _EDGE_BOOT_DESCRIPTOR {
+	__u8		Length;			// C0 Desc length, per USB (= 40h)
+	__u8		DescType;		// C1 Desc type, per USB (= DEVICE type)
+	__u8		DescVer;		// C2 Desc version/format
+	__u8		Reserved1;		// C3 -- unused, set to 0 --
+
+	__u16		BootCodeLength;		// C4 Boot code goes from FF:0000 to FF:(len-1)
+						//	  (LE format)
+
+	__u8		MajorVersion;		// C6 Firmware version: xx.
+	__u8		MinorVersion;		// C7			yy.
+	__u16		BuildNumber;		// C8			zzzz (LE format)
+	
+	__u16		EnumRootDescTable;	// CA Root of ROM-based descriptor table
+	__u8		NumDescTypes;		// CC Number of supported descriptor types
+
+	__u8		Reserved4;		// CD Fix Compiler Packing
+
+	__u16		Capabilities;		// CE-CF Capabilities flags (LE format)
+	__u8		Reserved2[0x28];	// D0 -- unused, set to 0 --
+	__u8		UConfig0;		// F8 930-defined CPU configuration byte 0
+	__u8		UConfig1;		// F9 930-defined CPU configuration byte 1
+	__u8		Reserved3[6];		// FA -- unused, set to 0 --
+						// FF end of structure, total len = 80
+
+} EDGE_BOOT_DESCRIPTOR, *PEDGE_BOOT_DESCRIPTOR;
+
+
+#define BOOT_DESC_VER_1		1	// Original definition of BOOT_PARAMS
+#define BOOT_DESC_VER_2		2	// 2nd definition, descriptors not included in boot
+
+
+	// Capabilities flags
+
+#define	BOOT_CAP_RESET_CMD	0x0001	// If set, boot correctly supports ION_RESET_DEVICE
+
+#endif	// if !defined()
+
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.4.2/linux/drivers/usb/serial/keyspan.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/keyspan.c	Fri Mar  2 17:50:22 2001
@@ -839,9 +839,6 @@
 	p_priv = (struct keyspan_port_private *)(port->private);
 
 	/* Set some sane defaults */
-	p_priv->baud = 9600;
-	p_priv->cflag = CREAD | CLOCAL;
-	p_priv->flow_control = flow_none;
 	p_priv->rts_state = 1;
 	p_priv->dtr_state = 1;
 
@@ -854,16 +851,8 @@
 			dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err);
 		}
 	}
-/*    Now done in startup routine
-	if (atomic_inc_return(&s_priv->active_count) == 1) {
-		s_priv->instat_urb->dev = serial->dev;
-		if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
-			dbg(__FUNCTION__ " submit instat urb failed %d", err);
-		}
-	}
-*/
 
-	keyspan_send_setup(port);
+	keyspan_set_termios(port, NULL);
 
 	return (0);
 }
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- v2.4.2/linux/drivers/usb/serial/mct_u232.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/mct_u232.c	Fri Mar 23 11:50:01 2001
@@ -346,8 +346,8 @@
 			mct_u232_close (&serial->port[i], NULL);
 		}
 		/* My special items, the standard routines free my urbs */
-		if (serial->port->private)
-			kfree(serial->port->private);
+		if (serial->port[i].private)
+			kfree(serial->port[i].private);
 	}
 } /* mct_u232_shutdown */
 
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- v2.4.2/linux/drivers/usb/serial/omninet.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/omninet.c	Fri Mar 23 11:50:01 2001
@@ -305,8 +305,6 @@
 		return (0);
 	}
 
-	usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
-	
 	spin_lock_irqsave (&port->port_lock, flags);
 	
 	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
@@ -318,6 +316,7 @@
 		memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
 	}
 
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, wport->write_urb->transfer_buffer);
 
 	header->oh_seq 	= od->od_outseq++;
 	header->oh_len 	= count;
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.4.2/linux/drivers/usb/serial/usbserial.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/usbserial.c	Fri Mar 23 11:50:01 2001
@@ -827,8 +827,6 @@
 		spin_lock_irqsave (&port->port_lock, flags);
 		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
-		usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
-
 		if (from_user) {
 			copy_from_user(port->write_urb->transfer_buffer, buf, count);
 		}
@@ -836,6 +834,8 @@
 			memcpy (port->write_urb->transfer_buffer, buf, count);
 		}  
 
+		usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+
 		/* set up our urb */
 		FILL_BULK_URB(port->write_urb, serial->dev, 
 			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
@@ -1211,6 +1211,7 @@
 	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
 	max_endpoints = MAX(num_bulk_in, num_bulk_out);
 	max_endpoints = MAX(max_endpoints, num_interrupt_in);
+	max_endpoints = MAX(max_endpoints, serial->num_ports);
 	dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = &serial->port[i];
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.4.2/linux/drivers/usb/serial/visor.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/visor.c	Mon Mar 19 17:21:54 2001
@@ -159,7 +159,7 @@
 
 
 #define NUM_URBS			24
-#define URB_TRANSFER_BUFFER_SIZE	64
+#define URB_TRANSFER_BUFFER_SIZE	768
 static struct urb	*write_urb_pool[NUM_URBS];
 static spinlock_t	write_urb_pool_lock;
 static int		bytes_in;
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- v2.4.2/linux/drivers/usb/serial/whiteheat.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/serial/whiteheat.c	Fri Mar 23 11:50:01 2001
@@ -1,7 +1,7 @@
 /*
  * USB ConnectTech WhiteHEAT driver
  *
- *	Copyright (C) 1999, 2000
+ *	Copyright (C) 1999 - 2001
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,11 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * 2001_Mar_19 gkh
+ *	Fixed MOD_INC and MOD_DEC logic, the ability to open a port more 
+ *	than once, and the got the proper usb_device_id table entries so
+ *	the driver works again.
+ *
  * (11/01/2000) Adam J. Richter
  *	usb_device_id table support
  * 
@@ -93,7 +98,7 @@
 };
 
 static __devinitdata struct usb_device_id id_table_prerenumeration [] = {
-	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
+	{ USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
 	{ }						/* Terminating entry */
 };
 
@@ -289,43 +294,44 @@
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
-	if (port->active) {
-		dbg (__FUNCTION__ " - device already open");
-		return -EINVAL;
-	}
-	port->active = 1;
-
-	/* set up some stuff for our command port */
-	command_port = &port->serial->port[COMMAND_PORT];
-	if (command_port->private == NULL) {
-		info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
-		if (info == NULL) {
-			err(__FUNCTION__ " - out of memory");
-			return -ENOMEM;
+	++port->open_count;
+	MOD_INC_USE_COUNT;
+	
+	if (!port->active) {
+		port->active = 1;
+
+		/* set up some stuff for our command port */
+		command_port = &port->serial->port[COMMAND_PORT];
+		if (command_port->private == NULL) {
+			info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+			if (info == NULL) {
+				err(__FUNCTION__ " - out of memory");
+				return -ENOMEM;
+			}
+			
+			init_waitqueue_head(&info->wait_command);
+			command_port->private = info;
+			command_port->write_urb->complete = command_port_write_callback;
+			command_port->read_urb->complete = command_port_read_callback;
+			command_port->read_urb->dev = port->serial->dev;
+			command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
+			usb_submit_urb (command_port->read_urb);
 		}
 		
-		init_waitqueue_head(&info->wait_command);
-		command_port->private = info;
-		command_port->write_urb->complete = command_port_write_callback;
-		command_port->read_urb->complete = command_port_read_callback;
-		command_port->read_urb->dev = port->serial->dev;
-		command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
-		usb_submit_urb (command_port->read_urb);
-	}
+		/* Start reading from the device */
+		port->read_urb->dev = port->serial->dev;
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	
+		/* send an open port command */
+		/* firmware uses 1 based port numbering */
+		open_command.port = port->number - port->serial->minor + 1;
+		whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
 	
-	/* Start reading from the device */
-	port->read_urb->dev = port->serial->dev;
-	result = usb_submit_urb(port->read_urb);
-	if (result)
-		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-
-	/* send an open port command */
-	/* firmware uses 1 based port numbering */
-	open_command.port = port->number - port->serial->minor + 1;
-	whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
-
-	/* Need to do device specific setup here (control lines, baud rate, etc.) */
-	/* FIXME!!! */
+		/* Need to do device specific setup here (control lines, baud rate, etc.) */
+		/* FIXME!!! */
+	}
 
 	dbg(__FUNCTION__ " - exit");
 	
@@ -339,18 +345,23 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 	
-	/* send a close command to the port */
-	/* firmware uses 1 based port numbering */
-	close_command.port = port->number - port->serial->minor + 1;
-	whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+	--port->open_count;
 
-	/* Need to change the control lines here */
-	/* FIXME */
+	if (port->open_count <= 0) {
+		/* send a close command to the port */
+		/* firmware uses 1 based port numbering */
+		close_command.port = port->number - port->serial->minor + 1;
+		whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
 	
-	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	port->active = 0;
+		/* Need to change the control lines here */
+		/* FIXME */
+		
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		port->active = 0;
+	}
+	MOD_DEC_USE_COUNT;
 }
 
 
@@ -548,8 +559,16 @@
 static void whiteheat_shutdown (struct usb_serial *serial)
 {
 	struct usb_serial_port 		*command_port;
+	int i;
 
 	dbg(__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			whiteheat_close (&serial->port[i], NULL);
+		}
+	}
 
 	/* free up our private data for our command port */
 	command_port = &serial->port[COMMAND_PORT];
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/storage/usb.h linux/drivers/usb/storage/usb.h
--- v2.4.2/linux/drivers/usb/storage/usb.h	Sat Feb  3 19:51:30 2001
+++ linux/drivers/usb/storage/usb.h	Fri Mar 23 18:24:40 2001
@@ -181,7 +181,7 @@
 extern struct semaphore us_list_semaphore;
 
 /* The structure which defines our driver */
-struct usb_driver usb_storage_driver;
+extern struct usb_driver usb_storage_driver;
 
 /* Function to fill an inquiry response. See usb.c for details */
 extern void fill_inquiry_response(struct us_data *us,
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.2/linux/drivers/usb/uhci.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/uhci.c	Fri Mar 23 11:50:01 2001
@@ -66,6 +66,10 @@
 static int uhci_unlink_generic(struct urb *urb);
 static int uhci_unlink_urb(struct urb *urb);
 
+static int  ports_active(struct uhci *uhci);
+static void suspend_hc(struct uhci *uhci);
+static void wakeup_hc(struct uhci *uhci);
+
 #define min(a,b) (((a)<(b))?(a):(b))
 
 /* If a transfer is still active after this much time, turn off FSBR */
@@ -1767,6 +1771,10 @@
 	}
 	nested_unlock(&uhci->urblist_lock, flags);
 
+	/* enter global suspend if nothing connected */
+	if (!uhci->is_suspended && !ports_active(uhci))
+		suspend_hc(uhci);
+
 	rh_init_int_timer(urb);
 }
 
@@ -2037,19 +2045,21 @@
 		return;
 	outw(status, io_addr + USBSTS);
 
-	if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) {
-		if (status & USBSTS_RD)
-			printk(KERN_INFO "uhci: resume detected, not implemented\n");
+	if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
 		if (status & USBSTS_HSE)
 			printk(KERN_ERR "uhci: host system error, PCI problems?\n");
 		if (status & USBSTS_HCPE)
 			printk(KERN_ERR "uhci: host controller process error. something bad happened\n");
-		if (status & USBSTS_HCH) {
+		if ((status & USBSTS_HCH) && !uhci->is_suspended) {
 			printk(KERN_ERR "uhci: host controller halted. very bad\n");
 			/* FIXME: Reset the controller, fix the offending TD */
 		}
 	}
 
+	if (status & USBSTS_RD) {
+		wakeup_hc(uhci);
+	}
+
 	uhci_free_pending_qhs(uhci);
 
 	spin_lock(&uhci->urb_remove_lock);
@@ -2093,6 +2103,49 @@
 	wait_ms(50);
 	outw(0, io_addr + USBCMD);
 	wait_ms(10);
+}
+
+static void suspend_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	dbg("suspend_hc");
+
+	outw(USBCMD_EGSM, io_addr + USBCMD);
+
+	uhci->is_suspended = 1;
+}
+
+static void wakeup_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	unsigned int status;
+
+	dbg("wakeup_hc");
+
+	outw(0, io_addr + USBCMD);
+	
+	/* wait for EOP to be sent */
+	status = inw(io_addr + USBCMD);
+	while (status & USBCMD_FGR)
+		status = inw(io_addr + USBCMD);
+
+	uhci->is_suspended = 0;
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+static int ports_active(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	int connection = 0;
+	int i;
+
+	for (i = 0; i < uhci->rh.numports; i++)
+		connection |= (inw(io_addr + USBPORTSC1 + i * 2) & 0x1);
+
+	return connection;
 }
 
 static void start_hc(struct uhci *uhci)
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.4.2/linux/drivers/usb/uhci.h	Thu Jan  4 14:52:32 2001
+++ linux/drivers/usb/uhci.h	Fri Mar 23 18:25:00 2001
@@ -321,6 +321,7 @@
 	spinlock_t framelist_lock;
 	struct uhci_framelist *fl;		/* Frame list */
 	int fsbr;				/* Full speed bandwidth reclamation */
+	int is_suspended;
 
 	spinlock_t qh_remove_lock;
 	struct list_head qh_remove_list;
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.4.2/linux/drivers/usb/usb-ohci.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/usb-ohci.c	Fri Mar 23 11:50:01 2001
@@ -12,6 +12,7 @@
  * 
  * History:
  * 
+ * 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
  * 2000/09/26 fixed races in removing the private portion of the urb
  * 2000/09/07 disable bulk and control lists when unlinking the last
  *	endpoint descriptor in order to avoid unrecoverable errors on
@@ -208,7 +209,7 @@
 	 __u32 * ed_p;
 	for (i= 0; i < 32; i++) {
 		j = 5;
-		ed_p = &(ohci->hcca.int_table [i]);
+		ed_p = &(ohci->hcca->int_table [i]);
 		if (*ed_p == 0)
 		    continue;
 		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
@@ -371,7 +372,7 @@
 	ohci_dump_status (controller);
 	if (verbose)
 		ep_print_int_eds (controller, "hcca");
-	dbg ("hcca frame #%04x", controller->hcca.frame_no);
+	dbg ("hcca frame #%04x", controller->hcca->frame_no);
 	ohci_dump_roothub (controller, 1);
 }
 
@@ -555,7 +556,7 @@
 			if (urb->transfer_flags & USB_ISO_ASAP) { 
 				urb->start_frame = ((ed->state == ED_OPER)
 					? (ed->last_iso + 1)
-					: (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
+					: (le16_to_cpu (ohci->hcca->frame_no) + 10)) & 0xffff;
 			}	
 			/* FALLTHROUGH */
 		case PIPE_INTERRUPT:
@@ -751,7 +752,7 @@
 				 * the controller won't ever be touching
 				 * these lists again!!
 				dl_del_list (ohci,
-					le16_to_cpu (ohci->hcca.frame_no) & 1);
+					le16_to_cpu (ohci->hcca->frame_no) & 1);
 				 */
 				warn ("TD leak, %d", cnt);
 
@@ -795,7 +796,7 @@
 {
 	ohci_t * ohci = usb_dev->bus->hcpriv;
 	
-	return le16_to_cpu (ohci->hcca.frame_no);
+	return le16_to_cpu (ohci->hcca->frame_no);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -914,7 +915,7 @@
 		
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
 			inter = 1;
-			for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); 
+			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]); 
 				(*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval); 
 				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
 					inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
@@ -935,7 +936,7 @@
 		} else {
 			for ( i = 0; i < 32; i += inter) {
 				inter = 1;
-				for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
 					*ed_p != 0; 
 					ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
 						inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
@@ -1009,7 +1010,7 @@
 		interval = ed->int_interval;
 
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
-			for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]), inter = 1; 
+			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]), inter = 1; 
 				(*ed_p != 0) && (*ed_p != ed->hwNextED); 
 				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED), 
 				inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) {				
@@ -1036,7 +1037,7 @@
 			ed->ed_prev->hwNextED = ed->hwNextED;
 		} else {
 			for (i = 0; i < 32; i++) {
-				for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
 						*ed_p != 0; 
 						ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
 					// inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
@@ -1148,7 +1149,7 @@
 		}
 	}
 
-	frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
+	frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
 	ed->ed_rm_list = ohci->ed_rm_list[frame];
 	ohci->ed_rm_list[frame] = ed;
 
@@ -1361,8 +1362,8 @@
   	
   	spin_lock_irqsave (&usb_ed_lock, flags);
   	
-	td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0;
-	ohci->hcca.done_head = 0;
+	td_list_hc = le32_to_cpup (&ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
 	
 	while (td_list_hc) {		
 		td_list = (td_t *) bus_to_virt (td_list_hc);
@@ -2018,7 +2019,7 @@
 	writel (0, &ohci->regs->ed_controlhead);
 	writel (0, &ohci->regs->ed_bulkhead);
 	
-	writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
+	writel (ohci->hcca_dma, &ohci->regs->hcca); /* a reset clears this */
    
   	fminterval = 0x2edf;
 	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
@@ -2075,13 +2076,13 @@
 	struct ohci_regs * regs = ohci->regs;
  	int ints; 
 
-	if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
+	if ((ohci->hcca->done_head != 0) && !(le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
 	} else if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0) {
 		return;
 	} 
 
-	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
 
 	if (ints & OHCI_INTR_UE) {
 		ohci->disabled++;
@@ -2111,7 +2112,7 @@
 	}
 
 	if (ints & OHCI_INTR_SF) { 
-		unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
+		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
 		writel (OHCI_INTR_SF, &regs->intrdisable);	
 		if (ohci->ed_rm_list[!frame] != NULL) {
 			dl_del_list (ohci, !frame);
@@ -2139,7 +2140,15 @@
 		return NULL;
 		
 	memset (ohci, 0, sizeof (ohci_t));
-	
+
+	ohci->hcca = pci_alloc_consistent (dev, sizeof *ohci->hcca,
+			&ohci->hcca_dma);
+        if (!ohci->hcca) {
+                kfree (ohci);
+                return NULL;
+        }
+        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+
 	ohci->disabled = 1;
 	ohci->irq = -1;
 	ohci->regs = mem_base;   
@@ -2192,7 +2201,9 @@
     
 	/* unmap the IO address space */
 	iounmap (ohci->regs);
-       
+
+	pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
+		ohci->hcca, ohci->hcca_dma);
 	kfree (ohci);
 }
 
@@ -2290,7 +2301,7 @@
 	
 	/* empty the interrupt branches */
 	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
 	
 	/* no EDs to remove */
 	ohci->ed_rm_list [0] = NULL;
@@ -2320,6 +2331,13 @@
 	unsigned long mem_resource, mem_len;
 	void *mem_base;
 
+	/* blacklisted hardware? */
+	if (id->driver_data) {
+		info ("%s (%s): %s", dev->slot_name,
+			dev->name, (char *) id->driver_data);
+		return -ENODEV;
+	}
+
 	if (pci_enable_device(dev) < 0)
 		return -ENODEV;
 	
@@ -2484,6 +2502,20 @@
 /*-------------------------------------------------------------------------*/
 
 static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
+
+	/*
+	 * AMD-756 [Viper] USB has a serious erratum when used with
+	 * lowspeed devices like mice; oopses have been seen.  The
+	 * vendor workaround needs an NDA ... for now, blacklist it.
+	 */
+	vendor:		0x1022,
+	device:		0x740c,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	driver_data:	(unsigned long) "blacklisted, erratum #4",
+
+} , {
 
 	/* handle any USB OHCI controller */
 	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x10),
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h
--- v2.4.2/linux/drivers/usb/usb-ohci.h	Wed Oct 18 15:28:18 2000
+++ linux/drivers/usb/usb-ohci.h	Mon Mar 19 17:21:54 2001
@@ -346,7 +346,8 @@
 
 
 typedef struct ohci {
-	struct ohci_hcca hcca;		/* hcca */
+	struct ohci_hcca *hcca;		/* hcca */
+	u32 hcca_dma;
 
 	int irq;
 	int disabled;			/* e.g. got a UE, we're hung */
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.4.2/linux/drivers/usb/usb-uhci.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/usb-uhci.c	Sat Mar  3 10:55:48 2001
@@ -2945,10 +2945,9 @@
 	/* Search for the IO base address.. */
 	for (i = 0; i < 6; i++) {
 
-		unsigned int io_addr = dev->resource[i].start;
-		unsigned int io_size =
-		dev->resource[i].end - dev->resource[i].start + 1;
-		if (!(dev->resource[i].flags & IORESOURCE_IO))
+		unsigned int io_addr = pci_resource_start(dev, i);
+		unsigned int io_size = pci_resource_len(dev, i);
+		if (!(pci_resource_flags(dev,i) & IORESOURCE_IO))
 			continue;
 
 		/* Is it already in use? */
diff -u --recursive --new-file v2.4.2/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.2/linux/drivers/usb/usb.c	Wed Feb 21 18:20:36 2001
+++ linux/drivers/usb/usb.c	Fri Mar 23 11:50:01 2001
@@ -39,11 +39,6 @@
 #endif
 #include <linux/usb.h>
 
-#define DEVNUM_ROUND_ROBIN	/***** OPTION *****/
-#ifdef DEVNUM_ROUND_ROBIN
-static int devnum_next = 1;
-#endif
-
 static const int usb_bandwidth_option =
 #ifdef CONFIG_USB_BANDWIDTH
 				1;
@@ -153,7 +148,9 @@
 			down(&driver->serialize);
 			driver->disconnect(dev, interface->private_data);
 			up(&driver->serialize);
-			usb_driver_release_interface(driver, interface);
+			/* if driver->disconnect didn't release the interface */
+			if (interface->driver)
+				usb_driver_release_interface(driver, interface);
 			/*
 			 * This will go through the list looking for another
 			 * driver that can handle the device
@@ -349,6 +346,7 @@
  *
  *	Creates a USB host controller bus structure with the specified 
  *	usb_operations and initializes all the necessary internal objects.
+ *	(For use only by USB Host Controller Drivers.)
  *
  *	If no memory is available, NULL is returned.
  *
@@ -364,6 +362,10 @@
 
 	memset(&bus->devmap, 0, sizeof(struct usb_devmap));
 
+#ifdef DEVNUM_ROUND_ROBIN
+	bus->devnum_next = 1;
+#endif /* DEVNUM_ROUND_ROBIN */
+
 	bus->op = op;
 	bus->root_hub = NULL;
 	bus->hcpriv = NULL;
@@ -382,6 +384,7 @@
  *	usb_free_bus - frees the memory used by a bus structure
  *	@bus: pointer to the bus to free
  *
+ *	(For use only by USB Host Controller Drivers.)
  */
 void usb_free_bus(struct usb_bus *bus)
 {
@@ -395,6 +398,7 @@
  *	usb_register_bus - registers the USB host controller with the usb core
  *	@bus: pointer to the bus to register
  *
+ *	(For use only by USB Host Controller Drivers.)
  */
 void usb_register_bus(struct usb_bus *bus)
 {
@@ -415,6 +419,12 @@
 	info("new USB bus registered, assigned bus number %d", bus->busnum);
 }
 
+/**
+ *	usb_deregister_bus - deregisters the USB host controller
+ *	@bus: pointer to the bus to deregister
+ *
+ *	(For use only by USB Host Controller Drivers.)
+ */
 void usb_deregister_bus(struct usb_bus *bus)
 {
 	info("USB bus %d deregistered", bus->busnum);
@@ -502,56 +512,69 @@
 }
 
 
-/* usb_match_id searches an array of usb_device_id's and returns
-   the first one that matches the device and interface.
-
-   Parameters:
-   	"id" is an array of usb_device_id's is terminated by an entry
-	 containing all zeroes.
-
-	 "dev" and "interface" are the device and interface for which
-	 a match is sought.
-
-   If no match is found or if the "id" pointer is NULL, then
-   usb_match_id returns NULL.
-
-
-   What constitutes a match:
-
-   A zero in any element of a usb_device_id entry is a wildcard
-   (i.e., that field always matches).  For there to be a match,
-   *every* nonzero element of the usb_device_id must match the
-   provided device and interface in.  The comparison is for equality,
-   except for one pair of fields: usb_match_id.bcdDevice_{lo,hi} define
-   an inclusive range that dev->descriptor.bcdDevice must be in.
-
-   If interface->altsettings does not exist (i.e., there are no
-   interfaces defined), then bInterface{Class,SubClass,Protocol}
-   only match if they are all zeroes.
-
-
-   What constitutes a good "usb_device_id"?
-
-   The match algorithm is very simple, so that intelligence in
-   driver selection must come from smart driver id records.
-   Unless you have good reasons to use another selection policy,
-   provide match elements only in related groups:
-
-    * device specifiers (vendor and product IDs; and maybe
-      a revision range for that product);
-    * generic device specs (class/subclass/protocol);
-    * interface specs (class/subclass/protocol).
-    
-   Within those groups, work from least specific to most specific.
-   For example, don't give a product version range without vendor
-   and product IDs.
-
-   "driver_info" is not considered by the kernel matching algorithm,
-   but you can create a wildcard "matches anything" usb_device_id
-   as your driver's "modules.usbmap" entry if you provide only an
-   id with a nonzero "driver_info" field.
-*/   
-
+/**
+ * usb_match_id - find first usb_device_id matching device or interface
+ * @dev: the device whose descriptors are considered when matching
+ * @interface: the interface of interest
+ * @id: array of usb_device_id structures, terminated by zero entry
+ *
+ * usb_match_id searches an array of usb_device_id's and returns
+ * the first one matching the device or interface, or null.
+ * This is used when binding (or rebinding) a driver to an interface.
+ * Most USB device drivers will use this indirectly, through the usb core,
+ * but some layered driver frameworks use it directly.
+ * These device tables are exported with MODULE_DEVICE_TABLE, through
+ * modutils and "modules.usbmap", to support the driver loading
+ * functionality of USB hotplugging.
+ *
+ * What Matches:
+ *
+ * The "match_flags" element in a usb_device_id controls which
+ * members are used.  If the corresponding bit is set, the
+ * value in the device_id must match its corresponding member
+ * in the device or interface descriptor, or else the device_id
+ * does not match.
+ *
+ * "driver_info" is normally used only by device drivers,
+ * but you can create a wildcard "matches anything" usb_device_id
+ * as a driver's "modules.usbmap" entry if you provide an id with
+ * only a nonzero "driver_info" field.  If you do this, the USB device
+ * driver's probe() routine should use additional intelligence to
+ * decide whether to bind to the specified interface.
+ * 
+ * What Makes Good usb_device_id Tables:
+ *
+ * The match algorithm is very simple, so that intelligence in
+ * driver selection must come from smart driver id records.
+ * Unless you have good reasons to use another selection policy,
+ * provide match elements only in related groups, and order match
+ * specifiers from specific to general.  Use the macros provided
+ * for that purpose if you can.
+ *
+ * The most specific match specifiers use device descriptor
+ * data.  These are commonly used with product-specific matches;
+ * the USB_DEVICE macro lets you provide vendor and product IDs,
+ * and you can also matche against ranges of product revisions.
+ * These are widely used for devices with application or vendor
+ * specific bDeviceClass values.
+ *
+ * Matches based on device class/subclass/protocol specifications
+ * are slightly more general; use the USB_DEVICE_INFO macro, or
+ * its siblings.  These are used with single-function devices
+ * where bDeviceClass doesn't specify that each interface has
+ * its own class. 
+ *
+ * Matches based on interface class/subclass/protocol are the
+ * most general; they let drivers bind to any interface on a
+ * multiple-function device.  Use the USB_INTERFACE_INFO
+ * macro, or its siblings, to match class-per-interface style 
+ * devices (as recorded in bDeviceClass).
+ *  
+ * Within those groups, remember that not all combinations are
+ * meaningful.  For example, don't give a product version range
+ * without vendor and product IDs; or specify a protocol without
+ * its associated class and subclass.
+ */   
 const struct usb_device_id *
 usb_match_id(struct usb_device *dev, struct usb_interface *interface,
 	     const struct usb_device_id *id)
@@ -827,7 +850,7 @@
 call_policy (char *verb, struct usb_device *dev)
 { } 
 
-#endif	/* KMOD */
+#endif	/* CONFIG_HOTPLUG */
 
 
 /*
@@ -1639,7 +1662,9 @@
 				down(&driver->serialize);
 				driver->disconnect(dev, interface->private_data);
 				up(&driver->serialize);
-				usb_driver_release_interface(driver, interface);
+				/* if driver->disconnect didn't release the interface */
+				if (interface->driver)
+					usb_driver_release_interface(driver, interface);
 			}
 		}
 	}
@@ -1681,14 +1706,12 @@
 #ifndef DEVNUM_ROUND_ROBIN
 	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
 #else	/* round_robin alloc of devnums */
-	/* Try to allocate the next devnum beginning at devnum_next. */
-	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, devnum_next);
+	/* Try to allocate the next devnum beginning at bus->devnum_next. */
+	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
 	if (devnum >= 128)
 		devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
 
-	devnum_next = devnum + 1;
-	if (devnum_next >= 128)
-		devnum_next = 1;
+	dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
 #endif	/* round_robin alloc of devnums */
 
 	if (devnum < 128) {
diff -u --recursive --new-file v2.4.2/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.4.2/linux/drivers/video/clgenfb.c	Wed Feb 21 18:20:37 2001
+++ linux/drivers/video/clgenfb.c	Tue Mar  6 19:28:33 2001
@@ -1,7 +1,7 @@
 /*
  * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
  *
- * Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 1999-2001 Jeff Garzik <jgarzik@mandrakesoft.com>
  *
  * Contributors (thanks, all!)
  *
diff -u --recursive --new-file v2.4.2/linux/drivers/video/fbcmap.c linux/drivers/video/fbcmap.c
--- v2.4.2/linux/drivers/video/fbcmap.c	Tue Mar  7 10:52:41 2000
+++ linux/drivers/video/fbcmap.c	Fri Mar  2 18:38:39 2001
@@ -3,6 +3,9 @@
  *
  *	Created 15 Jun 1997 by Geert Uytterhoeven
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.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.
@@ -73,9 +76,18 @@
 };
 
 
-    /*
-     *  Allocate a colormap
-     */
+/**
+ *	fb_alloc_cmap - allocate a colormap
+ *	@cmap: frame buffer colormap structure
+ *	@len: length of @cmap
+ *	@transp: boolean, 1 if there is transparency, 0 otherwise
+ *
+ *	Allocates memory for a colormap @cmap.  @len is the
+ *	number of entries in the palette.
+ *
+ *	Returns -1 errno on error, or zero on success.
+ *
+ */
 
 int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp)
 {
@@ -113,9 +125,20 @@
 }
 
 
-    /*
-     *  Copy a colormap
-     */
+/**
+ *	fb_copy_cmap - copy a colormap
+ *	@from: frame buffer colormap structure
+ *	@to: frame buffer colormap structure
+ *	@fsfromto: determine copy method
+ *
+ *	Copy contents of colormap from @from to @to.
+ *
+ *	@fsfromto accepts the following integer parameters:
+ *	0: memcpy function
+ *	1: copy_from_user() function to copy from userspace
+ *	2: copy_to_user() function to copy to userspace
+ *
+ */
 
 void fb_copy_cmap(struct fb_cmap *from, struct fb_cmap *to, int fsfromto)
 {
@@ -159,9 +182,18 @@
 }
 
 
-    /*
-     *  Get the colormap for a screen
-     */
+/**
+ *	fb_get_cmap - get a colormap
+ *	@cmap: frame buffer colormap
+ *	@kspc: boolean, 0 copy local, 1 put_user() function
+ *	@getcolreg: pointer to a function to get a color register
+ *	@info: frame buffer info structure
+ *
+ *	Get a colormap @cmap for a screen of device @info.
+ *
+ *	Returns negative errno on error, or zero on success.
+ *
+ */
 
 int fb_get_cmap(struct fb_cmap *cmap, int kspc,
     	    	int (*getcolreg)(u_int, u_int *, u_int *, u_int *, u_int *,
@@ -205,9 +237,17 @@
 }
 
 
-    /*
-     *  Set the colormap for a screen
-     */
+/**
+ *	fb_set_cmap - set the colormap
+ *	@cmap: frame buffer colormap structure
+ *	@kspc: boolean, 0 copy local, 1 get_user() function
+ *	@info: frame buffer info structure
+ *
+ *	Sets the colormap @cmap for a screen of device @info.
+ *
+ *	Returns negative errno on error, or zero on success.
+ *
+ */
 
 int fb_set_cmap(struct fb_cmap *cmap, int kspc,
     	    	int (*setcolreg)(u_int, u_int, u_int, u_int, u_int,
@@ -253,9 +293,16 @@
 }
 
 
-    /*
-     *  Get the default colormap for a specific screen depth
-     */
+/**
+ *	fb_default_cmap - get default colormap
+ *	@len: size of palette for a depth
+ *
+ *	Gets the default colormap for a specific screen depth.  @len
+ *	is the size of the palette for a particular screen depth.
+ *
+ *	Returns pointer to a frame buffer colormap structure.
+ *
+ */
 
 struct fb_cmap *fb_default_cmap(int len)
 {
@@ -269,9 +316,12 @@
 }
 
 
-    /*
-     *  Invert all default colormaps
-     */
+/**
+ *	fb_invert_cmaps - invert all defaults colormaps
+ *
+ *	Invert all default colormaps.
+ *
+ */
 
 void fb_invert_cmaps(void)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/video/fbgen.c linux/drivers/video/fbgen.c
--- v2.4.2/linux/drivers/video/fbgen.c	Wed Jul 26 11:08:41 2000
+++ linux/drivers/video/fbgen.c	Fri Mar  2 18:38:39 2001
@@ -3,6 +3,9 @@
  *
  *  Created 3 Jan 1998 by Geert Uytterhoeven
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.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.
@@ -25,9 +28,18 @@
 /* ---- `Generic' versions of the frame buffer device operations ----------- */
 
 
-    /*
-     *  Get the Fixed Part of the Display
-     */
+/**
+ *	fbgen_get_fix - get fixed part of display
+ *	@fix: fb_fix_screeninfo structure
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Get the fixed information part of the display and place it
+ *	into @fix for virtual console @con on device @info.
+ *
+ *	Returns negative errno on error, or zero on success.
+ *
+ */
 
 int fbgen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 {
@@ -48,9 +60,18 @@
 }
 
 
-    /*
-     *  Get the User Defined Part of the Display
-     */
+/**
+ *	fbgen_get_var - get user defined part of display
+ *	@var: fb_var_screeninfo structure
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Get the user defined part of the display and place it into @var
+ *	for virtual console @con on device @info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
@@ -67,9 +88,18 @@
 }
 
 
-    /*
-     *  Set the User Defined Part of the Display
-     */
+/**
+ *	fbgen_set_var - set the user defined part of display
+ *	@var: fb_var_screeninfo user defined part of the display
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Set the user defined part of the display as dictated by @var
+ *	for virtual console @con on device @info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
@@ -105,9 +135,19 @@
 }
 
 
-    /*
-     *  Get the Colormap
-     */
+/**
+ *	fbgen_get_cmap - get the colormap
+ *	@cmap: frame buffer colormap structure
+ *	@kspc: boolean, 0 copy local, 1 put_user() function
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Gets the colormap for virtual console @con and places it into
+ *	@cmap for device @info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 		   struct fb_info *info)
@@ -128,9 +168,19 @@
 }
 
 
-    /*
-     *  Set the Colormap
-     */
+/**
+ *	fbgen_set_cmap - set the colormap
+ *	@cmap: frame buffer colormap structure
+ *	@kspc: boolean, 0 copy local, 1 get_user() function
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Sets the colormap @cmap for virtual console @con on
+ *	device @info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 		   struct fb_info *info)
@@ -152,11 +202,20 @@
 }
 
 
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
+/**
+ *	fbgen_pan_display - pan or wrap the display
+ *	@var: frame buffer user defined part of display
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Pan or wrap virtual console @con for device @info.
+ *
+ *	This call looks only at xoffset, yoffset and the
+ *	FB_VMODE_YWRAP flag in @var.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_pan_display(struct fb_var_screeninfo *var, int con,
 		      struct fb_info *info)
@@ -193,9 +252,18 @@
 /* ---- Helper functions --------------------------------------------------- */
 
 
-    /*
-     *  Change the video mode
-     */
+/**
+ *	fbgen_do_set_var - change the video mode
+ *	@var: frame buffer user defined part of display
+ *	@isactive: boolean, 0 inactive, 1 active
+ *	@info: generic frame buffer info structure
+ *
+ *	Change the video mode settings for device @info.  If @isactive
+ *	is non-zero, the changes will be activated immediately.
+ *
+ *	Return negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_do_set_var(struct fb_var_screeninfo *var, int isactive,
 		     struct fb_info_gen *info)
@@ -215,6 +283,15 @@
 }
 
 
+/**
+ *	fbgen_set_disp - set generic display
+ *	@con: virtual console number
+ *	@info: generic frame buffer info structure
+ *
+ *	Sets a display on virtual console @con for device @info.
+ *
+ */
+
 void fbgen_set_disp(int con, struct fb_info_gen *info)
 {
     struct fbgen_hwswitch *fbhw = info->fbhw;
@@ -254,9 +331,15 @@
 }
 
 
-    /*
-     *  Install the current colormap
-     */
+/**
+ *	fbgen_install_cmap - install the current colormap
+ *	@con: virtual console number
+ *	@info: generic frame buffer info structure
+ *
+ *	Installs the current colormap for virtual console @con on
+ *	device @info.
+ *
+ */
 
 void fbgen_install_cmap(int con, struct fb_info_gen *info)
 {
@@ -272,9 +355,18 @@
 }
 
 
-    /*
-     *  Update the `var' structure (called by fbcon.c)
-     */
+/**
+ *	fbgen_update_var - update user defined part of display
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Updates the user defined part of the display ('var'
+ *	structure) on virtual console @con for device @info.
+ *	This function is called by fbcon.c.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int fbgen_update_var(int con, struct fb_info *info)
 {
@@ -290,9 +382,16 @@
 }
 
 
-    /*
-     *  Switch to a different virtual console
-     */
+/**
+ *	fbgen_switch - switch to a different virtual console.
+ *	@con: virtual console number
+ *	@info: frame buffer info structure
+ *
+ *	Switch to virtuall console @con on device @info.
+ *
+ *	Returns zero.
+ *
+ */
 
 int fbgen_switch(int con, struct fb_info *info)
 {
@@ -311,9 +410,14 @@
 }
 
 
-    /*
-     *  Blank the screen
-     */
+/**
+ *	fbgen_blank - blank the screen
+ *	@blank: boolean, 0 unblank, 1 blank
+ *	@info: frame buffer info structure
+ *
+ *	Blank the screen on device @info.
+ *
+ */
 
 void fbgen_blank(int blank, struct fb_info *info)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.4.2/linux/drivers/video/fbmem.c	Wed Feb 21 18:20:37 2001
+++ linux/drivers/video/fbmem.c	Fri Mar  2 18:38:39 2001
@@ -3,6 +3,9 @@
  *
  *  Copyright (C) 1994 Martin Schaller
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.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.
@@ -115,6 +118,8 @@
 extern int sisfb_setup(char*);
 extern int stifb_init(void);
 extern int stifb_setup(char*);
+extern int radeonfb_init(void);
+extern int radeonfb_setup(char*);
 
 static struct {
 	const char *name;
@@ -167,6 +172,9 @@
 #ifdef CONFIG_FB_RIVA
 	{ "riva", rivafb_init, rivafb_setup },
 #endif
+#ifdef CONFIG_FB_RADEON
+	{ "radeon", radeonfb_init, radeonfb_setup },
+#endif
 #ifdef CONFIG_FB_CONTROL
 	{ "controlfb", control_init, control_setup },
 #endif
@@ -683,6 +691,17 @@
 
 static devfs_handle_t devfs_handle;
 
+
+/**
+ *	register_framebuffer - registers a frame buffer device
+ *	@fb_info: frame buffer info structure
+ *
+ *	Registers a frame buffer device @fb_info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
 int
 register_framebuffer(struct fb_info *fb_info)
 {
@@ -732,6 +751,17 @@
 	return 0;
 }
 
+
+/**
+ *	unregister_framebuffer - releases a frame buffer device
+ *	@fb_info: frame buffer info structure
+ *
+ *	Unregisters a frame buffer device @fb_info.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
 int
 unregister_framebuffer(struct fb_info *fb_info)
 {
@@ -752,6 +782,16 @@
 	return 0;
 }
 
+
+/**
+ *	fbmem_init - init frame buffer subsystem
+ *
+ *	Initialize the frame buffer subsystem.
+ *
+ *	NOTE: This function is _only_ to be called by drivers/char/mem.c.
+ *
+ */
+
 void __init 
 fbmem_init(void)
 {
@@ -781,9 +821,18 @@
 			fb_drivers[i].init();
 }
 
-    /*
-     *  Command line options
-     */
+
+/**
+ *	video_setup - process command line options
+ *	@options: string of options
+ *
+ *	Process command line options for frame buffer subsystem.
+ *
+ *	NOTE: This function is a __setup and __init function.
+ *
+ *	Returns zero.
+ *
+ */
 
 int __init video_setup(char *options)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/video/fonts.c linux/drivers/video/fonts.c
--- v2.4.2/linux/drivers/video/fonts.c	Tue Jul 11 15:35:51 2000
+++ linux/drivers/video/fonts.c	Fri Mar  2 18:38:39 2001
@@ -4,6 +4,9 @@
  *    Created 1995 by Geert Uytterhoeven
  *    Rewritten 1998 by Martin Mares <mj@ucw.cz>
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.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.
@@ -61,9 +64,17 @@
 #error No fonts configured.
 #endif
 
-   /*
-    *    Find a font with a specific name
-    */
+
+/**
+ *	fbcon_find_font - find a font
+ *	@name: string name of a font
+ *
+ *	Find a specified font with string name @name.
+ *
+ *	Returns %NULL if no font found, or a pointer to the
+ *	specified font.
+ *
+ */
 
 struct fbcon_font_desc *fbcon_find_font(char *name)
 {
@@ -76,9 +87,18 @@
 }
 
 
-   /*
-    *    Get the default font for a specific screen size
-    */
+/**
+ *	fbcon_get_default_font - get default font
+ *	@xres: screen size of X
+ *	@yres: screen size of Y
+ *
+ *	Get the default font for a specified screen size.
+ *	Dimensions are in pixels.
+ *
+ *	Returns %NULL if no font is found, or a pointer to the
+ *	chosen font.
+ *
+ */
 
 struct fbcon_font_desc *fbcon_get_default_font(int xres, int yres)
 {
diff -u --recursive --new-file v2.4.2/linux/drivers/video/macmodes.c linux/drivers/video/macmodes.c
--- v2.4.2/linux/drivers/video/macmodes.c	Mon Nov 27 17:11:26 2000
+++ linux/drivers/video/macmodes.c	Fri Mar  2 18:38:39 2001
@@ -7,6 +7,9 @@
  *      - Ani Joshi
  *      - Brad Douglas <brad@neruo.com>
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.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.
@@ -203,12 +206,39 @@
 };
 
 
+/**
+ *	console_getmode - get current mode
+ *	@mode: virtual console mode structure
+ *
+ *	Populates @mode with the current mode held in the global
+ *	display_info structure.
+ *
+ *	Note, this function is only for XPMAC compatibility.
+ *
+ *	Returns zero.
+ */
+
 int console_getmode(struct vc_mode *mode)
 {
     *mode = display_info;
     return 0;
 }
 
+
+/**
+ *	console_setmode - sets current console mode
+ *	@mode: virtual console mode structure
+ *	@doit: boolean, 0 test mode, 1 test and activate mode
+ *
+ *	Sets @mode for all virtual consoles if @doit is non-zero,
+ *	otherwise, test a mode for validity.
+ *
+ *	Note, this function is only for XPMAC compatibility.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
 int console_setmode(struct vc_mode *mode, int doit)
 {
     struct fb_var_screeninfo var;
@@ -255,6 +285,23 @@
     return 0;
 }
 
+
+/**
+ *	console_setcmap - sets palette color map for console
+ *	@n_entries: number of entries in the palette (max 16)
+ *	@red: value for red component of palette
+ *	@green: value for green component of palette
+ *	@blue: value for blue component of palette
+ *
+ *	Sets global palette_cmap structure and activates the palette
+ *	on the current console.
+ *
+ *	Note, this function is only for XPMAC compatibility.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
+
 int console_setcmap(int n_entries, unsigned char *red, unsigned char *green,
                     unsigned char *blue)
 {
@@ -285,6 +332,21 @@
     return 0;
 }
 
+
+/**
+ *	console_powermode - sets monitor power mode
+ *	@mode: power state to set
+ *
+ *	Sets power state as dictated by @mode.
+ *
+ *	Note that this function is only for XPMAC compatibility and
+ *	doesn't do much.
+ *
+ *	Returns 0 for %VC_POWERMODE_INQUIRY, -EINVAL for VESA power
+ *	settings, or -ENIXIO on failure.
+ *
+ */
+
 int console_powermode(int mode)
 {
     if (mode == VC_POWERMODE_INQUIRY)
@@ -297,9 +359,18 @@
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 
 
-    /*
-     *  Convert a MacOS vmode/cmode pair to a frame buffer video mode structure
-     */
+/**
+ *	mac_vmode_to_var - converts vmode/cmode pair to var structure
+ *	@vmode: MacOS video mode
+ *	@cmode: MacOS color mode
+ *	@var: frame buffer video mode structure
+ *
+ *	Converts a MacOS vmode/cmode pair to a frame buffer video
+ *	mode structure.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int mac_vmode_to_var(int vmode, int cmode, struct fb_var_screeninfo *var)
 {
@@ -370,9 +441,18 @@
 }
 
 
-    /*
-     *  Convert a frame buffer video mode structure to a MacOS vmode/cmode pair
-     */
+/**
+ *	mac_var_to_vmode - convert var structure to MacOS vmode/cmode pair
+ *	@var: frame buffer video mode structure
+ *	@vmode: MacOS video mode
+ *	@cmode: MacOS color mode
+ *
+ *	Converts a frame buffer video mode structure to a MacOS
+ *	vmode/cmode pair.
+ *
+ *	Returns negative errno on error, or zero for success.
+ *
+ */
 
 int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
 		     int *cmode)
@@ -406,9 +486,16 @@
 }
 
 
-    /*
-     *  Convert a Mac monitor sense number to a MacOS vmode number
-     */
+/**
+ *	mac_map_monitor_sense - Convert monitor sense to vmode
+ *	@sense: Macintosh monitor sense number
+ *
+ *	Converts a Macintosh monitor sense number to a MacOS
+ *	vmode number.
+ *
+ *	Returns MacOS vmode video mode number.
+ *
+ */
 
 int mac_map_monitor_sense(int sense)
 {
@@ -421,12 +508,25 @@
 }
 
 
-    /*
-     *  Find a suitable video mode
-     *
-     *  If the name of the wanted mode begins with `mac', use the Mac video
-     *  mode database, else fall back to the standard video mode database.
-     */
+/**
+ *	mac_find_mode - find a video mode
+ *	@var: frame buffer user defined part of display
+ *	@info: frame buffer info structure
+ *	@mode_option: video mode name (see mac_modedb[])
+ *	@default_bpp: default color depth in bits per pixel
+ *
+ *	Finds a suitable video mode.  Tries to set mode specified
+ *	by @mode_option.  If the name of the wanted mode begins with
+ *	'mac', the Mac video mode database will be used, otherwise it
+ *	will fall back to the standard video mode database.
+ *
+ *	Note: Function marked as __init and can only be used during
+ *	system boot.
+ *
+ *	Returns error code from fb_find_mode (see fb_find_mode
+ *	function).
+ *
+ */
 
 int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
 			 const char *mode_option, unsigned int default_bpp)
diff -u --recursive --new-file v2.4.2/linux/drivers/video/modedb.c linux/drivers/video/modedb.c
--- v2.4.2/linux/drivers/video/modedb.c	Thu Mar 23 10:07:42 2000
+++ linux/drivers/video/modedb.c	Fri Mar  2 18:38:39 2001
@@ -3,6 +3,9 @@
  *
  *	Copyright (C) 1999 Geert Uytterhoeven
  *
+ *	2001 - Documented with DocBook
+ *	- Brad Douglas <brad@neruo.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.
@@ -276,6 +279,20 @@
 	return MINOR(current->tty->device) - 1;
 }
 
+
+/**
+ *	__fb_try_mode - test a video mode
+ *	@var: frame buffer user defined part of display
+ *	@info: frame buffer info structure
+ *	@mode: frame buffer video mode structure
+ *	@bpp: color depth in bits per pixel
+ *
+ *	Tries a video mode to test it's validity for device @info.
+ *
+ *	Returns 1 on success.
+ *
+ */
+
 int __fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
 		  const struct fb_videomode *mode, unsigned int bpp)
 {
@@ -306,21 +323,37 @@
 }
 
 
-    /*
-     *
-     *  Find a suitable video mode
-     *
-     *  Valid mode specifiers (mode_option):
-     *
-     *	<xres>x<yres>[-<bpp>][@<refresh>]
-     *	<name>[-<bpp>][@<refresh>]
-     *
-     *  with <xres>, <yres>, <bpp> and <refresh> decimal numbers and <name> a
-     *  string
-     *
-     *  The passed struct fb_var_screeninfo is _not_ cleared! This allows you
-     *  to supply values for e.g. the grayscale and accel_flags fields.
-     */
+/**
+ *	fb_find_mode - finds a valid video mode
+ *	@var: frame buffer user defined part of display
+ *	@info: frame buffer info structure
+ *	@mode_option: string video mode to find
+ *	@db: video mode database
+ *	@dbsize: size of @db
+ *	@default_mode: default video mode to fall back to
+ *	@default_bpp: default color depth in bits per pixel
+ *
+ *	Finds a suitable video mode, starting with the specified mode
+ *	in @mode_option with fallback to @default_mode.  If
+ *	@default_mode fails, all modes in the video mode database will
+ *	be tried.
+ *
+ *	Valid mode specifiers for @mode_option:
+ *
+ *	<xres>x<yres>[-<bpp>][@<refresh>] or
+ *	<name>[-<bpp>][@<refresh>]
+ *
+ *	with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
+ *	<name> a string.
+ *
+ *	NOTE: The passed struct @var is _not_ cleared!  This allows you
+ *	to supply values for e.g. the grayscale and accel_flags fields.
+ *
+ *	Returns zero for failure, 1 if using specified @mode_option,
+ *	2 if using specified @mode_option with an ignored refresh rate,
+ *	3 if default mode is used, 4 if fall back to any valid mode.
+ *
+ */
 
 int __init fb_find_mode(struct fb_var_screeninfo *var,
 			struct fb_info *info, const char *mode_option,
diff -u --recursive --new-file v2.4.2/linux/drivers/video/sis/sis_301.h linux/drivers/video/sis/sis_301.h
--- v2.4.2/linux/drivers/video/sis/sis_301.h	Sun Nov 12 20:40:42 2000
+++ linux/drivers/video/sis/sis_301.h	Tue Mar  6 19:28:33 2001
@@ -3,7 +3,7 @@
 
 USHORT SetFlag,RVBHCFACT,RVBHCMAX,VGAVT,VGAHT,VT,HT,VGAVDE,VGAHDE;
 USHORT VDE,HDE,RVBHRS,NewFlickerMode,RY1COE,RY2COE,RY3COE,RY4COE;                
-;USHORT LCDResInfo,LCDTypeInfo,LCDInfo;
+extern USHORT LCDResInfo,LCDTypeInfo,LCDInfo;
 USHORT VCLKLen;
 USHORT LCDHDES,LCDVDES;
 
diff -u --recursive --new-file v2.4.2/linux/fs/Makefile linux/fs/Makefile
--- v2.4.2/linux/fs/Makefile	Sat Feb  3 19:51:30 2001
+++ linux/fs/Makefile	Fri Mar  2 15:16:59 2001
@@ -7,7 +7,7 @@
 
 O_TARGET := fs.o
 
-export-objs :=	filesystems.o
+export-objs :=	filesystems.o dcache.o
 mod-subdirs :=	nls
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
diff -u --recursive --new-file v2.4.2/linux/fs/adfs/super.c linux/fs/adfs/super.c
--- v2.4.2/linux/fs/adfs/super.c	Wed Feb 21 18:20:38 2001
+++ linux/fs/adfs/super.c	Fri Mar  2 11:12:11 2001
@@ -385,6 +385,12 @@
 	sb->u.adfs_sb.s_size     = adfs_discsize(dr, sb->s_blocksize_bits);
 	sb->u.adfs_sb.s_version  = dr->format_version;
 	sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize;
+	
+	/*
+	 * Max file size is 2Gb
+	 */
+	 
+	sb->s_maxbytes = MAX_NON_LFS;
 
 	sb->u.adfs_sb.s_map = adfs_read_map(sb, dr);
 	if (!sb->u.adfs_sb.s_map)
diff -u --recursive --new-file v2.4.2/linux/fs/affs/super.c linux/fs/affs/super.c
--- v2.4.2/linux/fs/affs/super.c	Wed Feb 21 18:20:38 2001
+++ linux/fs/affs/super.c	Fri Mar  2 11:12:11 2001
@@ -415,6 +415,12 @@
 
 	s->s_flags |= MS_NODEV | MS_NOSUID;
 
+	/*
+	 * Max file size is 2Gb
+	 */
+	 
+	s->s_maxbytes = MAX_NON_LFS;
+
 	/* Keep super block in cache */
 	bb = affs_bread(dev,root_block,s->s_blocksize);
 	if (!bb)
diff -u --recursive --new-file v2.4.2/linux/fs/bfs/inode.c linux/fs/bfs/inode.c
--- v2.4.2/linux/fs/bfs/inode.c	Tue Nov 28 22:43:39 2000
+++ linux/fs/bfs/inode.c	Fri Mar  2 11:12:11 2001
@@ -250,6 +250,7 @@
 	set_blocksize(dev, BFS_BSIZE);
 	s->s_blocksize = BFS_BSIZE;
 	s->s_blocksize_bits = BFS_BSIZE_BITS;
+	s->s_maxbytes = MAX_NON_LFS;
 
 	bh = bread(dev, 0, BFS_BSIZE);
 	if(!bh)
diff -u --recursive --new-file v2.4.2/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.4.2/linux/fs/binfmt_aout.c	Wed Feb 21 18:20:38 2001
+++ linux/fs/binfmt_aout.c	Mon Mar 19 12:34:56 2001
@@ -342,7 +342,7 @@
 
 		error = bprm->file->f_op->read(bprm->file, (char *)text_addr,
 			  ex.a_text+ex.a_data, &pos);
-		if (error < 0) {
+		if ((signed long)error < 0) {
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
@@ -377,24 +377,24 @@
 			goto beyond_if;
 		}
 
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 		error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text,
 			PROT_READ | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 			fd_offset);
-		up(&current->mm->mmap_sem);
+		up_write(&current->mm->mmap_sem);
 
 		if (error != N_TXTADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
 		}
 
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
  		error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data,
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
-		up(&current->mm->mmap_sem);
+		up_write(&current->mm->mmap_sem);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -476,12 +476,12 @@
 		goto out;
 	}
 	/* Now use mmap to map the library into memory. */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap(file, start_addr, ex.a_text + ex.a_data,
 			PROT_READ | PROT_WRITE | PROT_EXEC,
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
 			N_TXTOFF(ex));
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	retval = error;
 	if (error != start_addr)
 		goto out;
diff -u --recursive --new-file v2.4.2/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.4.2/linux/fs/binfmt_elf.c	Wed Feb 21 18:20:38 2001
+++ linux/fs/binfmt_elf.c	Mon Mar 19 17:05:16 2001
@@ -214,11 +214,11 @@
 {
 	unsigned long map_addr;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	map_addr = do_mmap(filep, ELF_PAGESTART(addr),
 			   eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
 			   eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return(map_addr);
 }
 
@@ -732,10 +732,10 @@
 		   Since we do not have the power to recompile these, we
 		   emulate the SVr4 behavior.  Sigh.  */
 		/* N.B. Shouldn't the size here be PAGE_SIZE?? */
-		down(&current->mm->mmap_sem);
+		down_write(&current->mm->mmap_sem);
 		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE, 0);
-		up(&current->mm->mmap_sem);
+		up_write(&current->mm->mmap_sem);
 	}
 
 #ifdef ELF_PLAT_INIT
@@ -816,7 +816,7 @@
 	while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
 
 	/* Now use mmap to map the library into memory. */
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	error = do_mmap(file,
 			ELF_PAGESTART(elf_phdata->p_vaddr),
 			(elf_phdata->p_filesz +
@@ -825,7 +825,7 @@
 			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
 			(elf_phdata->p_offset -
 			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
 		goto out_free_ph;
 
@@ -1203,15 +1203,15 @@
 			pte_t *pte;
 
 			pgd = pgd_offset(vma->vm_mm, addr);
-			pmd = pmd_alloc(pgd, addr);
+			pmd = pmd_offset(pgd, addr);
 	
 			if (!pmd)
-				goto end_coredump;
-			pte = pte_alloc(pmd, addr);
+				goto nextpage_coredump;
+			pte = pte_offset(pmd, addr);
 			if (!pte)
-				goto end_coredump;
-			if (!pte_present(*pte) &&
-			    pte_none(*pte)) {
+				goto nextpage_coredump;
+			if (pte_none(*pte)) {
+nextpage_coredump:
 				DUMP_SEEK (file->f_pos + PAGE_SIZE);
 			} else {
 				DUMP_WRITE((void*)addr, PAGE_SIZE);
diff -u --recursive --new-file v2.4.2/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.2/linux/fs/buffer.c	Wed Feb 21 18:20:38 2001
+++ linux/fs/buffer.c	Wed Mar 21 20:28:28 2001
@@ -1880,8 +1880,8 @@
 	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
 	
 	page = grab_cache_page(mapping, index);
-	err = PTR_ERR(page);
-	if (IS_ERR(page))
+	err = -ENOMEM;
+	if (!page)
 		goto out;
 
 	if (!page->buffers)
@@ -2750,7 +2750,7 @@
 
 	tsk->session = 1;
 	tsk->pgrp = 1;
-	strcpy(tsk->comm, "kupdate");
+	strcpy(tsk->comm, "kupdated");
 
 	/* sigstop and sigcont will stop and wakeup kupdate */
 	spin_lock_irq(&tsk->sigmask_lock);
diff -u --recursive --new-file v2.4.2/linux/fs/coda/inode.c linux/fs/coda/inode.c
--- v2.4.2/linux/fs/coda/inode.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/coda/inode.c	Fri Mar  2 11:12:11 2001
@@ -141,6 +141,7 @@
         sb->s_magic = CODA_SUPER_MAGIC;
         sb->s_dev = dev;
         sb->s_op = &coda_super_operations;
+	sb->s_maxbytes = MAX_NON_LFS;
 
 	/* get root fid from Venus: this needs the root inode */
 	error = venus_rootfid(sb, &fid);
diff -u --recursive --new-file v2.4.2/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- v2.4.2/linux/fs/cramfs/inode.c	Fri Dec 29 14:07:57 2000
+++ linux/fs/cramfs/inode.c	Fri Mar  2 11:12:11 2001
@@ -194,9 +194,9 @@
 
 	/* Set it all up.. */
 	sb->s_op	= &cramfs_ops;
-	sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
+	sb->s_root 	= d_alloc_root(get_cramfs_inode(sb, &super.root));
+	sb->s_maxbytes = MAX_NON_LFS;
 	retval = sb;
-
 out:
 	return retval;
 }
diff -u --recursive --new-file v2.4.2/linux/fs/dcache.c linux/fs/dcache.c
--- v2.4.2/linux/fs/dcache.c	Wed Feb 21 18:20:38 2001
+++ linux/fs/dcache.c	Wed Mar  7 16:53:48 2001
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/cache.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 
@@ -223,8 +224,7 @@
 	atomic_inc(&dentry->d_count);
 	if (atomic_read(&dentry->d_count) == 1) {
 		dentry_stat.nr_unused--;
-		list_del(&dentry->d_lru);
-		INIT_LIST_HEAD(&dentry->d_lru);		/* make "list_empty()" work */
+		list_del_init(&dentry->d_lru);
 	}
 	return dentry;
 }
@@ -413,8 +413,7 @@
 		if (atomic_read(&dentry->d_count))
 			continue;
 		dentry_stat.nr_unused--;
-		list_del(tmp);
-		INIT_LIST_HEAD(tmp);
+		list_del_init(tmp);
 		prune_one_dentry(dentry);
 		goto repeat;
 	}
@@ -656,6 +655,7 @@
  
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
+	if (!list_empty(&entry->d_alias)) BUG();
 	spin_lock(&dcache_lock);
 	if (inode)
 		list_add(&entry->d_alias, &inode->i_dentry);
@@ -744,58 +744,48 @@
 
 /**
  * d_validate - verify dentry provided from insecure source
- * @dentry: The dentry alleged to be valid
- * @dparent: The parent dentry
+ * @dentry: The dentry alleged to be valid child of @dparent
+ * @dparent: The parent dentry (known to be valid)
  * @hash: Hash of the dentry
  * @len: Length of the name
  *
  * An insecure source has sent us a dentry, here we verify it and dget() it.
  * This is used by ncpfs in its readdir implementation.
  * Zero is returned in the dentry is invalid.
- *
- * NOTE: This function does _not_ dereference the pointers before we have
- * validated them. We can test the pointer values, but we
- * must not actually use them until we have found a valid
- * copy of the pointer in kernel space..
  */
  
-int d_validate(struct dentry *dentry, struct dentry *dparent,
-	       unsigned int hash, unsigned int len)
+int d_validate(struct dentry *dentry, struct dentry *dparent)
 {
+	unsigned long dent_addr = (unsigned long) dentry;
+	unsigned long min_addr = PAGE_OFFSET;
+	unsigned long align_mask = 0x0F;
 	struct list_head *base, *lhp;
-	int valid = 1;
 
-	spin_lock(&dcache_lock);
-	if (dentry != dparent) {
-		base = d_hash(dparent, hash);
-		lhp = base;
-		while ((lhp = lhp->next) != base) {
-			if (dentry == list_entry(lhp, struct dentry, d_hash)) {
-				__dget_locked(dentry);
-				goto out;
-			}
-		}
-	} else {
-		/*
-		 * Special case: local mount points don't live in
-		 * the hashes, so we search the super blocks.
-		 */
-		struct super_block *sb = sb_entry(super_blocks.next);
+	if (dent_addr < min_addr)
+		goto out;
+	if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))
+		goto out;
+	if (dent_addr & align_mask)
+		goto out;
+	if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
+						sizeof(struct dentry))))
+		goto out;
 
-		for (; sb != sb_entry(&super_blocks); 
-		     sb = sb_entry(sb->s_list.next)) {
-			if (!sb->s_dev)
-				continue;
-			if (sb->s_root == dentry) {
-				__dget_locked(dentry);
-				goto out;
-			}
+	if (dentry->d_parent != dparent)
+		goto out;
+
+	spin_lock(&dcache_lock);
+	lhp = base = d_hash(dparent, dentry->d_name.hash);
+	while ((lhp = lhp->next) != base) {
+		if (dentry == list_entry(lhp, struct dentry, d_hash)) {
+			__dget_locked(dentry);
+			spin_unlock(&dcache_lock);
+			return 1;
 		}
 	}
-	valid = 0;
-out:
 	spin_unlock(&dcache_lock);
-	return valid;
+out:
+	return 0;
 }
 
 /*
@@ -848,6 +838,7 @@
 void d_rehash(struct dentry * entry)
 {
 	struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);
+	if (!list_empty(&entry->d_hash)) BUG();
 	spin_lock(&dcache_lock);
 	list_add(&entry->d_hash, list);
 	spin_unlock(&dcache_lock);
@@ -922,8 +913,7 @@
 	list_add(&dentry->d_hash, &target->d_hash);
 
 	/* Unhash the target: dput() will then get rid of it */
-	list_del(&target->d_hash);
-	INIT_LIST_HEAD(&target->d_hash);
+	list_del_init(&target->d_hash);
 
 	list_del(&dentry->d_child);
 	list_del(&target->d_child);
@@ -1250,6 +1240,7 @@
 
 /* SLAB cache for buffer_head structures */
 kmem_cache_t *bh_cachep;
+EXPORT_SYMBOL(bh_cachep);
 
 void __init vfs_caches_init(unsigned long mempages)
 {
diff -u --recursive --new-file v2.4.2/linux/fs/efs/super.c linux/fs/efs/super.c
--- v2.4.2/linux/fs/efs/super.c	Wed Jun 21 10:10:02 2000
+++ linux/fs/efs/super.c	Fri Mar  2 11:12:11 2001
@@ -178,6 +178,8 @@
 	s->s_magic		= EFS_SUPER_MAGIC;
 	s->s_blocksize		= EFS_BLOCKSIZE;
 	s->s_blocksize_bits	= EFS_BLOCKSIZE_BITS;
+	s->s_maxbytes		= MAX_NON_LFS;
+
 	if (!(s->s_flags & MS_RDONLY)) {
 #ifdef DEBUG
 		printk(KERN_INFO "EFS: forcing read-only mode\n");
diff -u --recursive --new-file v2.4.2/linux/fs/exec.c linux/fs/exec.c
--- v2.4.2/linux/fs/exec.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/exec.c	Thu Mar 22 09:26:18 2001
@@ -252,6 +252,8 @@
 /*
  * This routine is used to map in a page into an address space: needed by
  * execve() for the initial stack and environment pages.
+ *
+ * tsk->mmap_sem is held for writing.
  */
 void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
 {
@@ -262,27 +264,29 @@
 	if (page_count(page) != 1)
 		printk("mem_map disagrees with %p at %08lx\n", page, address);
 	pgd = pgd_offset(tsk->mm, address);
-	pmd = pmd_alloc(pgd, address);
-	if (!pmd) {
-		__free_page(page);
-		force_sig(SIGKILL, tsk);
-		return;
-	}
-	pte = pte_alloc(pmd, address);
-	if (!pte) {
-		__free_page(page);
-		force_sig(SIGKILL, tsk);
-		return;
-	}
-	if (!pte_none(*pte)) {
-		pte_ERROR(*pte);
-		__free_page(page);
-		return;
-	}
+
+	spin_lock(&tsk->mm->page_table_lock);
+	pmd = pmd_alloc(tsk->mm, pgd, address);
+	if (!pmd)
+		goto out;
+	pte = pte_alloc(tsk->mm, pmd, address);
+	if (!pte)
+		goto out;
+	if (!pte_none(*pte))
+		goto out;
 	flush_dcache_page(page);
 	flush_page_to_ram(page);
 	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
-/* no need for flush_tlb */
+	tsk->mm->rss++;
+	spin_unlock(&tsk->mm->page_table_lock);
+
+	/* no need for flush_tlb */
+	return;
+out:
+	spin_unlock(&tsk->mm->page_table_lock);
+	__free_page(page);
+	force_sig(SIGKILL, tsk);
+	return;
 }
 
 int setup_arg_pages(struct linux_binprm *bprm)
@@ -302,7 +306,7 @@
 	if (!mpnt) 
 		return -ENOMEM; 
 	
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	{
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
@@ -321,12 +325,11 @@
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			current->mm->rss++;
 			put_dirty_page(current,page,stack_base);
 		}
 		stack_base += PAGE_SIZE;
 	}
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	
 	return 0;
 }
diff -u --recursive --new-file v2.4.2/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.4.2/linux/fs/ext2/ialloc.c	Fri Dec  8 17:35:54 2000
+++ linux/fs/ext2/ialloc.c	Fri Mar 23 12:15:07 2001
@@ -442,6 +442,7 @@
 	inode->u.ext2_i.i_file_acl = 0;
 	inode->u.ext2_i.i_dir_acl = 0;
 	inode->u.ext2_i.i_dtime = 0;
+	inode->u.ext2_i.i_prealloc_count = 0;
 	inode->u.ext2_i.i_block_group = i;
 	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
diff -u --recursive --new-file v2.4.2/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.4.2/linux/fs/ext2/inode.c	Fri Dec 29 14:36:44 2000
+++ linux/fs/ext2/inode.c	Fri Mar 23 12:15:29 2001
@@ -1047,6 +1047,7 @@
 		inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
 	}
 	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
+	inode->u.ext2_i.i_prealloc_count = 0;
 	inode->u.ext2_i.i_block_group = block_group;
 
 	/*
diff -u --recursive --new-file v2.4.2/linux/fs/hfs/super.c linux/fs/hfs/super.c
--- v2.4.2/linux/fs/hfs/super.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/hfs/super.c	Fri Mar  2 11:12:11 2001
@@ -436,6 +436,7 @@
 		goto bail1;
 	}
 
+	s->s_maxbytes = MAX_NON_LFS;
 	s->s_magic = HFS_SUPER_MAGIC;
 	s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS;
 	s->s_blocksize = HFS_SECTOR_SIZE;
diff -u --recursive --new-file v2.4.2/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.4.2/linux/fs/hpfs/super.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/hpfs/super.c	Fri Mar  2 11:12:11 2001
@@ -427,6 +427,7 @@
 	s->s_blocksize = 512;
 	s->s_blocksize_bits = 9;
 	s->s_op = &hpfs_sops;
+	s->s_maxbytes = MAX_NON_LFS;
 
 	s->s_hpfs_root = superblock->root;
 	s->s_hpfs_fs_size = superblock->n_sectors;
diff -u --recursive --new-file v2.4.2/linux/fs/inode.c linux/fs/inode.c
--- v2.4.2/linux/fs/inode.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/inode.c	Thu Mar 22 11:04:13 2001
@@ -133,7 +133,7 @@
 
 	if (sb) {
 		/* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself */
-		if (flags & (I_DIRTY | I_DIRTY_SYNC)) {
+		if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
 			if (sb->s_op && sb->s_op->dirty_inode)
 				sb->s_op->dirty_inode(inode);
 		}
@@ -613,6 +613,7 @@
 	inode->i_bdev = 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;
 }
 
diff -u --recursive --new-file v2.4.2/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.4.2/linux/fs/isofs/inode.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/isofs/inode.c	Fri Mar  2 11:12:11 2001
@@ -616,7 +616,7 @@
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
 	  if (isonum_723 (h_pri->volume_set_size) != 1)
 		goto out_no_support;
-#endif IGNORE_WRONG_MULTI_VOLUME_SPECS
+#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */
 	  s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size);
 	  s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size);
 	  s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size);
@@ -625,7 +625,7 @@
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
 	  if (isonum_723 (pri->volume_set_size) != 1)
 		goto out_no_support;
-#endif IGNORE_WRONG_MULTI_VOLUME_SPECS
+#endif /* IGNORE_WRONG_MULTI_VOLUME_SPECS */
 	  s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size);
 	  s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size);
 	  s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size);
@@ -662,6 +662,11 @@
 	   Rock Ridge extensions) */
 
 	s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
+
+	/* Set this for reference. Its not currently used except on write
+	   which we don't have .. */
+	   
+	s->s_maxbytes = MAX_NON_LFS;
 
 	/* RDE: data zone now byte offset! */
 
diff -u --recursive --new-file v2.4.2/linux/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c
--- v2.4.2/linux/fs/jffs/inode-v23.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/jffs/inode-v23.c	Fri Mar  2 11:12:11 2001
@@ -10,8 +10,8 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: inode-v23.c,v 1.43 2000/08/22 08:00:22 dwmw2 Exp $
- *
+ * $Id: inode-v23.c,v 1.43.2.6 2001/01/09 00:32:48 dwmw2 Exp $
+ * + sb_maxbytes / generic_file_open() fixes for 2.4.0-ac4
  *
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
@@ -84,6 +84,7 @@
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->u.generic_sbp = (void *) 0;
+	sb->s_maxbytes = 0xFFFFFFFF;
 
 	/* Build the file system.  */
 	if (jffs_build_fs(sb) < 0) {
diff -u --recursive --new-file v2.4.2/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.4.2/linux/fs/minix/inode.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/minix/inode.c	Fri Mar  2 11:12:11 2001
@@ -259,6 +259,9 @@
 
 	minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
 	minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
+
+	s->s_maxbytes = MAX_NON_LFS;
+
 	/* set up enough so that it can read an inode */
 	s->s_op = &minix_sops;
 	root_inode = iget(s, MINIX_ROOT_INO);
diff -u --recursive --new-file v2.4.2/linux/fs/namei.c linux/fs/namei.c
--- v2.4.2/linux/fs/namei.c	Fri Dec 29 14:07:23 2000
+++ linux/fs/namei.c	Thu Mar 22 11:07:58 2001
@@ -1013,7 +1013,7 @@
 		error = -ELOOP;
 		if (flag & O_NOFOLLOW)
 			goto exit_dput;
-		do __follow_down(&nd->mnt,&dentry); while(d_mountpoint(dentry));
+		while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
 	}
 	error = -ENOENT;
 	if (!dentry->d_inode)
@@ -1927,13 +1927,11 @@
 	 * bloody create() on broken symlinks. Furrfu...
 	 */
 	name = __getname();
-	if (IS_ERR(name))
-		goto fail_name;
+	if (!name)
+		return -ENOMEM;
 	strcpy(name, nd->last.name);
 	nd->last.name = name;
 	return 0;
-fail_name:
-	link = name;
 fail:
 	path_release(nd);
 	return PTR_ERR(link);
diff -u --recursive --new-file v2.4.2/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.4.2/linux/fs/ncpfs/dir.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/ncpfs/dir.c	Wed Mar  7 16:53:48 2001
@@ -326,56 +326,15 @@
 	return res;
 }
 
-/* most parts from nfsd_d_validate() */
-static int
-ncp_d_validate(struct dentry *dentry)
-{
-	unsigned long dent_addr = (unsigned long) dentry;
-	unsigned long min_addr = PAGE_OFFSET;
-	unsigned long align_mask = 0x0F;
-	unsigned int len;
-	int valid = 0;
-
-	if (dent_addr < min_addr)
-		goto bad_addr;
-	if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))
-		goto bad_addr;
-	if ((dent_addr & ~align_mask) != dent_addr)
-		goto bad_align;
-	if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
-						sizeof(struct dentry))))
-		goto bad_addr;
-	/*
-	 * Looks safe enough to dereference ...
-	 */
-	len = dentry->d_name.len;
-	if (len > NCP_MAXPATHLEN)
-		goto out;
-	/*
-	 * Note: d_validate doesn't dereference the parent pointer ...
-	 * just combines it with the name hash to find the hash chain.
-	 */
-	valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
-out:
-	return valid;
-
-bad_addr:
-	PRINTK("ncp_d_validate: invalid address %lx\n", dent_addr);
-	goto out;
-bad_align:
-	PRINTK("ncp_d_validate: unaligned address %lx\n", dent_addr);
-	goto out;
-}
-
 static struct dentry *
 ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
 {
 	struct dentry *dent = dentry;
 	struct list_head *next;
 
-	if (ncp_d_validate(dent)) {
-		if (dent->d_parent == parent &&
-		   (unsigned long)dent->d_fsdata == fpos) {
+	if (d_validate(dent, parent)) {
+		if (dent->d_name.len <= NCP_MAXPATHLEN &&
+		    (unsigned long)dent->d_fsdata == fpos) {
 			if (!dent->d_inode) {
 				dput(dent);
 				dent = NULL;
@@ -580,6 +539,7 @@
 	struct ncp_cache_control ctl = *ctrl;
 	struct qstr qname;
 	int valid = 0;
+	int hashed = 0;
 	ino_t ino = 0;
 	__u8 __name[256];
 
@@ -602,9 +562,11 @@
 		newdent = d_alloc(dentry, &qname);
 		if (!newdent)
 			goto end_advance;
-	} else
+	} else {
+		hashed = 1;
 		memcpy((char *) newdent->d_name.name, qname.name,
 							newdent->d_name.len);
+	}
 
 	if (!newdent->d_inode) {
 		entry->opened = 0;
@@ -612,7 +574,9 @@
 		newino = ncp_iget(inode->i_sb, entry);
 		if (newino) {
 			newdent->d_op = &ncp_dentry_operations;
-			d_add(newdent, newino);
+			d_instantiate(newdent, newino);
+			if (!hashed)
+				d_rehash(newdent);
 		}
 	} else
 		ncp_update_inode2(newdent->d_inode, entry);
diff -u --recursive --new-file v2.4.2/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.4.2/linux/fs/ncpfs/inode.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/ncpfs/inode.c	Fri Mar  2 11:12:11 2001
@@ -327,6 +327,7 @@
 	else
 		default_bufsize = 1024;
 
+	sb->s_maxbytes = MAX_NON_LFS;
 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
 	sb->s_blocksize_bits = 10;
 	sb->s_magic = NCP_SUPER_MAGIC;
diff -u --recursive --new-file v2.4.2/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.4.2/linux/fs/ncpfs/mmap.c	Wed Feb 21 18:20:39 2001
+++ linux/fs/ncpfs/mmap.c	Fri Mar  2 15:15:12 2001
@@ -43,7 +43,7 @@
 	int bufsize;
 	int pos;
 
-	page = alloc_page(GFP_HIGHMEM); /* ncpfs has nothing against GFP_HIGHMEM
+	page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages
 	           as long as recvmsg and memset works on it */
 	if (!page)
 		return page;
diff -u --recursive --new-file v2.4.2/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.4.2/linux/fs/nfs/dir.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/nfs/dir.c	Thu Mar 15 09:56:07 2001
@@ -321,7 +321,7 @@
 		desc->page = NULL;
 	}
 
-	page = page_cache_alloc();
+	page = alloc_page(GFP_HIGHUSER);
 	if (!page) {
 		status = -ENOMEM;
 		goto out;
@@ -1097,6 +1097,10 @@
 
 	if (!NFS_PROTO(inode)->access)
 		goto out;
+
+	if (error == -EROFS)
+		goto out;
+
 	/*
 	 * Trust UNIX mode bits except:
 	 *
diff -u --recursive --new-file v2.4.2/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.4.2/linux/fs/nfs/inode.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/nfs/inode.c	Fri Mar  2 11:12:11 2001
@@ -434,6 +434,11 @@
         if (server->namelen == 0 || server->namelen > maxlen)
                 server->namelen = maxlen;
 
+	if(version == 2)
+		sb->s_maxbytes = MAX_NON_LFS;
+	else
+		sb->s_maxbytes = ~0ULL;	/* Unlimited on NFSv3 */
+
 	/* Fire up the writeback cache */
 	if (nfs_reqlist_alloc(server) < 0) {
 		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
diff -u --recursive --new-file v2.4.2/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.4.2/linux/fs/nfsd/nfsproc.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/nfsd/nfsproc.c	Mon Mar 12 18:14:55 2001
@@ -196,7 +196,7 @@
 	struct iattr	*attr = &argp->attrs;
 	struct inode	*inode;
 	struct dentry	*dchild;
-	int		nfserr, type, mode, rdonly = 0;
+	int		nfserr, type, mode;
 	dev_t		rdev = NODEV;
 
 	dprintk("nfsd: CREATE   %s %s\n",
@@ -207,13 +207,7 @@
 	if (nfserr)
 		goto done; /* must fh_put dirfhp even on error */
 
-	/* Check for MAY_WRITE separately. */
-	nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry,
-				 MAY_WRITE);
-	if (nfserr == nfserr_rofs) {
-		rdonly = 1;	/* Non-fatal error for echo > /dev/null */
-	} else if (nfserr)
-		goto done;
+	/* Check for MAY_WRITE in nfsd_create if necessary */
 
 	nfserr = nfserr_acces;
 	if (!argp->len)
@@ -257,10 +251,25 @@
 			 * else assume a file */
 			if (inode) {
 				type = inode->i_mode & S_IFMT;
-				if (type == S_IFCHR || type == S_IFBLK) {
+				switch(type) {
+				case S_IFCHR:
+				case S_IFBLK:
 					/* reserve rdev for later checking */
 					attr->ia_size = inode->i_rdev;
 					attr->ia_valid |= ATTR_SIZE;
+
+					/* FALLTHROUGH */
+				case S_IFIFO:
+					/* this is probably a permission check..
+					 * at least IRIX implements perm checking on
+					 *   echo thing > device-special-file-or-pipe
+					 * by does a CREATE with type==0
+					 */
+					nfserr = nfsd_permission(newfhp->fh_export,
+								 newfhp->fh_dentry,
+								 MAY_WRITE);
+					if (nfserr && nfserr != nfserr_rofs)
+						goto out_unlock;
 				}
 			} else
 				type = S_IFREG;
@@ -272,11 +281,6 @@
 		type = S_IFREG;
 		mode = 0;	/* ??? */
 	}
-
-	/* This is for "echo > /dev/null" a la SunOS. Argh. */
-	nfserr = nfserr_rofs;
-	if (rdonly && (!inode || type == S_IFREG))
-		goto out_unlock;
 
 	attr->ia_valid |= ATTR_MODE;
 	attr->ia_mode = mode;
diff -u --recursive --new-file v2.4.2/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- v2.4.2/linux/fs/nfsd/nfssvc.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/nfsd/nfssvc.c	Thu Mar 15 09:56:07 2001
@@ -149,12 +149,8 @@
 	/* Lock module and set up kernel thread */
 	MOD_INC_USE_COUNT;
 	lock_kernel();
-	exit_mm(current);
-	current->session = 1;
-	current->pgrp = 1;
+	daemonize();
 	sprintf(current->comm, "nfsd");
-	current->fs->umask = 0;
-
 	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 
 
 	nfsdstats.th_cnt++;
diff -u --recursive --new-file v2.4.2/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.4.2/linux/fs/nfsd/vfs.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/nfsd/vfs.c	Mon Mar 12 18:13:28 2001
@@ -737,27 +737,24 @@
 		 * nice and simple solution (IMHO), and it seems to
 		 * work:-)
 		 */
-		if (EX_WGATHER(exp) && (atomic_read(&inode->i_writecount) > 1
-		 || (last_ino == inode->i_ino && last_dev == inode->i_dev))) {
-#if 0
-			interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
-#else
-			dprintk("nfsd: write defer %d\n", current->pid);
-/* FIXME: Olaf commented this out [gam3] */
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((HZ+99)/100);
-			current->state = TASK_RUNNING;
-			dprintk("nfsd: write resume %d\n", current->pid);
-#endif
-		}
+		if (EX_WGATHER(exp)) {
+			if (atomic_read(&inode->i_writecount) > 1
+			    || (last_ino == inode->i_ino && last_dev == inode->i_dev)) {
+				dprintk("nfsd: write defer %d\n", current->pid);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				schedule_timeout((HZ+99)/100);
+				current->state = TASK_RUNNING;
+				dprintk("nfsd: write resume %d\n", current->pid);
+			}
 
-		if (inode->i_state & I_DIRTY) {
-			dprintk("nfsd: write sync %d\n", current->pid);
-			nfsd_sync(&file);
-		}
+			if (inode->i_state & I_DIRTY) {
+				dprintk("nfsd: write sync %d\n", current->pid);
+				nfsd_sync(&file);
+			}
 #if 0
-		wake_up(&inode->i_wait);
+			wake_up(&inode->i_wait);
 #endif
+		}
 		last_ino = inode->i_ino;
 		last_dev = inode->i_dev;
 	}
diff -u --recursive --new-file v2.4.2/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.4.2/linux/fs/proc/array.c	Tue Nov 14 11:22:36 2000
+++ linux/fs/proc/array.c	Mon Mar 19 12:34:55 2001
@@ -181,7 +181,7 @@
 	unsigned long data = 0, stack = 0;
 	unsigned long exec = 0, lib = 0;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
 		unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
 		if (!vma->vm_file) {
@@ -212,7 +212,7 @@
 		mm->rss << (PAGE_SHIFT-10),
 		data - stack, stack,
 		exec - lib, lib);
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	return buffer;
 }
 
@@ -321,7 +321,7 @@
 	task_unlock(task);
 	if (mm) {
 		struct vm_area_struct *vma;
-		down(&mm->mmap_sem);
+		down_read(&mm->mmap_sem);
 		vma = mm->mmap;
 		while (vma) {
 			vsize += vma->vm_end - vma->vm_start;
@@ -329,7 +329,7 @@
 		}
 		eip = KSTK_EIP(task);
 		esp = KSTK_ESP(task);
-		up(&mm->mmap_sem);
+		up_read(&mm->mmap_sem);
 	}
 
 	wchan = get_wchan(task);
@@ -484,7 +484,7 @@
 	task_unlock(task);
 	if (mm) {
 		struct vm_area_struct * vma;
-		down(&mm->mmap_sem);
+		down_read(&mm->mmap_sem);
 		vma = mm->mmap;
 		while (vma) {
 			pgd_t *pgd = pgd_offset(mm, vma->vm_start);
@@ -505,7 +505,7 @@
 				drs += pages;
 			vma = vma->vm_next;
 		}
-		up(&mm->mmap_sem);
+		up_read(&mm->mmap_sem);
 		mmput(mm);
 	}
 	return sprintf(buffer,"%d %d %d %d %d %d %d\n",
@@ -582,7 +582,7 @@
 	column = *ppos & (MAPS_LINE_LENGTH-1);
 
 	/* quickly go to line lineno */
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
 		continue;
 
@@ -644,9 +644,7 @@
 		i = len-column;
 		if (i > count)
 			i = count;
-		up(&mm->mmap_sem);
 		copy_to_user(destptr, line+column, i); /* may have slept */
-		down(&mm->mmap_sem);
 		destptr += i;
 		count   -= i;
 		column  += i;
@@ -665,7 +663,7 @@
 		if (volatile_task)
 			break;
 	}
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 
 	/* encode f_pos */
 	*ppos = (lineno << MAPS_LINE_SHIFT) + column;
diff -u --recursive --new-file v2.4.2/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.4.2/linux/fs/proc/base.c	Thu Nov 16 13:18:26 2000
+++ linux/fs/proc/base.c	Mon Mar 19 12:34:55 2001
@@ -64,7 +64,7 @@
 	task_unlock(task);
 	if (!mm)
 		goto out;
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = mm->mmap;
 	while (vma) {
 		if ((vma->vm_flags & VM_EXECUTABLE) && 
@@ -76,7 +76,7 @@
 		}
 		vma = vma->vm_next;
 	}
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	mmput(mm);
 out:
 	return result;
diff -u --recursive --new-file v2.4.2/linux/fs/proc/inode.c linux/fs/proc/inode.c
--- v2.4.2/linux/fs/proc/inode.c	Fri Nov 17 16:51:47 2000
+++ linux/fs/proc/inode.c	Fri Mar  2 11:12:12 2001
@@ -188,6 +188,8 @@
 	s->s_blocksize_bits = 10;
 	s->s_magic = PROC_SUPER_MAGIC;
 	s->s_op = &proc_sops;
+	s->s_maxbytes = MAX_NON_LFS;
+	
 	root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
 	if (!root_inode)
 		goto out_no_root;
diff -u --recursive --new-file v2.4.2/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.4.2/linux/fs/proc/proc_misc.c	Tue Nov  7 11:08:09 2000
+++ linux/fs/proc/proc_misc.c	Fri Mar 23 11:45:28 2001
@@ -293,8 +293,8 @@
 		"page %u %u\n"
                 "swap %u %u\n"
 		"intr %u",
-			kstat.pgpgin,
-			kstat.pgpgout,
+			kstat.pgpgin >> 1,
+			kstat.pgpgout >> 1,
 			kstat.pswpin,
 			kstat.pswpout,
 			sum
diff -u --recursive --new-file v2.4.2/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.4.2/linux/fs/qnx4/inode.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/qnx4/inode.c	Fri Mar  2 11:12:12 2001
@@ -369,6 +369,7 @@
 	}
 	s->s_op = &qnx4_sops;
 	s->s_magic = QNX4_SUPER_MAGIC;
+	s->s_maxbytes = MAX_NON_LFS;
 #ifndef CONFIG_QNX4FS_RW
 	s->s_flags |= MS_RDONLY;	/* Yup, read-only yet */
 #endif
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/dir.c linux/fs/reiserfs/dir.c
--- v2.4.2/linux/fs/reiserfs/dir.c	Sat Feb  3 19:51:31 2001
+++ linux/fs/reiserfs/dir.c	Fri Mar  2 10:06:47 2001
@@ -51,12 +51,16 @@
   int windex ;
   struct reiserfs_transaction_handle th ;
 
+  lock_kernel();
+
   journal_begin(&th, dentry->d_inode->i_sb, 1) ;
   windex = push_journal_writer("dir_fsync") ;
   reiserfs_prepare_for_journal(th.t_super, SB_BUFFER_WITH_SB(th.t_super), 1) ;
   journal_mark_dirty(&th, dentry->d_inode->i_sb, SB_BUFFER_WITH_SB (dentry->d_inode->i_sb)) ;
   pop_journal_writer(windex) ;
   journal_end_sync(&th, dentry->d_inode->i_sb, 1) ;
+
+  unlock_kernel();
 
   return ret ;
 }
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/fix_node.c linux/fs/reiserfs/fix_node.c
--- v2.4.2/linux/fs/reiserfs/fix_node.c	Sat Feb  3 19:51:31 2001
+++ linux/fs/reiserfs/fix_node.c	Fri Mar  2 18:38:39 2001
@@ -840,7 +840,7 @@
 
 
 /* Get new buffers for storing new nodes that are created while balancing.
- * Returns:	SCHEDULE_OCCURED - schedule occured while the function worked;
+ * Returns:	SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *	        CARRY_ON - schedule didn't occur while the function worked;
  *	        NO_DISK_SPACE - no disk space.
  */
@@ -1077,7 +1077,7 @@
  * Calculate left/right common parent of the current node and L[h]/R[h].
  * Calculate left/right delimiting key position.
  * Returns:	PATH_INCORRECT   - path in the tree is not correct;
- 		SCHEDULE_OCCURRED - schedule occured while the function worked;
+ 		SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *	        CARRY_ON         - schedule didn't occur while the function worked;
  */
 static int  get_far_parent (struct tree_balance *   p_s_tb,
@@ -1198,7 +1198,7 @@
  * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset],
  * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset].
  * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset].
- * Returns:	SCHEDULE_OCCURRED - schedule occured while the function worked;
+ * Returns:	SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *	        CARRY_ON - schedule didn't occur while the function worked;
  */
 static int  get_parents (struct tree_balance * p_s_tb, int n_h)
@@ -1340,7 +1340,7 @@
  *	h	current level of the node;
  *	inum	item number in S[h];
  *	mode	i - insert, p - paste;
- * Returns:	1 - schedule occured; 
+ * Returns:	1 - schedule occurred; 
  *	        0 - balancing for higher levels needed;
  *	       -1 - no balancing for higher levels needed;
  *	       -2 - no disk space.
@@ -1678,7 +1678,7 @@
  *	h	current level of the node;
  *	inum	item number in S[h];
  *	mode	i - insert, p - paste;
- * Returns:	1 - schedule occured; 
+ * Returns:	1 - schedule occurred; 
  *	        0 - balancing for higher levels needed;
  *	       -1 - no balancing for higher levels needed;
  *	       -2 - no disk space.
@@ -1848,7 +1848,7 @@
  *	h	current level of the node;
  *	inum	item number in S[h];
  *	mode	i - insert, p - paste;
- * Returns:	1 - schedule occured; 
+ * Returns:	1 - schedule occurred; 
  *	        0 - balancing for higher levels needed;
  *	       -1 - no balancing for higher levels needed;
  *	       -2 - no disk space.
@@ -1951,7 +1951,7 @@
  *	h	current level of the node;
  *	inum	item number in S[h];
  *	mode	d - delete, c - cut.
- * Returns:	1 - schedule occured; 
+ * Returns:	1 - schedule occurred; 
  *	        0 - balancing for higher levels needed;
  *	       -1 - no balancing for higher levels needed;
  *	       -2 - no disk space.
@@ -1985,7 +1985,7 @@
  *	h	current level of the node;
  *	inum	item number in S[h];
  *	mode	i - insert, p - paste, d - delete, c - cut.
- * Returns:	1 - schedule occured; 
+ * Returns:	1 - schedule occurred; 
  *	        0 - balancing for higher levels needed;
  *	       -1 - no balancing for higher levels needed;
  *	       -2 - no disk space.
@@ -2075,7 +2075,7 @@
 /* Using lnum[n_h] and rnum[n_h] we should determine what neighbors
  * of S[n_h] we
  * need in order to balance S[n_h], and get them if necessary.
- * Returns:	SCHEDULE_OCCURRED - schedule occured while the function worked;
+ * Returns:	SCHEDULE_OCCURRED - schedule occurred while the function worked;
  *	        CARRY_ON - schedule didn't occur while the function worked;
  */
 static int  get_neighbors(
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- v2.4.2/linux/fs/reiserfs/inode.c	Sat Feb  3 19:51:31 2001
+++ linux/fs/reiserfs/inode.c	Wed Mar 21 20:27:36 2001
@@ -476,8 +476,8 @@
     index = tail_offset >> PAGE_CACHE_SHIFT ;
     if (index != hole_page->index) {
 	tail_page = grab_cache_page(inode->i_mapping, index) ;
-	retval = PTR_ERR(tail_page) ;
-	if (IS_ERR(tail_page)) {
+	retval = -ENOMEM;
+	if (!tail_page) {
 	    goto out ;
 	}
     } else {
@@ -771,6 +771,7 @@
 	    ** flush unbh before the transaction commits
 	    */
 	    reiserfs_add_page_to_flush_list(&th, inode, unbh) ;
+	    mark_buffer_dirty(unbh) ;
 		  
 	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
@@ -1260,7 +1261,7 @@
     retval = search_item (sb, &key, path);
     if (retval == IO_ERROR) {
 	reiserfs_warning ("vs-13080: reiserfs_new_directory: "
-			  "i/o failure occured creating new directory\n");
+			  "i/o failure occurred creating new directory\n");
 	return -EIO;
     }
     if (retval == ITEM_FOUND) {
@@ -1296,7 +1297,7 @@
     retval = search_item (sb, &key, path);
     if (retval == IO_ERROR) {
 	reiserfs_warning ("vs-13080: reiserfs_new_symlinik: "
-			  "i/o failure occured creating new symlink\n");
+			  "i/o failure occurred creating new symlink\n");
 	return -EIO;
     }
     if (retval == ITEM_FOUND) {
@@ -1486,8 +1487,8 @@
         return -ENOENT ;
     }
     page = grab_cache_page(p_s_inode->i_mapping, index) ;
-    error = PTR_ERR(page) ;
-    if (IS_ERR(page)) {
+    error = -ENOMEM ;
+    if (!page) {
         goto out ;
     }
     /* start within the page of the last block in the file */
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/ioctl.c linux/fs/reiserfs/ioctl.c
--- v2.4.2/linux/fs/reiserfs/ioctl.c	Sat Feb  3 19:51:31 2001
+++ linux/fs/reiserfs/ioctl.c	Wed Mar 21 20:28:56 2001
@@ -77,8 +77,8 @@
     */
     index = inode->i_size >> PAGE_CACHE_SHIFT ;
     page = grab_cache_page(inode->i_mapping, index) ;
-    retval = PTR_ERR(page) ;
-    if (IS_ERR(page)) {
+    retval = -ENOMEM;
+    if (!page) {
         goto out ;
     }
     retval = reiserfs_prepare_write(NULL, page, write_from, blocksize) ;
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- v2.4.2/linux/fs/reiserfs/stree.c	Sat Feb  3 19:51:31 2001
+++ linux/fs/reiserfs/stree.c	Fri Mar  2 18:38:39 2001
@@ -734,7 +734,7 @@
 	    return IO_ERROR;
 	}
 
-	/* It is possible that schedule occured. We must check whether the key
+	/* It is possible that schedule occurred. We must check whether the key
 	   to search is still in the tree rooted from the current buffer. If
 	   not then repeat search from the root. */
 	if ( fs_changed (fs_gen, p_s_sb) && 
@@ -1438,7 +1438,6 @@
 
     if ( p_s_un_bh )  {
 	int off;
-        int block_off ;
         char *data ;
 
 	/* We are in direct2indirect conversion, so move tail contents
@@ -1452,7 +1451,8 @@
 	** the unformatted node, which might schedule, meaning we'd have to
 	** loop all the way back up to the start of the while loop.
 	**
-	** The unformatted node is prepared and logged after the do_balance.
+	** The unformatted node must be dirtied later on.  We can't be
+	** sure here if the entire tail has been deleted yet.
         **
         ** p_s_un_bh is from the page cache (all unformatted nodes are
         ** from the page cache) and might be a highmem page.  So, we
@@ -1463,25 +1463,13 @@
 
         data = page_address(p_s_un_bh->b_page) ;
 	off = ((le_ih_k_offset (&s_ih) - 1) & (PAGE_CACHE_SIZE - 1));
-        block_off = off & (p_s_un_bh->b_size - 1) ;
 	memcpy(data + off,
 	       B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value);
-
-	/* clear out the rest of the block past the end of the file. */
-	if (block_off + n_ret_value < p_s_un_bh->b_size) {
-	    memset(data + off + n_ret_value, 0, 
-		   p_s_un_bh->b_size - block_off - n_ret_value) ;
-	}
     }
 
     /* Perform balancing after all resources have been collected at once. */ 
     do_balance(&s_del_balance, NULL, NULL, M_DELETE);
 
-    /* see comment above for why this is after the do_balance */
-    if (p_s_un_bh) {
-        mark_buffer_dirty(p_s_un_bh) ;
-    }
-
     /* Return deleted body length */
     return n_ret_value;
 }
@@ -1521,7 +1509,7 @@
 	retval = search_item (th->t_super, &cpu_key, &path);
 	if (retval == IO_ERROR) {
 	    reiserfs_warning ("vs-: reiserfs_delete_solid_item: "
-			      "i/o failure occured trying to delete %K\n", &cpu_key);
+			      "i/o failure occurred trying to delete %K\n", &cpu_key);
 	    break;
 	}
 	if (retval != ITEM_FOUND) {
@@ -1869,7 +1857,7 @@
     retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path);
     if (retval == IO_ERROR) {
 	reiserfs_warning ("vs-5657: reiserfs_do_truncate: "
-			  "i/o failure occured trying to truncate %K\n", &s_item_key);
+			  "i/o failure occurred trying to truncate %K\n", &s_item_key);
 	return;
     }
     if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- v2.4.2/linux/fs/reiserfs/super.c	Sat Feb  3 19:51:31 2001
+++ linux/fs/reiserfs/super.c	Fri Mar  2 11:12:12 2001
@@ -1,5 +1,14 @@
 /*
  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ *
+ * Trivial changes by Alan Cox to add the LFS fixes
+ *
+ * Trivial Changes:
+ * Rights granted to Hans Reiser to redistribute under other terms providing
+ * he accepts all liability including but not limited to patent, fitness
+ * for purpose, and direct or indirect claims arising from failure to perform.
+ *
+ * NO WARRANTY
  */
 
 #ifdef __KERNEL__
@@ -483,6 +492,7 @@
     SB_BUFFER_WITH_SB (s) = bh;
     SB_DISK_SUPER_BLOCK (s) = rs;
     s->s_op = &reiserfs_sops;
+    s->s_maxbytes = 0xFFFFFFFF;	/* 4Gig */
     return 0;
 }
 
diff -u --recursive --new-file v2.4.2/linux/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- v2.4.2/linux/fs/reiserfs/tail_conversion.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/reiserfs/tail_conversion.c	Wed Feb 28 19:21:58 2001
@@ -32,6 +32,7 @@
     struct super_block * sb = inode->i_sb;
     struct buffer_head *up_to_date_bh ;
     struct item_head * p_le_ih = PATH_PITEM_HEAD (path);
+    unsigned long total_tail = 0 ;
     struct cpu_key end_key;  /* Key to search for the last byte of the
 				converted item. */
     struct item_head ind_ih; /* new indirect item to be inserted or
@@ -121,10 +122,19 @@
 	n_retval = reiserfs_delete_item (th, path, &end_key, inode, 
 	                                 up_to_date_bh) ;
 
+	total_tail += n_retval ;
 	if (tail_size == n_retval)
 	    // done: file does not have direct items anymore
 	    break;
 
+    }
+    /* if we've copied bytes from disk into the page, we need to zero
+    ** out the unused part of the block (it was not up to date before)
+    ** the page is still kmapped (by whoever called reiserfs_get_block)
+    */
+    if (up_to_date_bh) {
+        unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
+	memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ;
     }
 
     inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
diff -u --recursive --new-file v2.4.2/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.4.2/linux/fs/romfs/inode.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/romfs/inode.c	Fri Mar  2 11:12:12 2001
@@ -110,6 +110,9 @@
 	set_blocksize(dev, ROMBSIZE);
 	s->s_blocksize = ROMBSIZE;
 	s->s_blocksize_bits = ROMBSBITS;
+	s->u.generic_sbp = (void *) 0;
+	s->s_maxbytes = 0xFFFFFFFF;
+
 	bh = bread(dev, 0, ROMBSIZE);
 	if (!bh) {
 		/* XXX merge with other printk? */
diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/ChangeLog linux/fs/smbfs/ChangeLog
--- v2.4.2/linux/fs/smbfs/ChangeLog	Wed Feb 21 18:20:40 2001
+++ linux/fs/smbfs/ChangeLog	Tue Mar  6 19:14:59 2001
@@ -1,9 +1,22 @@
 ChangeLog for smbfs.
 
+2001-03-06 Urban Widmark <urban@teststation.com>
+
+	* cache.c: d_add on hashed dentries corrupts d_hash list and
+	  causes loops in d_lookup. Inherited bug. :)
+	* inode.c: tail -f fix for non-readonly opened files
+	  (related to the smb_proc_open change).
+	* inode.c: tail -f fix for fast size changes with the same mtime.
+
+2001-03-02 Michael Kockelkorn <m.kockelkorn@biodata.com>
+
+	* proc.c: fix smb_proc_open to allow open being called more than once
+	  with different modes (O_RDONLY -> O_WRONLY) without closing.
+
 2001-02-10 Urban Widmark <urban@teststation.com>
 
-	* dir.c: replace non-bigmem safe cache with cache code from ncpfs
-	  and fix some other bigmem bugs in smbfs.
+	* dir.c, cache.c: replace non-bigmem safe cache with cache code
+	  from ncpfs and fix some other bigmem bugs in smbfs.
 	* inode.c: root dentry not properly initialized
 	* proc.c, sock.c: adjust max parameters & max data to follow max_xmit
 	  lots of servers were having find_next trouble with this.
diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/cache.c linux/fs/smbfs/cache.c
--- v2.4.2/linux/fs/smbfs/cache.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/smbfs/cache.c	Fri Mar 23 11:50:52 2001
@@ -48,6 +48,7 @@
 	UnlockPage(page);
 	page_cache_release(page);
 out:
+	return;
 }
 
 /*
@@ -71,47 +72,6 @@
 	spin_unlock(&dcache_lock);
 }
 
-
-static int
-smb_d_validate(struct dentry *dentry)
-{
-	unsigned long dent_addr = (unsigned long) dentry;
-	unsigned long min_addr = PAGE_OFFSET;
-	unsigned long align_mask = 0x0F;
-	unsigned int len;
-	int valid = 0;
-
-	if (dent_addr < min_addr)
-		goto bad_addr;
-	if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))
-		goto bad_addr;
-	if ((dent_addr & ~align_mask) != dent_addr)
-		goto bad_align;
-	if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
-						       sizeof(struct dentry))))
-		goto bad_addr;
-	/*
-	 * Looks safe enough to dereference ...
-	 */
-	len = dentry->d_name.len;
-	if (len > SMB_MAXPATHLEN)
-		goto out;
-	/*
-	 * Note: d_validate doesn't dereference the parent pointer ...
-	 * just combines it with the name hash to find the hash chain.
-	 */
-	valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
-out:
-	return valid;
-
-bad_addr:
-	printk(KERN_ERR "smb_d_validate: invalid address %lx\n", dent_addr);
-	goto out;
-bad_align:
-	printk(KERN_ERR "smb_d_validate: unaligned address %lx\n", dent_addr);
-	goto out;
-}
-
 /*
  * dget, but require that fpos and parent matches what the dentry contains.
  * dentry is not known to be a valid pointer at entry.
@@ -122,8 +82,8 @@
 	struct dentry *dent = dentry;
 	struct list_head *next;
 
-	if (smb_d_validate(dent)) {
-		if (dent->d_parent == parent &&
+	if (d_validate(dent, parent)) {
+		if (dent->d_name.len <= SMB_MAXPATHLEN &&
 		    (unsigned long)dent->d_fsdata == fpos) {
 			if (!dent->d_inode) {
 				dput(dent);
@@ -167,6 +127,7 @@
 	struct inode *newino, *inode = dentry->d_inode;
 	struct smb_cache_control ctl = *ctrl;
 	int valid = 0;
+	int hashed = 0;
 	ino_t ino = 0;
 
 	qname->hash = full_name_hash(qname->name, qname->len);
@@ -181,9 +142,11 @@
 		newdent = d_alloc(dentry, qname);
 		if (!newdent)
 			goto end_advance;
-	} else
+	} else {
+		hashed = 1;
 		memcpy((char *) newdent->d_name.name, qname->name,
 		       newdent->d_name.len);
+	}
 
 	if (!newdent->d_inode) {
 		smb_renew_times(newdent);
@@ -191,7 +154,9 @@
 		newino = smb_iget(inode->i_sb, entry);
 		if (newino) {
 			smb_new_dentry(newdent);
-			d_add(newdent, newino);
+			d_instantiate(newdent, newino);
+			if (!hashed)
+				d_rehash(newdent);
 		}
 	} else
 		smb_set_inode_attr(newdent->d_inode, entry);
diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.4.2/linux/fs/smbfs/inode.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/smbfs/inode.c	Tue Mar  6 19:14:59 2001
@@ -161,17 +161,15 @@
 	struct smb_fattr fattr;
 
 	error = smb_proc_getattr(dentry, &fattr);
-	if (!error)
-	{
+	if (!error) {
 		smb_renew_times(dentry);
 		/*
 		 * Check whether the type part of the mode changed,
 		 * and don't update the attributes if it did.
 		 */
-		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT))
+		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
 			smb_set_inode_attr(inode, &fattr);
-		else
-		{
+		} else {
 			/*
 			 * Big trouble! The inode has become a new object,
 			 * so any operations attempted on it are invalid.
@@ -212,18 +210,11 @@
 	struct smb_sb_info *s = server_from_dentry(dentry);
 	struct inode *inode = dentry->d_inode;
 	time_t last_time;
+	loff_t last_sz;
 	int error = 0;
 
 	DEBUG1("smb_revalidate_inode\n");
-	/*
-	 * If this is a file opened with write permissions,
-	 * the inode will be up-to-date.
-	 */
 	lock_kernel();
-	if (S_ISREG(inode->i_mode) && smb_is_open(inode)) {
-		if (inode->u.smbfs_i.access != SMB_O_RDONLY)
-			goto out;
-	}
 
 	/*
 	 * Check whether we've recently refreshed the inode.
@@ -236,11 +227,13 @@
 
 	/*
 	 * Save the last modified time, then refresh the inode.
-	 * (Note: a size change should have a different mtime.)
+	 * (Note: a size change should have a different mtime,
+	 *  or same mtime but different size.)
 	 */
 	last_time = inode->i_mtime;
+	last_sz   = inode->i_size;
 	error = smb_refresh_inode(dentry);
-	if (error || inode->i_mtime != last_time) {
+	if (error || inode->i_mtime != last_time || inode->i_size != last_sz) {
 		VERBOSE("%s/%s changed, old=%ld, new=%ld\n",
 			DENTRY_PATH(dentry),
 			(long) last_time, (long) inode->i_mtime);
@@ -399,6 +392,7 @@
 	sb->s_magic = SMB_SUPER_MAGIC;
 	sb->s_flags = 0;
 	sb->s_op = &smb_sops;
+	sb->s_maxbytes = MAX_NON_LFS;	/* client support missing */
 
 	sb->u.smbfs_sb.mnt = NULL;
 	sb->u.smbfs_sb.sock_file = NULL;
diff -u --recursive --new-file v2.4.2/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c
--- v2.4.2/linux/fs/smbfs/proc.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/smbfs/proc.c	Tue Mar  6 19:14:59 2001
@@ -950,7 +950,10 @@
 #if 0
 	/* FIXME: why is this code not in? below we fix it so that a caller
 	   wanting RO doesn't get RW. smb_revalidate_inode does some 
-	   optimization based on access mode. tail -f needs it to be correct. */
+	   optimization based on access mode. tail -f needs it to be correct.
+
+	   We must open rw since we don't do the open if called a second time
+	   with different 'wish'. Is that not supported by smb servers? */
 	if (!(wish & (O_WRONLY | O_RDWR)))
 		mode = read_only;
 #endif
@@ -989,8 +992,6 @@
 	/* smb_vwv2 has mtime */
 	/* smb_vwv4 has size  */
 	ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
-	if (!(wish & (O_WRONLY | O_RDWR)))
-		ino->u.smbfs_i.access = SMB_O_RDONLY;
 	ino->u.smbfs_i.open = server->generation;
 
 out:
@@ -1008,23 +1009,20 @@
 	int result;
 
 	result = -ENOENT;
-	if (!inode)
-	{
+	if (!inode) {
 		printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n",
 		       DENTRY_PATH(dentry));
 		goto out;
 	}
 
-	if (!smb_is_open(inode))
-	{
+	if (!smb_is_open(inode)) {
 		struct smb_sb_info *server = SMB_SERVER(inode);
 		smb_lock_server(server);
 		result = 0;
 		if (!smb_is_open(inode))
 			result = smb_proc_open(server, dentry, wish);
 		smb_unlock_server(server);
-		if (result)
-		{
+		if (result) {
 			PARANOIA("%s/%s open failed, result=%d\n",
 				 DENTRY_PATH(dentry), result);
 			goto out;
diff -u --recursive --new-file v2.4.2/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.4.2/linux/fs/sysv/inode.c	Mon Dec  4 19:00:09 2000
+++ linux/fs/sysv/inode.c	Fri Mar  2 11:12:12 2001
@@ -365,6 +365,7 @@
 		panic("sysv fs: bad i-node size");
 	set_blocksize(dev,BLOCK_SIZE);
 	sb->sv_block_base = 0;
+	sb->s_maxbytes = MAX_NON_LFS;
 
 	/* Try to read Xenix superblock */
 	if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) {
diff -u --recursive --new-file v2.4.2/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.4.2/linux/fs/udf/super.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/udf/super.c	Fri Mar  2 11:12:12 2001
@@ -1415,7 +1415,7 @@
 		iput(inode);
 		goto error_out;
 	}
-
+	sb->s_maxbytes = ~0ULL;
 	return sb;
 
 error_out:
diff -u --recursive --new-file v2.4.2/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.4.2/linux/fs/ufs/super.c	Wed Feb 21 18:20:40 2001
+++ linux/fs/ufs/super.c	Fri Mar  2 11:12:12 2001
@@ -489,6 +489,12 @@
 	if (!uspi)
 		goto failed;
 
+	/* Set a 2Gig file limit. Some UFS variants need to override 
+	   this but as I don't know which I'll let those in the know loosen
+	   the rules */
+	   
+	sb->s_maxbytes = MAX_NON_LFS;
+
 	switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) {
 	case UFS_MOUNT_UFSTYPE_44BSD:
 		UFSD(("ufstype=44bsd\n"))
diff -u --recursive --new-file v2.4.2/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c
--- v2.4.2/linux/fs/ufs/truncate.c	Tue Sep  5 14:07:30 2000
+++ linux/fs/ufs/truncate.c	Tue Mar  6 19:44:37 2001
@@ -160,7 +160,7 @@
 			frag_to_free = tmp;
 			free_count = uspi->s_fpb;
 		}
-next2:
+next2:;
 	}
 	
 	if (free_count > 0)
@@ -261,7 +261,7 @@
 		}
 		inode->i_blocks -= uspi->s_nspb;
 		mark_inode_dirty(inode);
-next:
+next:;
 	}
 
 	if (free_count > 0) {
diff -u --recursive --new-file v2.4.2/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.4.2/linux/fs/umsdos/emd.c	Wed Nov  8 19:01:34 2000
+++ linux/fs/umsdos/emd.c	Tue Mar  6 19:44:37 2001
@@ -16,8 +16,7 @@
 #include <linux/umsdos_fs.h>
 #include <linux/dcache.h>
 #include <linux/pagemap.h>
-
-#include <asm/delay.h>
+#include <linux/delay.h>
 
 static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q)
 {
diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.4.2/linux/include/asm-alpha/io.h	Wed Feb 21 18:20:41 2001
+++ linux/include/asm-alpha/io.h	Fri Mar  2 11:12:07 2001
@@ -455,6 +455,23 @@
 #define isa_memcpy_fromio(a,b,c)	memcpy_fromio((a),__ioremap(b),(c))
 #define isa_memcpy_toio(a,b,c)		memcpy_toio(__ioremap(a),(b),(c))
 
+static inline int
+isa_check_signature(unsigned long io_addr, const unsigned char *signature,
+		int length)
+{
+	int retval = 0;
+	do {
+		if (isa_readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
+
 
 /*
  * The Alpha Jensen hardware for some rather strange reason puts
diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- v2.4.2/linux/include/asm-alpha/machvec.h	Thu Mar  2 11:35:17 2000
+++ linux/include/asm-alpha/machvec.h	Fri Mar  2 11:12:07 2001
@@ -21,7 +21,7 @@
 struct linux_hose_info;
 struct pci_dev;
 struct pci_ops;
-struct pci_controler;
+struct pci_controller;
 
 struct alpha_machine_vector
 {
@@ -40,7 +40,7 @@
 	unsigned long min_io_address;
 	unsigned long min_mem_address;
 
-	void (*mv_pci_tbi)(struct pci_controler *hose,
+	void (*mv_pci_tbi)(struct pci_controller *hose,
 			   dma_addr_t start, dma_addr_t end);
 
 	unsigned int (*mv_inb)(unsigned long);
diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h
--- v2.4.2/linux/include/asm-alpha/pci.h	Tue Jul 18 22:58:28 2000
+++ linux/include/asm-alpha/pci.h	Fri Mar  2 11:12:07 2001
@@ -16,10 +16,10 @@
 struct resource;
 struct pci_iommu_arena;
 
-/* A controler.  Used to manage multiple PCI busses.  */
+/* A controller.  Used to manage multiple PCI busses.  */
 
-struct pci_controler {
-	struct pci_controler *next;
+struct pci_controller {
+	struct pci_controller *next;
         struct pci_bus *bus;
 	struct resource *io_space;
 	struct resource *mem_space;
diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.4.2/linux/include/asm-alpha/semaphore.h	Tue Nov 14 11:12:08 2000
+++ linux/include/asm-alpha/semaphore.h	Fri Mar  2 11:12:07 2001
@@ -12,6 +12,7 @@
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <asm/compiler.h>	/* __builtin_expect */
+#include <linux/wait.h>
 
 #define DEBUG_SEMAPHORE 0
 #define DEBUG_RW_SEMAPHORE 0
diff -u --recursive --new-file v2.4.2/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.4.2/linux/include/asm-alpha/smp.h	Tue Jan  2 16:45:37 2001
+++ linux/include/asm-alpha/smp.h	Fri Mar  2 11:30:15 2001
@@ -57,6 +57,7 @@
 #define smp_processor_id()	(current->processor)
 
 extern unsigned long cpu_present_mask;
+#define cpu_online_map cpu_present_mask
 
 #endif /* CONFIG_SMP */
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/bits.h linux/include/asm-arm/arch-integrator/bits.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/bits.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/bits.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+/* DO NOT EDIT!! - this file automatically generated
+ *                 from .s file by awk -f s2h.awk
+ */
+/*  Bit field defintions
+ *  Copyright (C) ARM Limited 1998. All rights reserved.
+ */
+
+#ifndef __bits_h
+#define __bits_h                        1
+
+#define BIT0                            0x00000001
+#define BIT1                            0x00000002
+#define BIT2                            0x00000004
+#define BIT3                            0x00000008
+#define BIT4                            0x00000010
+#define BIT5                            0x00000020
+#define BIT6                            0x00000040
+#define BIT7                            0x00000080
+#define BIT8                            0x00000100
+#define BIT9                            0x00000200
+#define BIT10                           0x00000400
+#define BIT11                           0x00000800
+#define BIT12                           0x00001000
+#define BIT13                           0x00002000
+#define BIT14                           0x00004000
+#define BIT15                           0x00008000
+#define BIT16                           0x00010000
+#define BIT17                           0x00020000
+#define BIT18                           0x00040000
+#define BIT19                           0x00080000
+#define BIT20                           0x00100000
+#define BIT21                           0x00200000
+#define BIT22                           0x00400000
+#define BIT23                           0x00800000
+#define BIT24                           0x01000000
+#define BIT25                           0x02000000
+#define BIT26                           0x04000000
+#define BIT27                           0x08000000
+#define BIT28                           0x10000000
+#define BIT29                           0x20000000
+#define BIT30                           0x40000000
+#define BIT31                           0x80000000
+
+#endif
+
+/*         END */
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/dma.h linux/include/asm-arm/arch-integrator/dma.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/dma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/dma.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,28 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/dma.h
+ *
+ *  Copyright (C) 1997,1998 Russell King
+ *
+ * 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
+ */
+#ifndef __ASM_ARCH_DMA_H
+#define __ASM_ARCH_DMA_H
+
+#define MAX_DMA_ADDRESS		0xffffffff
+
+#define MAX_DMA_CHANNELS	0
+
+#endif /* _ASM_ARCH_DMA_H */
+
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/hardware.h linux/include/asm-arm/arch-integrator/hardware.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/hardware.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,57 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/hardware.h
+ *
+ *  This file contains the hardware definitions of the Integrator.
+ *
+ *  Copyright (C) 1999 ARM Limited.
+ *
+ * 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
+ */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/arch/sizes.h>
+#include <asm/arch/platform.h>
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+#define IO_BASE			0xF0000000                 // VA of IO 
+#define IO_SIZE			0x0B000000                 // How much?
+#define IO_START		INTEGRATOR_HDR_BASE        // PA of IO
+
+/*
+ * Similar to above, but for PCI addresses (memory, IO, Config and the
+ * V3 chip itself).  WARNING: this has to mirror definitions in platform.h
+ */
+#define PCI_MEMORY_VADDR        0xe8000000
+#define PCI_CONFIG_VADDR        0xec000000
+#define PCI_V3_VADDR            0xed000000
+#define PCI_IO_VADDR            0xee000000
+
+#define PCIO_BASE		PCI_IO_VADDR
+#define PCIMEM_BASE		PCI_MEMORY_VADDR
+
+/* macro to get at IO space when running virtually */
+#define IO_ADDRESS(x) (((x) >> 4) + IO_BASE) 
+
+#define pcibios_assign_all_busses()	1
+
+#define PCIBIOS_MIN_IO		0x6000
+#define PCIBIOS_MIN_MEM 	0x00100000
+
+#endif
+
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/io.h linux/include/asm-arm/arch-integrator/io.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/io.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/io.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,46 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/io.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffff
+
+#define __io(a)			(PCI_IO_VADDR + (a))
+#define __mem_pci(a)		((unsigned long)(a))
+#define __mem_isa(a)		(PCI_MEMORY_VADDR + (unsigned long)(a))
+
+/*
+ * Generic virtual read/write
+ */
+#define __arch_getw(a)		(*(volatile unsigned short *)(a))
+#define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
+
+/*
+ * Validate the pci memory address for ioremap.
+ */
+#define iomem_valid_addr(iomem,size)	\
+	((iomem) > 0 && (iomem) + (size) <= 0x20000000)
+
+/*
+ * Convert PCI memory space to a CPU physical address
+ */
+#define iomem_to_phys(iomem)	((iomem) + PHYS_PCI_MEM_BASE)
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/irq.h linux/include/asm-arm/arch-integrator/irq.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/irq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/irq.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,20 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/irq.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+#define fixup_irq(i)	(i)
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/irqs.h linux/include/asm-arm/arch-integrator/irqs.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/irqs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/irqs.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,134 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/irqs.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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
+ */
+
+/* Use the integrator definitions */
+#include <asm/arch/platform.h>
+
+/* 
+ *  IRQ interrupts definitions are the same the INT definitions
+ *  held within platform.h
+ */
+#define IRQ_SOFTINT                     INT_SOFTINT
+#define IRQ_UARTINT0                    INT_UARTINT0
+#define IRQ_UARTINT1                    INT_UARTINT1
+#define IRQ_KMIINT0                     INT_KMIINT0
+#define IRQ_KMIINT1                     INT_KMIINT1
+#define IRQ_TIMERINT0                   INT_TIMERINT0
+#define IRQ_TIMERINT1                   INT_TIMERINT1
+#define IRQ_TIMERINT2                   INT_TIMERINT2
+#define IRQ_RTCINT                      INT_RTCINT
+#define IRQ_EXPINT0                     INT_EXPINT0
+#define IRQ_EXPINT1                     INT_EXPINT1
+#define IRQ_EXPINT2                     INT_EXPINT2
+#define IRQ_EXPINT3                     INT_EXPINT3
+#define IRQ_PCIINT0                     INT_PCIINT0
+#define IRQ_PCIINT1                     INT_PCIINT1
+#define IRQ_PCIINT2                     INT_PCIINT2
+#define IRQ_PCIINT3                     INT_PCIINT3
+#define IRQ_V3INT                       INT_V3INT
+#define IRQ_CPINT0                      INT_CPINT0
+#define IRQ_CPINT1                      INT_CPINT1
+#define IRQ_LBUSTIMEOUT                 INT_LBUSTIMEOUT
+#define IRQ_APCINT                      INT_APCINT
+
+#define IRQMASK_SOFTINT                 INTMASK_SOFTINT
+#define IRQMASK_UARTINT0                INTMASK_UARTINT0
+#define IRQMASK_UARTINT1                INTMASK_UARTINT1
+#define IRQMASK_KMIINT0                 INTMASK_KMIINT0
+#define IRQMASK_KMIINT1                 INTMASK_KMIINT1
+#define IRQMASK_TIMERINT0               INTMASK_TIMERINT0
+#define IRQMASK_TIMERINT1               INTMASK_TIMERINT1
+#define IRQMASK_TIMERINT2               INTMASK_TIMERINT2
+#define IRQMASK_RTCINT                  INTMASK_RTCINT
+#define IRQMASK_EXPINT0                 INTMASK_EXPINT0
+#define IRQMASK_EXPINT1                 INTMASK_EXPINT1
+#define IRQMASK_EXPINT2                 INTMASK_EXPINT2
+#define IRQMASK_EXPINT3                 INTMASK_EXPINT3
+#define IRQMASK_PCIINT0                 INTMASK_PCIINT0
+#define IRQMASK_PCIINT1                 INTMASK_PCIINT1
+#define IRQMASK_PCIINT2                 INTMASK_PCIINT2
+#define IRQMASK_PCIINT3                 INTMASK_PCIINT3
+#define IRQMASK_V3INT                   INTMASK_V3INT
+#define IRQMASK_CPINT0                  INTMASK_CPINT0
+#define IRQMASK_CPINT1                  INTMASK_CPINT1
+#define IRQMASK_LBUSTIMEOUT             INTMASK_LBUSTIMEOUT
+#define IRQMASK_APCINT                  INTMASK_APCINT
+
+/* 
+ *  FIQ interrupts definitions are the same the INT definitions.
+ */
+#define FIQ_SOFTINT                     INT_SOFTINT
+#define FIQ_UARTINT0                    INT_UARTINT0
+#define FIQ_UARTINT1                    INT_UARTINT1
+#define FIQ_KMIINT0                     INT_KMIINT0
+#define FIQ_KMIINT1                     INT_KMIINT1
+#define FIQ_TIMERINT0                   INT_TIMERINT0
+#define FIQ_TIMERINT1                   INT_TIMERINT1
+#define FIQ_TIMERINT2                   INT_TIMERINT2
+#define FIQ_RTCINT                      INT_RTCINT
+#define FIQ_EXPINT0                     INT_EXPINT0
+#define FIQ_EXPINT1                     INT_EXPINT1
+#define FIQ_EXPINT2                     INT_EXPINT2
+#define FIQ_EXPINT3                     INT_EXPINT3
+#define FIQ_PCIINT0                     INT_PCIINT0
+#define FIQ_PCIINT1                     INT_PCIINT1
+#define FIQ_PCIINT2                     INT_PCIINT2
+#define FIQ_PCIINT3                     INT_PCIINT3
+#define FIQ_V3INT                       INT_V3INT
+#define FIQ_CPINT0                      INT_CPINT0
+#define FIQ_CPINT1                      INT_CPINT1
+#define FIQ_LBUSTIMEOUT                 INT_LBUSTIMEOUT
+#define FIQ_APCINT                      INT_APCINT
+
+#define FIQMASK_SOFTINT                 INTMASK_SOFTINT
+#define FIQMASK_UARTINT0                INTMASK_UARTINT0
+#define FIQMASK_UARTINT1                INTMASK_UARTINT1
+#define FIQMASK_KMIINT0                 INTMASK_KMIINT0
+#define FIQMASK_KMIINT1                 INTMASK_KMIINT1
+#define FIQMASK_TIMERINT0               INTMASK_TIMERINT0
+#define FIQMASK_TIMERINT1               INTMASK_TIMERINT1
+#define FIQMASK_TIMERINT2               INTMASK_TIMERINT2
+#define FIQMASK_RTCINT                  INTMASK_RTCINT
+#define FIQMASK_EXPINT0                 INTMASK_EXPINT0
+#define FIQMASK_EXPINT1                 INTMASK_EXPINT1
+#define FIQMASK_EXPINT2                 INTMASK_EXPINT2
+#define FIQMASK_EXPINT3                 INTMASK_EXPINT3
+#define FIQMASK_PCIINT0                 INTMASK_PCIINT0
+#define FIQMASK_PCIINT1                 INTMASK_PCIINT1
+#define FIQMASK_PCIINT2                 INTMASK_PCIINT2
+#define FIQMASK_PCIINT3                 INTMASK_PCIINT3
+#define FIQMASK_V3INT                   INTMASK_V3INT
+#define FIQMASK_CPINT0                  INTMASK_CPINT0
+#define FIQMASK_CPINT1                  INTMASK_CPINT1
+#define FIQMASK_LBUSTIMEOUT             INTMASK_LBUSTIMEOUT
+#define FIQMASK_APCINT                  INTMASK_APCINT
+
+/* 
+ *  Misc. interrupt definitions
+ */
+#define IRQ_KEYBDINT                    INT_KMIINT0
+#define IRQ_MOUSEINT                    INT_KMIINT1
+
+#define IRQMASK_KEYBDINT                INTMASK_KMIINT0
+#define IRQMASK_MOUSEINT                INTMASK_KMIINT1
+
+#define NR_IRQS                         (MAXIRQNUM + 1)
+
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/keyboard.h linux/include/asm-arm/arch-integrator/keyboard.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/keyboard.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/keyboard.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,45 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/keyboard.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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 License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  Keyboard driver definitions for the Integrator architecture
+ */
+#include <asm/irq.h>
+
+#define NR_SCANCODES 128
+
+extern unsigned char kmi_kbd_sysrq_xlate[NR_SCANCODES];
+
+extern int kmi_kbd_setkeycode(u_int scancode, u_int keycode);
+extern int kmi_kbd_getkeycode(u_int scancode);
+extern int kmi_kbd_translate(u_char scancode, u_char *keycode, char raw_mode);
+extern char kmi_kbd_unexpected_up(u_char keycode);
+extern void kmi_kbd_leds(u_char leds);
+extern int kmi_kbd_init(void);
+
+#define kbd_setkeycode(sc,kc)		kmi_kbd_setkeycode(sc,kc)
+#define kbd_getkeycode(sc)		kmi_kbd_getkeycode(sc)
+
+#define kbd_translate(sc, kcp, rm)	kmi_kbd_translate(sc,kcp,rm)
+#define kbd_unexpected_up(kc)		kmi_kbd_unexpected_up(kc)
+#define kbd_leds(leds)			kmi_kbd_leds(leds)
+#define kbd_init_hw()			kmi_kbd_init()
+#define kbd_sysrq_xlate			kmi_kbd_sysrq_xlate
+#define kbd_disable_irq()		disable_irq(IRQ_KMIINT0)
+#define kbd_enable_irq()		enable_irq(IRQ_KMIINT0)
+
+#define SYSRQ_KEY			0x54
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/memory.h linux/include/asm-arm/arch-integrator/memory.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/memory.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,61 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/mmu.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+#define TASK_SIZE_26	(0x04000000UL)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+#define PHYS_OFFSET	(0x00000000UL)
+
+/*
+ * On integrator, the dram is contiguous
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	(x - PAGE_OFFSET + INTEGRATOR_HDR0_SDRAM_BASE)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	(x - INTEGRATOR_HDR0_SDRAM_BASE + PAGE_OFFSET)
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/param.h linux/include/asm-arm/arch-integrator/param.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/param.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/param.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,21 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/param.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+
+#define HZ 100
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/platform.h linux/include/asm-arm/arch-integrator/platform.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/platform.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/platform.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,544 @@
+/*
+ * 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
+ */
+/* DO NOT EDIT!! - this file automatically generated
+ *                 from .s file by awk -f s2h.awk
+ */
+/**************************************************************************
+ * * Copyright İ ARM Limited 1998.  All rights reserved.
+ * ***********************************************************************/
+/* ************************************************************************
+ * 
+ *   Integrator address map
+ * 
+ * 	NOTE: This is a multi-hosted header file for use with uHAL and
+ * 	      supported debuggers.
+ * 
+ * 	$Id: platform.s,v 1.32 2000/02/18 10:51:39 asims Exp $
+ * 
+ * ***********************************************************************/
+
+#ifndef __address_h
+#define __address_h                     1
+
+/* ========================================================================
+ *  Integrator definitions
+ * ========================================================================
+ * ------------------------------------------------------------------------
+ *  Memory definitions
+ * ------------------------------------------------------------------------
+ *  Integrator memory map
+ * 
+ */
+#define INTEGRATOR_BOOT_ROM_LO          0x00000000
+#define INTEGRATOR_BOOT_ROM_HI          0x20000000
+#define INTEGRATOR_BOOT_ROM_BASE        INTEGRATOR_BOOT_ROM_HI	 /*  Normal position */
+#define INTEGRATOR_BOOT_ROM_SIZE        SZ_512K
+
+/* 
+ *  New Core Modules have different amounts of SSRAM, the amount of SSRAM
+ *  fitted can be found in HDR_STAT.
+ * 
+ *  The symbol INTEGRATOR_SSRAM_SIZE is kept, however this now refers to
+ *  the minimum amount of SSRAM fitted on any core module.
+ * 
+ *  New Core Modules also alias the SSRAM.
+ * 
+ */
+#define INTEGRATOR_SSRAM_BASE           0x00000000
+#define INTEGRATOR_SSRAM_ALIAS_BASE     0x10800000
+#define INTEGRATOR_SSRAM_SIZE           SZ_256K
+
+#define INTEGRATOR_FLASH_BASE           0x24000000
+#define INTEGRATOR_FLASH_SIZE           SZ_32M
+
+#define INTEGRATOR_MBRD_SSRAM_BASE      0x28000000
+#define INTEGRATOR_MBRD_SSRAM_SIZE      SZ_512K
+
+/* 
+ *  SDRAM is a SIMM therefore the size is not known.
+ * 
+ */
+#define INTEGRATOR_SDRAM_BASE           0x00040000
+
+#define INTEGRATOR_SDRAM_ALIAS_BASE     0x80000000
+#define INTEGRATOR_HDR0_SDRAM_BASE      0x80000000
+#define INTEGRATOR_HDR1_SDRAM_BASE      0x90000000
+#define INTEGRATOR_HDR2_SDRAM_BASE      0xA0000000
+#define INTEGRATOR_HDR3_SDRAM_BASE      0xB0000000
+
+/* 
+ *  Logic expansion modules
+ * 
+ */
+#define INTEGRATOR_LOGIC_MODULES_BASE   0xC0000000
+#define INTEGRATOR_LOGIC_MODULE0_BASE   0xC0000000
+#define INTEGRATOR_LOGIC_MODULE1_BASE   0xD0000000
+#define INTEGRATOR_LOGIC_MODULE2_BASE   0xE0000000
+#define INTEGRATOR_LOGIC_MODULE3_BASE   0xF0000000
+
+/* ------------------------------------------------------------------------
+ *  Integrator header card registers
+ * ------------------------------------------------------------------------
+ * 
+ */
+#define INTEGRATOR_HDR_ID_OFFSET        0x00
+#define INTEGRATOR_HDR_PROC_OFFSET      0x04
+#define INTEGRATOR_HDR_OSC_OFFSET       0x08
+#define INTEGRATOR_HDR_CTRL_OFFSET      0x0C
+#define INTEGRATOR_HDR_STAT_OFFSET      0x10
+#define INTEGRATOR_HDR_LOCK_OFFSET      0x14
+#define INTEGRATOR_HDR_SDRAM_OFFSET     0x20
+#define INTEGRATOR_HDR_INIT_OFFSET      0x24	 /*  CM9x6 */
+#define INTEGRATOR_HDR_IC_OFFSET        0x40
+#define INTEGRATOR_HDR_SPDBASE_OFFSET   0x100
+#define INTEGRATOR_HDR_SPDTOP_OFFSET    0x200
+
+#define INTEGRATOR_HDR_BASE             0x10000000
+#define INTEGRATOR_HDR_ID               (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_ID_OFFSET)
+#define INTEGRATOR_HDR_PROC             (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_PROC_OFFSET)
+#define INTEGRATOR_HDR_OSC              (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_OSC_OFFSET)
+#define INTEGRATOR_HDR_CTRL             (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_CTRL_OFFSET)
+#define INTEGRATOR_HDR_STAT             (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_STAT_OFFSET)
+#define INTEGRATOR_HDR_LOCK             (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_LOCK_OFFSET)
+#define INTEGRATOR_HDR_SDRAM            (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SDRAM_OFFSET)
+#define INTEGRATOR_HDR_INIT             (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_INIT_OFFSET)
+#define INTEGRATOR_HDR_IC               (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_IC_OFFSET)
+#define INTEGRATOR_HDR_SPDBASE          (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDBASE_OFFSET)
+#define INTEGRATOR_HDR_SPDTOP           (INTEGRATOR_HDR_BASE + INTEGRATOR_HDR_SPDTOP_OFFSET)
+
+#define INTEGRATOR_HDR_CTRL_LED         0x01
+#define INTEGRATOR_HDR_CTRL_MBRD_DETECH 0x02
+#define INTEGRATOR_HDR_CTRL_REMAP       0x04
+#define INTEGRATOR_HDR_CTRL_RESET       0x08
+#define INTEGRATOR_HDR_CTRL_HIGHVECTORS 0x10
+#define INTEGRATOR_HDR_CTRL_BIG_ENDIAN  0x20
+#define INTEGRATOR_HDR_CTRL_FASTBUS     0x40
+#define INTEGRATOR_HDR_CTRL_SYNC        0x80
+
+#define INTEGRATOR_HDR_OSC_CORE_10MHz   0x102
+#define INTEGRATOR_HDR_OSC_CORE_15MHz   0x107
+#define INTEGRATOR_HDR_OSC_CORE_20MHz   0x10C
+#define INTEGRATOR_HDR_OSC_CORE_25MHz   0x111
+#define INTEGRATOR_HDR_OSC_CORE_30MHz   0x116
+#define INTEGRATOR_HDR_OSC_CORE_35MHz   0x11B
+#define INTEGRATOR_HDR_OSC_CORE_40MHz   0x120
+#define INTEGRATOR_HDR_OSC_CORE_45MHz   0x125
+#define INTEGRATOR_HDR_OSC_CORE_50MHz   0x12A
+#define INTEGRATOR_HDR_OSC_CORE_55MHz   0x12F
+#define INTEGRATOR_HDR_OSC_CORE_60MHz   0x134
+#define INTEGRATOR_HDR_OSC_CORE_65MHz   0x139
+#define INTEGRATOR_HDR_OSC_CORE_70MHz   0x13E
+#define INTEGRATOR_HDR_OSC_CORE_75MHz   0x143
+#define INTEGRATOR_HDR_OSC_CORE_80MHz   0x148
+#define INTEGRATOR_HDR_OSC_CORE_85MHz   0x14D
+#define INTEGRATOR_HDR_OSC_CORE_90MHz   0x152
+#define INTEGRATOR_HDR_OSC_CORE_95MHz   0x157
+#define INTEGRATOR_HDR_OSC_CORE_100MHz  0x15C
+#define INTEGRATOR_HDR_OSC_CORE_105MHz  0x161
+#define INTEGRATOR_HDR_OSC_CORE_110MHz  0x166
+#define INTEGRATOR_HDR_OSC_CORE_115MHz  0x16B
+#define INTEGRATOR_HDR_OSC_CORE_120MHz  0x170
+#define INTEGRATOR_HDR_OSC_CORE_125MHz  0x175
+#define INTEGRATOR_HDR_OSC_CORE_130MHz  0x17A
+#define INTEGRATOR_HDR_OSC_CORE_135MHz  0x17F
+#define INTEGRATOR_HDR_OSC_CORE_140MHz  0x184
+#define INTEGRATOR_HDR_OSC_CORE_145MHz  0x189
+#define INTEGRATOR_HDR_OSC_CORE_150MHz  0x18E
+#define INTEGRATOR_HDR_OSC_CORE_155MHz  0x193
+#define INTEGRATOR_HDR_OSC_CORE_160MHz  0x198
+#define INTEGRATOR_HDR_OSC_CORE_MASK    0x7FF
+
+#define INTEGRATOR_HDR_OSC_MEM_10MHz    0x10C000
+#define INTEGRATOR_HDR_OSC_MEM_15MHz    0x116000
+#define INTEGRATOR_HDR_OSC_MEM_20MHz    0x120000
+#define INTEGRATOR_HDR_OSC_MEM_25MHz    0x12A000
+#define INTEGRATOR_HDR_OSC_MEM_30MHz    0x134000
+#define INTEGRATOR_HDR_OSC_MEM_33MHz    0x13A000
+#define INTEGRATOR_HDR_OSC_MEM_40MHz    0x148000
+#define INTEGRATOR_HDR_OSC_MEM_50MHz    0x15C000
+#define INTEGRATOR_HDR_OSC_MEM_60MHz    0x170000
+#define INTEGRATOR_HDR_OSC_MEM_66MHz    0x17C000
+#define INTEGRATOR_HDR_OSC_MEM_MASK     0x7FF000
+
+#define INTEGRATOR_HDR_OSC_BUS_MODE_CM7x0  0x0
+#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x0  0x0800000
+#define INTEGRATOR_HDR_OSC_BUS_MODE_CM9x6  0x1000000
+#define INTEGRATOR_HDR_OSC_BUS_MODE_CM10x00  0x1800000
+#define INTEGRATOR_HDR_OSC_BUS_MODE_MASK  0x1800000
+
+#define INTEGRATOR_HDR_SDRAM_SPD_OK     (1 << 5)
+
+
+/* ------------------------------------------------------------------------
+ *  Integrator system registers
+ * ------------------------------------------------------------------------
+ * 
+ */
+
+/* 
+ *  System Controller
+ * 
+ */
+#define INTEGRATOR_SC_ID_OFFSET         0x00
+#define INTEGRATOR_SC_OSC_OFFSET        0x04
+#define INTEGRATOR_SC_CTRLS_OFFSET      0x08
+#define INTEGRATOR_SC_CTRLC_OFFSET      0x0C
+#define INTEGRATOR_SC_DEC_OFFSET        0x10
+#define INTEGRATOR_SC_ARB_OFFSET        0x14
+#define INTEGRATOR_SC_PCIENABLE_OFFSET  0x18
+#define INTEGRATOR_SC_LOCK_OFFSET       0x1C
+
+#define INTEGRATOR_SC_BASE              0x11000000
+#define INTEGRATOR_SC_ID                (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ID_OFFSET)
+#define INTEGRATOR_SC_OSC               (INTEGRATOR_SC_BASE + INTEGRATOR_SC_OSC_OFFSET)
+#define INTEGRATOR_SC_CTRLS             (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET)
+#define INTEGRATOR_SC_CTRLC             (INTEGRATOR_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET)
+#define INTEGRATOR_SC_DEC               (INTEGRATOR_SC_BASE + INTEGRATOR_SC_DEC_OFFSET)
+#define INTEGRATOR_SC_ARB               (INTEGRATOR_SC_BASE + INTEGRATOR_SC_ARB_OFFSET)
+#define INTEGRATOR_SC_PCIENABLE         (INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET)
+#define INTEGRATOR_SC_LOCK              (INTEGRATOR_SC_BASE + INTEGRATOR_SC_LOCK_OFFSET)
+
+#define INTEGRATOR_SC_OSC_SYS_10MHz     0x20
+#define INTEGRATOR_SC_OSC_SYS_15MHz     0x34
+#define INTEGRATOR_SC_OSC_SYS_20MHz     0x48
+#define INTEGRATOR_SC_OSC_SYS_25MHz     0x5C
+#define INTEGRATOR_SC_OSC_SYS_33MHz     0x7C
+#define INTEGRATOR_SC_OSC_SYS_MASK      0xFF
+
+#define INTEGRATOR_SC_OSC_PCI_25MHz     0x100
+#define INTEGRATOR_SC_OSC_PCI_33MHz     0x0
+#define INTEGRATOR_SC_OSC_PCI_MASK      0x100
+
+#define INTEGRATOR_SC_CTRL_SOFTRST      (1 << 0)
+#define INTEGRATOR_SC_CTRL_nFLVPPEN     (1 << 1)
+#define INTEGRATOR_SC_CTRL_nFLWP        (1 << 2)
+#define INTEGRATOR_SC_CTRL_URTS0        (1 << 4)
+#define INTEGRATOR_SC_CTRL_UDTR0        (1 << 5)
+#define INTEGRATOR_SC_CTRL_URTS1        (1 << 6)
+#define INTEGRATOR_SC_CTRL_UDTR1        (1 << 7)
+
+/* 
+ *  External Bus Interface
+ * 
+ */
+#define INTEGRATOR_EBI_BASE             0x12000000 
+
+#define INTEGRATOR_EBI_CSR0_OFFSET      0x00
+#define INTEGRATOR_EBI_CSR1_OFFSET      0x04
+#define INTEGRATOR_EBI_CSR2_OFFSET      0x08
+#define INTEGRATOR_EBI_CSR3_OFFSET      0x0C
+#define INTEGRATOR_EBI_LOCK_OFFSET      0x20
+
+#define INTEGRATOR_EBI_CSR0             (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR0_OFFSET)
+#define INTEGRATOR_EBI_CSR1             (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)
+#define INTEGRATOR_EBI_CSR2             (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR2_OFFSET)
+#define INTEGRATOR_EBI_CSR3             (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_CSR3_OFFSET)
+#define INTEGRATOR_EBI_LOCK             (INTEGRATOR_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)
+
+#define INTEGRATOR_EBI_8_BIT            0x00
+#define INTEGRATOR_EBI_16_BIT           0x01
+#define INTEGRATOR_EBI_32_BIT           0x02
+#define INTEGRATOR_EBI_WRITE_ENABLE     0x04
+#define INTEGRATOR_EBI_SYNC             0x08
+#define INTEGRATOR_EBI_WS_2             0x00
+#define INTEGRATOR_EBI_WS_3             0x10
+#define INTEGRATOR_EBI_WS_4             0x20
+#define INTEGRATOR_EBI_WS_5             0x30
+#define INTEGRATOR_EBI_WS_6             0x40
+#define INTEGRATOR_EBI_WS_7             0x50
+#define INTEGRATOR_EBI_WS_8             0x60
+#define INTEGRATOR_EBI_WS_9             0x70
+#define INTEGRATOR_EBI_WS_10            0x80
+#define INTEGRATOR_EBI_WS_11            0x90
+#define INTEGRATOR_EBI_WS_12            0xA0
+#define INTEGRATOR_EBI_WS_13            0xB0
+#define INTEGRATOR_EBI_WS_14            0xC0
+#define INTEGRATOR_EBI_WS_15            0xD0
+#define INTEGRATOR_EBI_WS_16            0xE0
+#define INTEGRATOR_EBI_WS_17            0xF0
+
+
+#define INTEGRATOR_CT_BASE              0x13000000	 /*  Counter/Timers */
+#define INTEGRATOR_IC_BASE              0x14000000	 /*  Interrupt Controller */
+#define INTEGRATOR_RTC_BASE             0x15000000	 /*  Real Time Clock */
+#define INTEGRATOR_UART0_BASE           0x16000000	 /*  UART 0 */
+#define INTEGRATOR_UART1_BASE           0x17000000	 /*  UART 1 */
+#define INTEGRATOR_KBD_BASE             0x18000000	 /*  Keyboard */
+#define INTEGRATOR_MOUSE_BASE           0x19000000	 /*  Mouse */
+
+/* 
+ *  LED's & Switches
+ * 
+ */
+#define INTEGRATOR_DBG_ALPHA_OFFSET     0x00
+#define INTEGRATOR_DBG_LEDS_OFFSET      0x04
+#define INTEGRATOR_DBG_SWITCH_OFFSET    0x08
+
+#define INTEGRATOR_DBG_BASE             0x1A000000
+#define INTEGRATOR_DBG_ALPHA            (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_ALPHA_OFFSET)
+#define INTEGRATOR_DBG_LEDS             (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_LEDS_OFFSET)
+#define INTEGRATOR_DBG_SWITCH           (INTEGRATOR_DBG_BASE + INTEGRATOR_DBG_SWITCH_OFFSET)
+
+
+#define INTEGRATOR_GPIO_BASE            0x1B000000	 /*  GPIO */
+
+/* ------------------------------------------------------------------------
+ *  KMI keyboard/mouse definitions
+ * ------------------------------------------------------------------------
+ */
+/* PS2 Keyboard interface */
+#define KMI0_BASE                       INTEGRATOR_KBD_BASE		
+
+/* PS2 Mouse interface */
+#define KMI1_BASE                       INTEGRATOR_MOUSE_BASE
+
+/* KMI definitions are now in include/asm-arm/hardware/amba_kmi.h -- rmk */
+
+/* ------------------------------------------------------------------------
+ *  Where in the memory map does PCI live?
+ * ------------------------------------------------------------------------
+ *  This represents a fairly liberal usage of address space.  Even though
+ *  the V3 only has two windows (therefore we need to map stuff on the fly),
+ *  we maintain the same addresses, even if they're not mapped.
+ * 
+ */
+#define PHYS_PCI_MEM_BASE               0x40000000   /* 512M to xxx */
+/*  unused 256M from A0000000-AFFFFFFF might be used for I2O ???
+ */
+#define PHYS_PCI_IO_BASE                0x60000000   /* 16M to xxx */
+/*  unused (128-16)M from B1000000-B7FFFFFF
+ */
+#define PHYS_PCI_CONFIG_BASE            0x61000000   /* 16M to xxx */
+/*  unused ((128-16)M - 64K) from XXX
+ */
+#define PHYS_PCI_V3_BASE                0x62000000
+
+#define PCI_DRAMSIZE                    INTEGRATOR_SSRAM_SIZE	
+
+/* 'export' these to UHAL */
+#define UHAL_PCI_IO                     PCI_IO_BASE
+#define UHAL_PCI_MEM                    PCI_MEM_BASE
+#define UHAL_PCI_ALLOC_IO_BASE          0x00004000
+#define UHAL_PCI_ALLOC_MEM_BASE         PCI_MEM_BASE
+#define UHAL_PCI_MAX_SLOT               20
+	
+/* ========================================================================
+ *  Start of uHAL definitions
+ * ========================================================================
+ */
+
+/* ------------------------------------------------------------------------
+ *  Integrator Interrupt Controllers
+ * ------------------------------------------------------------------------
+ * 
+ *  Offsets from interrupt controller base 
+ * 
+ *  System Controller interrupt controller base is
+ * 
+ * 	INTEGRATOR_IC_BASE + (header_number << 6)
+ * 
+ *  Core Module interrupt controller base is
+ * 
+ * 	INTEGRATOR_HDR_IC 
+ * 
+ */
+#define IRQ_STATUS                      0
+#define IRQ_RAW_STATUS                  0x04
+#define IRQ_ENABLE                      0x08
+#define IRQ_ENABLE_SET                  0x08
+#define IRQ_ENABLE_CLEAR                0x0C
+
+#define INT_SOFT_SET                    0x10
+#define INT_SOFT_CLEAR                  0x14
+
+#define FIQ_STATUS                      0x20
+#define FIQ_RAW_STATUS                  0x24
+#define FIQ_ENABLE                      0x28
+#define FIQ_ENABLE_SET                  0x28
+#define FIQ_ENABLE_CLEAR                0x2C
+
+
+/* ------------------------------------------------------------------------
+ *  Interrupts
+ * ------------------------------------------------------------------------
+ * 
+ *  
+ *  Each Core Module has two interrupts controllers, one on the core module
+ *  itself and one in the system controller on the motherboard.  The
+ *  READ_INT macro in target.s reads both interrupt controllers and returns
+ *  a 32 bit bitmask, bits 0 to 23 are interrupts from the system controller
+ *  and bits 24 to 31 are from the core module.
+ *  
+ *  The following definitions relate to the bitmask returned by READ_INT.
+ * 
+ */
+
+/* 
+ *  As the interrupt bit definitions for FIQ/IRQ there is a common
+ *  set of definitions prefixed INT/INTMASK.  The FIQ/IRQ definitions
+ *  have been left to maintain backwards compatible.
+ * 
+ */
+
+/* 
+ *  Interrupt numbers
+ * 
+ */
+#define INT_SOFTINT                     0
+#define INT_UARTINT0                    1
+#define INT_UARTINT1                    2
+#define INT_KMIINT0                     3
+#define INT_KMIINT1                     4
+#define INT_TIMERINT0                   5
+#define INT_TIMERINT1                   6
+#define INT_TIMERINT2                   7
+#define INT_RTCINT                      8
+#define INT_EXPINT0                     9
+#define INT_EXPINT1                     10
+#define INT_EXPINT2                     11
+#define INT_EXPINT3                     12
+#define INT_PCIINT0                     13
+#define INT_PCIINT1                     14
+#define INT_PCIINT2                     15
+#define INT_PCIINT3                     16
+#define INT_V3INT                       17
+#define INT_CPINT0                      18
+#define INT_CPINT1                      19
+#define INT_LBUSTIMEOUT                 20
+#define INT_APCINT                      21
+#define INT_CM_SOFTINT                  24
+#define INT_CM_COMMRX                   25
+#define INT_CM_COMMTX                   26
+
+/* 
+ *  Interrupt bit positions
+ * 
+ */
+#define INTMASK_SOFTINT                 (1 << INT_SOFTINT)
+#define INTMASK_UARTINT0                (1 << INT_UARTINT0)
+#define INTMASK_UARTINT1                (1 << INT_UARTINT1)
+#define INTMASK_KMIINT0                 (1 << INT_KMIINT0)
+#define INTMASK_KMIINT1                 (1 << INT_KMIINT1)
+#define INTMASK_TIMERINT0               (1 << INT_TIMERINT0)
+#define INTMASK_TIMERINT1               (1 << INT_TIMERINT1)
+#define INTMASK_TIMERINT2               (1 << INT_TIMERINT2)
+#define INTMASK_RTCINT                  (1 << INT_RTCINT)
+#define INTMASK_EXPINT0                 (1 << INT_EXPINT0)
+#define INTMASK_EXPINT1                 (1 << INT_EXPINT1)
+#define INTMASK_EXPINT2                 (1 << INT_EXPINT2)
+#define INTMASK_EXPINT3                 (1 << INT_EXPINT3)
+#define INTMASK_PCIINT0                 (1 << INT_PCIINT0)
+#define INTMASK_PCIINT1                 (1 << INT_PCIINT1)
+#define INTMASK_PCIINT2                 (1 << INT_PCIINT2)
+#define INTMASK_PCIINT3                 (1 << INT_PCIINT3)
+#define INTMASK_V3INT                   (1 << INT_V3INT)
+#define INTMASK_CPINT0                  (1 << INT_CPINT0)
+#define INTMASK_CPINT1                  (1 << INT_CPINT1)
+#define INTMASK_LBUSTIMEOUT             (1 << INT_LBUSTIMEOUT)
+#define INTMASK_APCINT                  (1 << INT_APCINT)
+#define INTMASK_CM_SOFTINT              (1 << INT_CM_SOFTINT)
+#define INTMASK_CM_COMMRX               (1 << INT_CM_COMMRX)
+#define INTMASK_CM_COMMTX               (1 << INT_CM_COMMTX)
+
+/* 
+ *  INTEGRATOR_CM_INT0      - Interrupt number of first CM interrupt
+ *  INTEGRATOR_SC_VALID_INT - Mask of valid system controller interrupts
+ * 
+ */
+#define INTEGRATOR_CM_INT0              INT_CM_SOFTINT
+#define INTEGRATOR_SC_VALID_INT         0x003FFFFF
+
+#define MAXIRQNUM                       31
+#define MAXFIQNUM                       31
+#define MAXSWINUM                       31
+ 
+/* ------------------------------------------------------------------------
+ *  LED's - The header LED is not accessable via the uHAL API
+ * ------------------------------------------------------------------------
+ * 
+ */
+#define GREEN_LED                       0x01
+#define YELLOW_LED                      0x02
+#define RED_LED                         0x04
+#define GREEN_LED_2                     0x08
+#define ALL_LEDS                        0x0F
+
+#define LED_BANK                        INTEGRATOR_DBG_LEDS
+
+/* 
+ *  Memory definitions - run uHAL out of SSRAM.
+ * 
+ */
+#define uHAL_MEMORY_SIZE                INTEGRATOR_SSRAM_SIZE
+
+/* 
+ *  Application Flash
+ * 
+ */
+#define FLASH_BASE                      INTEGRATOR_FLASH_BASE
+#define FLASH_SIZE                      INTEGRATOR_FLASH_SIZE
+#define FLASH_END                       (FLASH_BASE + FLASH_SIZE - 1)
+#define FLASH_BLOCK_SIZE                SZ_128K
+
+/* 
+ *  Boot Flash
+ * 
+ */
+#define EPROM_BASE                      INTEGRATOR_BOOT_ROM_HI
+#define EPROM_SIZE                      INTEGRATOR_BOOT_ROM_SIZE
+#define EPROM_END                       (EPROM_BASE + EPROM_SIZE - 1)
+
+/* 
+ *  Clean base - dummy
+ * 
+ */
+#define CLEAN_BASE                      EPROM_BASE
+
+/* 
+ *  Timer definitions
+ * 
+ *  Only use timer 1 & 2
+ *  (both run at 24MHz and will need the clock divider set to 16).
+ * 
+ *  Timer 0 runs at bus frequency and therefore could vary and currently
+ *  uHAL can't handle that.
+ * 
+ */
+
+#define INTEGRATOR_TIMER0_BASE          INTEGRATOR_CT_BASE
+#define INTEGRATOR_TIMER1_BASE          (INTEGRATOR_CT_BASE + 0x100)
+#define INTEGRATOR_TIMER2_BASE          (INTEGRATOR_CT_BASE + 0x200)
+
+#define MAX_TIMER                       2
+#define MAX_PERIOD                      699050
+#define TICKS_PER_uSEC                  24
+
+/* 
+ *  These are useconds NOT ticks.  
+ * 
+ */
+#define mSEC_1                          1000
+#define mSEC_5                          (mSEC_1 * 5)
+#define mSEC_10                         (mSEC_1 * 10)
+#define mSEC_25                         (mSEC_1 * 25)
+#define SEC_1                           (mSEC_1 * 1000)
+
+#define INTEGRATOR_CSR_BASE             0x10000000
+#define INTEGRATOR_CSR_SIZE             0x10000000
+
+#endif
+
+/* 	END */
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/serial.h linux/include/asm-arm/arch-integrator/serial.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/serial.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/serial.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,49 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/serial.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+#include <asm/arch/platform.h>
+#include <asm/irq.h>
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
+#define BASE_BAUD (1843200 / 16)
+
+#define _SER_IRQ0	IRQ_UARTINT0
+#define _SER_IRQ1	IRQ_UARTINT1
+
+#define RS_TABLE_SIZE	2
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+     /* UART CLK        PORT  IRQ     FLAGS        */
+#define STD_SERIAL_PORT_DEFNS \
+	{ 0, BASE_BAUD, 0x3F8, _SER_IRQ0, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, _SER_IRQ1, STD_COM_FLAGS },	/* ttyS1 */
+
+#define EXTRA_SERIAL_PORT_DEFNS
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/sizes.h linux/include/asm-arm/arch-integrator/sizes.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/sizes.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/sizes.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,52 @@
+/*
+ * 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
+ */
+/* DO NOT EDIT!! - this file automatically generated
+ *                 from .s file by awk -f s2h.awk
+ */
+/*  Size defintions
+ *  Copyright (C) ARM Limited 1998. All rights reserved.
+ */
+
+#ifndef __sizes_h
+#define __sizes_h                       1
+
+/* handy sizes */
+#define SZ_1K                           0x00000400
+#define SZ_4K                           0x00001000
+#define SZ_8K                           0x00002000
+#define SZ_16K                          0x00004000
+#define SZ_64K                          0x00010000
+#define SZ_128K                         0x00020000
+#define SZ_256K                         0x00040000
+#define SZ_512K                         0x00080000
+
+#define SZ_1M                           0x00100000
+#define SZ_2M                           0x00200000
+#define SZ_4M                           0x00400000
+#define SZ_8M                           0x00800000
+#define SZ_16M                          0x01000000
+#define SZ_32M                          0x02000000
+#define SZ_64M                          0x04000000
+#define SZ_128M                         0x08000000
+#define SZ_256M                         0x10000000
+#define SZ_512M                         0x20000000
+
+#define SZ_1G                           0x40000000
+#define SZ_2G                           0x80000000
+
+#endif
+
+/*         END */
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/system.h linux/include/asm-arm/arch-integrator/system.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/system.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/system.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,49 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/system.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * 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
+ */
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <asm/arch/platform.h>
+
+static void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+	cpu_do_idle(0);
+}
+
+extern __inline__ void arch_reset(char mode)
+{
+	unsigned int hdr_ctrl =	(IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET);
+	unsigned int val;
+
+	/*
+	 * To reset, we hit the on-board reset register
+	 * in the system FPGA
+	 */
+	val = __raw_readl(hdr_ctrl);
+	val |= INTEGRATOR_HDR_CTRL_RESET;
+	__raw_writel(val, hdr_ctrl);
+}
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/time.h linux/include/asm-arm/arch-integrator/time.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/time.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/time.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,140 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/time.h
+ *
+ * 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
+ */
+#include <asm/system.h>
+#include <asm/leds.h>
+
+/*
+ * Where is the timer (VA)?
+ */
+#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
+#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
+#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
+#define VA_IC_BASE     IO_ADDRESS(INTEGRATOR_IC_BASE) 
+
+/*
+ * How long is the timer interval?
+ */
+#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
+#if TIMER_INTERVAL >= 0x100000
+#define TIMER_RELOAD	(TIMER_INTERVAL >> 8)		/* Divide by 256 */
+#define TIMER_CTRL	0x88				/* Enable, Clock / 256 */
+#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
+#elif TIMER_INTERVAL >= 0x10000
+#define TIMER_RELOAD	(TIMER_INTERVAL >> 4)		/* Divide by 16 */
+#define TIMER_CTRL	0x84				/* Enable, Clock / 16 */
+#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
+#else
+#define TIMER_RELOAD	(TIMER_INTERVAL)
+#define TIMER_CTRL	0x80				/* Enable */
+#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
+#endif
+
+/*
+ * What does it look like?
+ */
+typedef struct TimerStruct {
+	unsigned long TimerLoad;
+	unsigned long TimerValue;
+	unsigned long TimerControl;
+	unsigned long TimerClear;
+} TimerStruct_t;
+
+extern unsigned long (*gettimeoffset)(void);
+
+/*
+ * Returns number of ms since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long integrator_gettimeoffset(void)
+{
+	volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
+	unsigned long ticks1, ticks2, status;
+
+	/*
+	 * Get the current number of ticks.  Note that there is a race
+	 * condition between us reading the timer and checking for
+	 * an interrupt.  We get around this by ensuring that the
+	 * counter has not reloaded between our two reads.
+	 */
+	ticks2 = timer1->TimerValue & 0xffff;
+	do {
+		ticks1 = ticks2;
+		status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
+		ticks2 = timer1->TimerValue & 0xffff;
+	} while (ticks2 > ticks1);
+
+	/*
+	 * Number of ticks since last interrupt.
+	 */
+	ticks1 = TIMER_RELOAD - ticks2;
+
+	/*
+	 * Interrupt pending?  If so, we've reloaded once already.
+	 */
+	if (status & IRQMASK_TIMERINT1)
+		ticks1 += TIMER_RELOAD;
+
+	/*
+	 * Convert the ticks to usecs
+	 */
+	return TICKS2USECS(ticks1);
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static void integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
+
+	// ...clear the interrupt
+	timer1->TimerClear = 1;
+
+	do_leds();
+	do_timer(regs);
+	do_profile(regs);
+}
+
+/*
+ * Set up timer interrupt, and return the current time in seconds.
+ */
+extern __inline__ void setup_timer(void)
+{
+	volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
+	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
+	volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
+
+	timer_irq.handler = integrator_timer_interrupt;
+
+	/*
+	 * Initialise to a known state (all timers off)
+	 */
+	timer0->TimerControl = 0;
+	timer1->TimerControl = 0;
+	timer2->TimerControl = 0;
+
+	timer1->TimerLoad    = TIMER_RELOAD;
+	timer1->TimerValue   = TIMER_RELOAD;
+	timer1->TimerControl = TIMER_CTRL | 0x40;	/* periodic */
+
+	/* 
+	 * Make irqs happen for the system timer
+	 */
+	setup_arm_irq(IRQ_TIMERINT1, &timer_irq);
+	gettimeoffset = integrator_gettimeoffset;
+}
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/timex.h linux/include/asm-arm/arch-integrator/timex.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/timex.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/timex.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,26 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/timex.h
+ *
+ *  Integrator architecture timex specifications
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+
+/*
+ * ??
+ */
+#define CLOCK_TICK_RATE		(50000000 / 16)
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/uncompress.h linux/include/asm-arm/arch-integrator/uncompress.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/uncompress.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/uncompress.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,53 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/uncompress.h
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * 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
+ */
+
+#define AMBA_UART_DR	(*(volatile unsigned char *)0x16000000)
+#define AMBA_UART_LCRH	(*(volatile unsigned char *)0x16000008)
+#define AMBA_UART_LCRM	(*(volatile unsigned char *)0x1600000c)
+#define AMBA_UART_LCRL	(*(volatile unsigned char *)0x16000010)
+#define AMBA_UART_CR	(*(volatile unsigned char *)0x16000014)
+#define AMBA_UART_FR	(*(volatile unsigned char *)0x16000018)
+
+/*
+ * This does not append a newline
+ */
+static void puts(const char *s)
+{
+	while (*s) {
+		while (AMBA_UART_FR & (1 << 5));
+
+		AMBA_UART_DR = *s;
+
+		if (*s == '\n') {
+			while (AMBA_UART_FR & (1 << 5));
+
+			AMBA_UART_DR = '\r';
+		}
+		s++;
+	}
+	while (AMBA_UART_FR & (1 << 3));
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-integrator/vmalloc.h linux/include/asm-arm/arch-integrator/vmalloc.h
--- v2.4.2/linux/include/asm-arm/arch-integrator/vmalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-integrator/vmalloc.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,32 @@
+/*
+ *  linux/include/asm-arm/arch-integrator/vmalloc.h
+ *
+ *  Copyright (C) 2000 Russell King.
+ *
+ * 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
+ */
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 8MB value just means that there will be a 8MB "hole" after the
+ * physical memory until the kernel virtual memory starts.  That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ */
+#define VMALLOC_OFFSET	  (8*1024*1024)
+#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/arch-sa1100/irq.h linux/include/asm-arm/arch-sa1100/irq.h
--- v2.4.2/linux/include/asm-arm/arch-sa1100/irq.h	Wed Feb 21 18:20:41 2001
+++ linux/include/asm-arm/arch-sa1100/irq.h	Fri Mar  2 11:12:06 2001
@@ -134,7 +134,7 @@
 	int mask = (1 << GPIO_11_27_IRQ(irq));
 	if (GPIO_11_27_spurious & mask) {
 		/* 
-		 * We don't want to miss an interrupt that would have occured
+		 * We don't want to miss an interrupt that would have occurred
 		 * while it was masked.  Simulate it if it is the case.
 		 */
 		int state = GPLR;
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/hardware/amba_kmi.h linux/include/asm-arm/hardware/amba_kmi.h
--- v2.4.2/linux/include/asm-arm/hardware/amba_kmi.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/hardware/amba_kmi.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,92 @@
+/*
+ *  linux/include/asm-arm/hardware/amba_kmi.h
+ *
+ *  Internal header file for AMBA KMI ports
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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
+ *
+ *
+ * ---------------------------------------------------------------------------
+ *  From ARM PrimeCell(tm) PS2 Keyboard/Mouse Interface (PL050) Technical
+ *  Reference Manual - ARM DDI 0143B - see http://www.arm.com/
+ * ---------------------------------------------------------------------------
+ */
+#ifndef ASM_ARM_HARDWARE_AMBA_KMI_H
+#define ASM_ARM_HARDWARE_AMBA_KMI_H
+
+/*
+ * KMI control register:
+ *  KMICR_TYPE       0 = PS2/AT mode, 1 = No line control bit mode
+ *  KMICR_RXINTREN   1 = enable RX interrupts
+ *  KMICR_TXINTREN   1 = enable TX interrupts
+ *  KMICR_EN         1 = enable KMI
+ *  KMICR_FD         1 = force KMI data low
+ *  KMICR_FC         1 = force KMI clock low
+ */
+#define KMICR		(KMI_BASE + 0x00)
+#define KMICR_TYPE		(1 << 5)
+#define KMICR_RXINTREN		(1 << 4)
+#define KMICR_TXINTREN		(1 << 3)
+#define KMICR_EN		(1 << 2)
+#define KMICR_FD		(1 << 1)
+#define KMICR_FC		(1 << 0)
+
+/*
+ * KMI status register:
+ *  KMISTAT_TXEMPTY  1 = transmitter register empty
+ *  KMISTAT_TXBUSY   1 = currently sending data
+ *  KMISTAT_RXFULL   1 = receiver register ready to be read
+ *  KMISTAT_RXBUSY   1 = currently receiving data
+ *  KMISTAT_RXPARITY parity of last databyte received
+ *  KMISTAT_IC       current level of KMI clock input
+ *  KMISTAT_ID       current level of KMI data input
+ */
+#define KMISTAT		(KMI_BASE + 0x04)
+#define KMISTAT_TXEMPTY		(1 << 6)
+#define KMISTAT_TXBUSY		(1 << 5)
+#define KMISTAT_RXFULL		(1 << 4)
+#define KMISTAT_RXBUSY		(1 << 3)
+#define KMISTAT_RXPARITY	(1 << 2)
+#define KMISTAT_IC		(1 << 1)
+#define KMISTAT_ID		(1 << 0)
+
+/*
+ * KMI data register
+ */
+#define KMIDATA		(KMI_BASE + 0x08)
+
+/*
+ * KMI clock divisor: to generate 8MHz internal clock
+ *  div = (ref / 8MHz) - 1; 0 <= div <= 15
+ */
+#define KMICLKDIV	(KMI_BASE + 0x0c)
+
+/*
+ * KMI interrupt register:
+ *  KMIIR_TXINTR     1 = transmit interrupt asserted
+ *  KMIIR_RXINTR     1 = receive interrupt asserted
+ */
+#define KMIIR		(KMI_BASE + 0x10)
+#define KMIIR_TXINTR		(1 << 1)
+#define KMIIR_RXINTR		(1 << 0)
+
+/*
+ * The size of the KMI primecell
+ */
+#define KMI_SIZE	(0x100)
+
+#endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/hardware/pci_v3.h linux/include/asm-arm/hardware/pci_v3.h
--- v2.4.2/linux/include/asm-arm/hardware/pci_v3.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/hardware/pci_v3.h	Fri Mar  2 18:38:39 2001
@@ -88,41 +88,41 @@
 
 /*  PCI COMMAND REGISTER bits
  */
-#define V3_COMMAND_M_FBB_EN             BIT9
-#define V3_COMMAND_M_SERR_EN            BIT8
-#define V3_COMMAND_M_PAR_EN             BIT6
-#define V3_COMMAND_M_MASTER_EN          BIT2
-#define V3_COMMAND_M_MEM_EN             BIT1
-#define V3_COMMAND_M_IO_EN              BIT0
+#define V3_COMMAND_M_FBB_EN             (1 << 9)
+#define V3_COMMAND_M_SERR_EN            (1 << 8)
+#define V3_COMMAND_M_PAR_EN             (1 << 6)
+#define V3_COMMAND_M_MASTER_EN          (1 << 2)
+#define V3_COMMAND_M_MEM_EN             (1 << 1)
+#define V3_COMMAND_M_IO_EN              (1 << 0)
 
 /*  SYSTEM REGISTER bits
  */
-#define V3_SYSTEM_M_RST_OUT             BIT15
-#define V3_SYSTEM_M_LOCK                BIT14 
+#define V3_SYSTEM_M_RST_OUT             (1 << 15)
+#define V3_SYSTEM_M_LOCK                (1 << 14)
 
 /*  PCI_CFG bits
  */
-#define V3_PCI_CFG_M_RETRY_EN           BIT10
-#define V3_PCI_CFG_M_AD_LOW1            BIT9
-#define V3_PCI_CFG_M_AD_LOW0            BIT8
+#define V3_PCI_CFG_M_RETRY_EN           (1 << 10)
+#define V3_PCI_CFG_M_AD_LOW1            (1 << 9)
+#define V3_PCI_CFG_M_AD_LOW0            (1 << 8)
 
 /*  PCI_BASE register bits (PCI -> Local Bus)
  */
 #define V3_PCI_BASE_M_ADR_BASE          0xFFF00000
 #define V3_PCI_BASE_M_ADR_BASEL         0x000FFF00
-#define V3_PCI_BASE_M_PREFETCH          BIT3
-#define V3_PCI_BASE_M_TYPE              BIT2+BIT1
-#define V3_PCI_BASE_M_IO                BIT0
+#define V3_PCI_BASE_M_PREFETCH          (1 << 3)
+#define V3_PCI_BASE_M_TYPE              (3 << 1)
+#define V3_PCI_BASE_M_IO                (1 << 0)
 
 /*  PCI MAP register bits (PCI -> Local bus)
  */
 #define V3_PCI_MAP_M_MAP_ADR            0xFFF00000
-#define V3_PCI_MAP_M_RD_POST_INH        BIT15
-#define V3_PCI_MAP_M_ROM_SIZE           BIT11+BIT10
-#define V3_PCI_MAP_M_SWAP               BIT9+BIT8
+#define V3_PCI_MAP_M_RD_POST_INH        (1 << 15)
+#define V3_PCI_MAP_M_ROM_SIZE           (3 << 10)
+#define V3_PCI_MAP_M_SWAP               (3 << 8)
 #define V3_PCI_MAP_M_ADR_SIZE           0x000000F0
-#define V3_PCI_MAP_M_REG_EN             BIT1	
-#define V3_PCI_MAP_M_ENABLE             BIT0
+#define V3_PCI_MAP_M_REG_EN             (1 << 1)
+#define V3_PCI_MAP_M_ENABLE             (1 << 0)
 
 /*  9 => 512M window size
  */
@@ -134,15 +134,15 @@
 /*  LB_BASE register bits (Local bus -> PCI)
  */
 #define V3_LB_BASE_M_MAP_ADR            0xFFF00000
-#define V3_LB_BASE_M_SWAP               BIT9+BIT8
+#define V3_LB_BASE_M_SWAP               (3 << 8)
 #define V3_LB_BASE_M_ADR_SIZE           0x000000F0
-#define V3_LB_BASE_M_PREFETCH           BIT3
-#define V3_LB_BASE_M_ENABLE             BIT0
+#define V3_LB_BASE_M_PREFETCH           (1 << 3)
+#define V3_LB_BASE_M_ENABLE             (1 << 0)
 
 /*  LB_MAP register bits (Local bus -> PCI)
  */
 #define V3_LB_MAP_M_MAP_ADR             0xFFF0
 #define V3_LB_MAP_M_TYPE                0x000E
-#define V3_LB_MAP_M_AD_LOW_EN           BIT0
+#define V3_LB_MAP_M_AD_LOW_EN           (1 << 0)
 
 #endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/hardware/serial_amba.h linux/include/asm-arm/hardware/serial_amba.h
--- v2.4.2/linux/include/asm-arm/hardware/serial_amba.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/hardware/serial_amba.h	Fri Mar  2 18:38:39 2001
@@ -88,4 +88,7 @@
 #define ARM_BAUD_2400                   383
 #define ARM_BAUD_1200                   767
 
+#define AMBA_UARTRSR_ANY	(AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE)
+#define AMBA_UARTFR_MODEM_ANY	(AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS)
+
 #endif
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/mach/amba_kmi.h linux/include/asm-arm/mach/amba_kmi.h
--- v2.4.2/linux/include/asm-arm/mach/amba_kmi.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/mach/amba_kmi.h	Fri Mar  2 18:38:39 2001
@@ -0,0 +1,39 @@
+/*
+ *  linux/include/asm-arm/mach/amba_kmi.h
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * 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
+ */
+struct kmi_info {
+	u_int			base;
+	u_int			irq;
+	u_char			divisor;
+	u_char			type;
+	u_char			state;
+	u_char			prev_rx;
+	u_char			last_tx;
+	u_char			resend_count;
+	u_short			res;
+	wait_queue_head_t	wait_q;
+	void			(*rx)(struct kmi_info *, u_int val,
+				      struct pt_regs *regs);
+	char			name[8];
+};
+
+#define KMI_KEYBOARD		0
+#define KMI_MOUSE		1
+
+int register_kmi(struct kmi_info *kmi);
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/param.h linux/include/asm-arm/param.h
--- v2.4.2/linux/include/asm-arm/param.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/param.h	Tue Mar  6 19:44:35 2001
@@ -28,5 +28,9 @@
 /* max length of hostname */
 #define MAXHOSTNAMELEN  64
 
+#ifdef __KERNEL__
+# define CLOCKS_PER_SEC	HZ
+#endif
+
 #endif
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h
--- v2.4.2/linux/include/asm-arm/pgtable.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-arm/pgtable.h	Tue Mar  6 19:44:35 2001
@@ -180,8 +180,6 @@
 /* FIXME: this is not correct */
 #define kern_addr_valid(addr)	(1)
 
-#define io_remap_page_range	remap_page_range
-
 #include <asm-generic/pgtable.h>
 
 #endif /* !__ASSEMBLY__ */
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h
--- v2.4.2/linux/include/asm-arm/proc-armv/uaccess.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/proc-armv/uaccess.h	Tue Mar  6 19:44:35 2001
@@ -24,7 +24,7 @@
 /* We use 33-bit arithmetic here... */
 #define __range_ok(addr,size) ({ \
 	unsigned long flag, sum; \
-	__asm__ __volatile__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \
+	__asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \
 		: "=&r" (flag), "=&r" (sum) \
 		: "r" (addr), "Ir" (size), "0" (current->addr_limit) \
 		: "cc"); \
@@ -32,7 +32,7 @@
 
 #define __addr_ok(addr) ({ \
 	unsigned long flag; \
-	__asm__ __volatile__("cmp %2, %0; movlo %0, #0" \
+	__asm__("cmp %2, %0; movlo %0, #0" \
 		: "=&r" (flag) \
 		: "0" (current->addr_limit), "r" (addr) \
 		: "cc"); \
@@ -57,24 +57,8 @@
 #define __put_user_asm_half(x,addr,err)				\
 ({								\
 	unsigned long __temp = (unsigned long)(x);		\
-	__asm__ __volatile__(					\
-	"1:	strbt	%1,[%3],#0\n"				\
-	"2:	strbt	%2,[%4],#0\n"				\
-	"3:\n"							\
-	"	.section .fixup,\"ax\"\n"			\
-	"	.align	2\n"					\
-	"4:	mov	%0, %5\n"				\
-	"	b	3b\n"					\
-	"	.previous\n"					\
-	"	.section __ex_table,\"a\"\n"			\
-	"	.align	3\n"					\
-	"	.long	1b, 4b\n"				\
-	"	.long	2b, 4b\n"				\
-	"	.previous"					\
-	: "=r" (err)						\
-	: "r" (__temp), "r" (__temp >> 8),			\
-	  "r" (addr), "r" ((int)(addr) + 1),			\
-	   "i" (-EFAULT), "0" (err));				\
+	__put_user_asm_byte(__temp, addr, err);			\
+	__put_user_asm_byte(__temp >> 8, (int)(addr) + 1, err);	\
 })
 
 #define __put_user_asm_word(x,addr,err)				\
@@ -112,26 +96,10 @@
 
 #define __get_user_asm_half(x,addr,err)				\
 ({								\
-	unsigned long __temp;					\
-	__asm__ __volatile__(					\
-	"1:	ldrbt	%1,[%3],#0\n"				\
-	"2:	ldrbt	%2,[%4],#0\n"				\
-	"	orr	%1, %1, %2, lsl #8\n"			\
-	"3:\n"							\
-	"	.section .fixup,\"ax\"\n"			\
-	"	.align	2\n"					\
-	"4:	mov	%0, %5\n"				\
-	"	mov	%1, #0\n"				\
-	"	b	3b\n"					\
-	"	.previous\n"					\
-	"	.section __ex_table,\"a\"\n"			\
-	"	.align	3\n"					\
-	"	.long	1b, 4b\n"				\
-	"	.long	2b, 4b\n"				\
-	"	.previous"					\
-	: "=r" (err), "=r" (x), "=&r" (__temp)			\
-	: "r" (addr), "r" ((int)(addr) + 1),			\
-	   "i" (-EFAULT), "0" (err));				\
+	unsigned long __b1, __b2;				\
+	__get_user_asm_byte(__b1, addr, err);			\
+	__get_user_asm_byte(__b2, (int)(addr) + 1, err);	\
+	(x) = __b1 | (__b2 << 8);				\
 })
 
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.4.2/linux/include/asm-arm/proc-fns.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/proc-fns.h	Tue Mar  6 19:44:35 2001
@@ -28,7 +28,7 @@
 
 #ifdef CONFIG_CPU_32
 # define CPU_INCLUDE_NAME "asm/cpu-multi32.h"
-# ifdef CONFIG_CPU_ARM6
+# ifdef CONFIG_CPU_ARM610
 #  ifdef CPU_NAME
 #   undef  MULTI_CPU
 #   define MULTI_CPU
@@ -36,7 +36,7 @@
 #   define CPU_NAME arm6
 #  endif
 # endif
-# ifdef CONFIG_CPU_ARM7
+# ifdef CONFIG_CPU_ARM710
 #  ifdef CPU_NAME
 #   undef  MULTI_CPU
 #   define MULTI_CPU
@@ -44,7 +44,7 @@
 #   define CPU_NAME arm7
 #  endif
 # endif
-# ifdef CONFIG_CPU_ARM720
+# ifdef CONFIG_CPU_ARM720T
 #  ifdef CPU_NAME
 #   undef  MULTI_CPU
 #   define MULTI_CPU
@@ -52,7 +52,7 @@
 #   define CPU_NAME arm720
 #  endif
 # endif
-# ifdef CONFIG_CPU_ARM920
+# ifdef CONFIG_CPU_ARM920T
 #  ifdef CPU_NAME
 #   undef  MULTI_CPU
 #   define MULTI_CPU
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h
--- v2.4.2/linux/include/asm-arm/uaccess.h	Tue Aug 29 14:09:15 2000
+++ linux/include/asm-arm/uaccess.h	Tue Mar  6 19:44:35 2001
@@ -182,7 +182,8 @@
 #define __put_user_nocheck(x,ptr,size)					\
 ({									\
 	long __pu_err = 0;						\
-	__put_user_size((x),(ptr),(size),__pu_err);			\
+	__typeof__(*(ptr)) *__pu_addr = (ptr);				\
+	__put_user_size((x),__pu_addr,(size),__pu_err);			\
 	__pu_err;							\
 })
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.4.2/linux/include/asm-arm/unistd.h	Fri Aug 11 14:29:03 2000
+++ linux/include/asm-arm/unistd.h	Tue Mar  6 19:44:35 2001
@@ -400,7 +400,6 @@
 
 static inline pid_t waitpid(pid_t pid, int *wait_stat, int options)
 {
-	extern long sys_wait4(int, int *, int, struct rusage *);
 	return sys_wait4((int)pid, wait_stat, options, NULL);
 }
 
@@ -412,7 +411,6 @@
 
 static inline pid_t wait(int * wait_stat)
 {
-	extern long sys_wait4(int, int *, int, struct rusage *);
 	return sys_wait4(-1, wait_stat, 0, NULL);
 }
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-arm/xor.h linux/include/asm-arm/xor.h
--- v2.4.2/linux/include/asm-arm/xor.h	Sun Nov 12 19:39:51 2000
+++ linux/include/asm-arm/xor.h	Tue Mar  6 19:44:35 2001
@@ -1 +1,142 @@
+/*
+ *  linux/include/asm-arm/xor.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * 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 <asm-generic/xor.h>
+
+#define __XOR(a1, a2) a1 ^= a2
+
+#define GET_BLOCK_2(dst) \
+	__asm__("ldmia	%0, {%1, %2}" \
+		: "=r" (dst), "=r" (a1), "=r" (a2) \
+		: "0" (dst))
+
+#define GET_BLOCK_4(dst) \
+	__asm__("ldmia	%0, {%1, %2, %3, %4}" \
+		: "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
+		: "0" (dst))
+
+#define XOR_BLOCK_2(src) \
+	__asm__("ldmia	%0!, {%1, %2}" \
+		: "=r" (src), "=r" (b1), "=r" (b2) \
+		: "0" (src)); \
+	__XOR(a1, b1); __XOR(a2, b2);
+
+#define XOR_BLOCK_4(src) \
+	__asm__("ldmia	%0!, {%1, %2, %3, %4}" \
+		: "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
+		: "0" (src)); \
+	__XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
+
+#define PUT_BLOCK_2(dst) \
+	__asm__ __volatile__("stmia	%0!, {%2, %3}" \
+		: "=r" (dst) \
+		: "0" (dst), "r" (a1), "r" (a2))
+
+#define PUT_BLOCK_4(dst) \
+	__asm__ __volatile__("stmia	%0!, {%2, %3, %4, %5}" \
+		: "=r" (dst) \
+		: "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
+
+static void
+xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 4;
+	register unsigned int a1 __asm__("r4");
+	register unsigned int a2 __asm__("r5");
+	register unsigned int a3 __asm__("r6");
+	register unsigned int a4 __asm__("r7");
+	register unsigned int b1 __asm__("r8");
+	register unsigned int b2 __asm__("r9");
+	register unsigned int b3 __asm__("ip");
+	register unsigned int b4 __asm__("lr");
+
+	do {
+		GET_BLOCK_4(p1);
+		XOR_BLOCK_4(p2);
+		PUT_BLOCK_4(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 4;
+	register unsigned int a1 __asm__("r4");
+	register unsigned int a2 __asm__("r5");
+	register unsigned int a3 __asm__("r6");
+	register unsigned int a4 __asm__("r7");
+	register unsigned int b1 __asm__("r8");
+	register unsigned int b2 __asm__("r9");
+	register unsigned int b3 __asm__("ip");
+	register unsigned int b4 __asm__("lr");
+
+	do {
+		GET_BLOCK_4(p1);
+		XOR_BLOCK_4(p2);
+		XOR_BLOCK_4(p3);
+		PUT_BLOCK_4(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3, unsigned long *p4)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 2;
+	register unsigned int a1 __asm__("r8");
+	register unsigned int a2 __asm__("r9");
+	register unsigned int b1 __asm__("ip");
+	register unsigned int b2 __asm__("lr");
+
+	do {
+		GET_BLOCK_2(p1);
+		XOR_BLOCK_2(p2);
+		XOR_BLOCK_2(p3);
+		XOR_BLOCK_2(p4);
+		PUT_BLOCK_2(p1);
+	} while (--lines);
+}
+
+static void
+xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+		unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	unsigned int lines = bytes / sizeof(unsigned long) / 2;
+	register unsigned int a1 __asm__("r8");
+	register unsigned int a2 __asm__("r9");
+	register unsigned int b1 __asm__("ip");
+	register unsigned int b2 __asm__("lr");
+
+	do {
+		GET_BLOCK_2(p1);
+		XOR_BLOCK_2(p2);
+		XOR_BLOCK_2(p3);
+		XOR_BLOCK_2(p4);
+		XOR_BLOCK_2(p5);
+		PUT_BLOCK_2(p1);
+	} while (--lines);
+}
+
+static struct xor_block_template xor_block_arm4regs = {
+	name:	"arm4regs",
+	do_2:	xor_arm4regs_2,
+	do_3:	xor_arm4regs_3,
+	do_4:	xor_arm4regs_4,
+	do_5:	xor_arm4regs_5,
+};
+
+#undef XOR_TRY_TEMPLATES
+#define XOR_TRY_TEMPLATES			\
+	do {					\
+		xor_speed(&xor_block_arm4regs);	\
+		xor_speed(&xor_block_8regs);	\
+		xor_speed(&xor_block_32regs);	\
+	} while (0)
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h
--- v2.4.2/linux/include/asm-i386/atomic.h	Thu Jan  4 14:50:46 2001
+++ linux/include/asm-i386/atomic.h	Fri Mar 23 18:23:07 2001
@@ -23,9 +23,33 @@
 
 #define ATOMIC_INIT(i)	{ (i) }
 
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically reads the value of @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 #define atomic_read(v)		((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ * 
+ * Atomically sets the value of @v to @i.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 #define atomic_set(v,i)		(((v)->counter) = (i))
 
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically adds @i to @v.  Note that the guaranteed useful range
+ * of an atomic_t is only 24 bits.
+ */
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
 	__asm__ __volatile__(
@@ -34,6 +58,14 @@
 		:"ir" (i), "m" (v->counter));
 }
 
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically subtracts @i from @v.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
 	__asm__ __volatile__(
@@ -42,6 +74,16 @@
 		:"ir" (i), "m" (v->counter));
 }
 
+/**
+ * atomic_sub_and_test - test variable then subtract 
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */
 static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
 {
 	unsigned char c;
@@ -53,6 +95,13 @@
 	return c;
 }
 
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 static __inline__ void atomic_inc(atomic_t *v)
 {
 	__asm__ __volatile__(
@@ -61,6 +110,13 @@
 		:"m" (v->counter));
 }
 
+/**
+ * atomic_dec - decrement the atomic variable
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 static __inline__ void atomic_dec(atomic_t *v)
 {
 	__asm__ __volatile__(
@@ -69,6 +125,15 @@
 		:"m" (v->counter));
 }
 
+/**
+ * atomic_dec_and_test - decrement by 1 and test
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 static __inline__ int atomic_dec_and_test(atomic_t *v)
 {
 	unsigned char c;
@@ -80,6 +145,15 @@
 	return c != 0;
 }
 
+/**
+ * atomic_inc_and_test - increment by 1 and test 
+ * @v: pointer of type atomic_t
+ * 
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 static __inline__ int atomic_inc_and_test(atomic_t *v)
 {
 	unsigned char c;
@@ -91,6 +165,16 @@
 	return c != 0;
 }
 
+/**
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ * 
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.  Note that the guaranteed
+ * useful range of an atomic_t is only 24 bits.
+ */ 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
 	unsigned char c;
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/highmem.h linux/include/asm-i386/highmem.h
--- v2.4.2/linux/include/asm-i386/highmem.h	Thu Jan  4 14:50:47 2001
+++ linux/include/asm-i386/highmem.h	Fri Mar 23 18:23:08 2001
@@ -2,14 +2,14 @@
  * highmem.h: virtual kernel memory mappings for high memory
  *
  * Used in CONFIG_HIGHMEM systems for memory pages which
- * are not addressable by direct kernel virtual adresses.
+ * are not addressable by direct kernel virtual addresses.
  *
  * Copyright (C) 1999 Gerhard Wichert, Siemens AG
  *		      Gerhard.Wichert@pdb.siemens.de
  *
  *
  * Redesigned the x86 32-bit VM architecture to deal with 
- * up to 16 Terrabyte physical memory. With current x86 CPUs
+ * up to 16 Terabyte physical memory. With current x86 CPUs
  * we now support up to 64 Gigabytes physical RAM.
  *
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.4.2/linux/include/asm-i386/pci.h	Thu Jan  4 14:51:31 2001
+++ linux/include/asm-i386/pci.h	Fri Mar 23 18:23:35 2001
@@ -152,6 +152,14 @@
  */
 extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
 {
+        /*
+         * we fall back to GFP_DMA when the mask isn't all 1s,
+         * so we can't guarantee allocations that must be
+         * within a tighter range than GFP_DMA..
+         */
+        if(mask < 0x00ffffff)
+                return 0;
+
 	return 1;
 }
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgalloc-2level.h linux/include/asm-i386/pgalloc-2level.h
--- v2.4.2/linux/include/asm-i386/pgalloc-2level.h	Sat Nov 20 10:09:05 1999
+++ linux/include/asm-i386/pgalloc-2level.h	Mon Mar 19 18:17:48 2001
@@ -3,21 +3,14 @@
 
 /*
  * traditional i386 two-level paging, page table allocation routines:
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
  */
-
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-extern __inline__ void free_pmd_fast(pmd_t *pmd) { }
-extern __inline__ void free_pmd_slow(pmd_t *pmd) { }
-
-extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	if (!pgd)
-		BUG();
-	return (pmd_t *) pgd;
-}
+#define pmd_alloc_one_fast()		({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one()			({ BUG(); ((pmd_t *)2); })
+#define pmd_free_slow(x)		do { } while (0)
+#define pmd_free_fast(x)		do { } while (0)
+#define pmd_free(x)			do { } while (0)
+#define pgd_populate(pmd, pte)		BUG()
 
 #endif /* _I386_PGALLOC_2LEVEL_H */
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgalloc-3level.h linux/include/asm-i386/pgalloc-3level.h
--- v2.4.2/linux/include/asm-i386/pgalloc-3level.h	Fri Dec  3 11:12:23 1999
+++ linux/include/asm-i386/pgalloc-3level.h	Mon Mar 19 17:12:21 2001
@@ -8,7 +8,7 @@
  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  */
 
-extern __inline__ pmd_t *get_pmd_slow(void)
+extern __inline__ pmd_t *pmd_alloc_one(void)
 {
 	pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
 
@@ -17,7 +17,7 @@
 	return ret;
 }
 
-extern __inline__ pmd_t *get_pmd_fast(void)
+extern __inline__ pmd_t *pmd_alloc_one_fast(void)
 {
 	unsigned long *ret;
 
@@ -30,39 +30,16 @@
 	return (pmd_t *)ret;
 }
 
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
+extern __inline__ void pmd_free_fast(pmd_t *pmd)
 {
 	*(unsigned long *)pmd = (unsigned long) pmd_quicklist;
 	pmd_quicklist = (unsigned long *) pmd;
 	pgtable_cache_size++;
 }
 
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
+extern __inline__ void pmd_free_slow(pmd_t *pmd)
 {
 	free_page((unsigned long)pmd);
-}
-
-extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	if (!pgd)
-		BUG();
-	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
-	if (pgd_none(*pgd)) {
-		pmd_t *page = get_pmd_fast();
-
-		if (!page)
-			page = get_pmd_slow();
-		if (page) {
-			if (pgd_none(*pgd)) {
-				set_pgd(pgd, __pgd(1 + __pa(page)));
-				__flush_tlb();
-				return page + address;
-			} else
-				free_pmd_fast(page);
-		} else
-			return NULL;
-	}
-	return (pmd_t *)pgd_page(*pgd) + address;
 }
 
 #endif /* _I386_PGALLOC_3LEVEL_H */
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- v2.4.2/linux/include/asm-i386/pgalloc.h	Thu Jan  4 14:50:46 2001
+++ linux/include/asm-i386/pgalloc.h	Fri Mar 23 18:23:07 2001
@@ -11,6 +11,8 @@
 #define pte_quicklist (current_cpu_data.pte_quick)
 #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz)
 
+#define pmd_populate(pmd, pte)		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
+
 #if CONFIG_X86_PAE
 # include <asm/pgalloc-3level.h>
 #else
@@ -65,14 +67,20 @@
 	free_page((unsigned long)pgd);
 }
 
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+static inline pte_t *pte_alloc_one(void)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	clear_page(pte);
+	return pte;
+}
 
-extern __inline__ pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(void)
 {
 	unsigned long *ret;
 
-	if((ret = (unsigned long *)pte_quicklist) != NULL) {
+	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
 		pgtable_cache_size--;
@@ -80,72 +88,29 @@
 	return (pte_t *)ret;
 }
 
-extern __inline__ void free_pte_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++;
 }
 
-extern __inline__ void free_pte_slow(pte_t *pte)
+extern __inline__ void pte_free_slow(pte_t *pte)
 {
 	free_page((unsigned long)pte);
 }
 
-#define pte_free_kernel(pte)    free_pte_slow(pte)
-#define pte_free(pte)	   free_pte_slow(pte)
-#define pgd_free(pgd)	   free_pgd_slow(pgd)
-#define pgd_alloc()	     get_pgd_fast()
-
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
-{
-	if (!pmd)
-		BUG();
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-	if (pmd_none(*pmd)) {
-		pte_t * page = (pte_t *) get_pte_fast();
-		
-		if (!page)
-			return get_pte_kernel_slow(pmd, address);
-		set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(page)));
-		return page + address;
-	}
-	if (pmd_bad(*pmd)) {
-		__handle_bad_pmd_kernel(pmd);
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
-	if (pmd_none(*pmd))
-		goto getnew;
-	if (pmd_bad(*pmd))
-		goto fix;
-	return (pte_t *)pmd_page(*pmd) + address;
-getnew:
-{
-	unsigned long page = (unsigned long) get_pte_fast();
-	
-	if (!page)
-		return get_pte_slow(pmd, address);
-	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(page)));
-	return (pte_t *)page + address;
-}
-fix:
-	__handle_bad_pmd(pmd);
-	return NULL;
-}
+#define pte_free_kernel(pte)	pte_free_slow(pte)
+#define pte_free(pte)		pte_free_slow(pte)
+#define pgd_free(pgd)		free_pgd_slow(pgd)
+#define pgd_alloc()		get_pgd_fast()
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  * (In the PAE case we free the page.)
  */
-#define pmd_free(pmd)	   free_pmd_slow(pmd)
+#define pmd_free_one(pmd)	free_pmd_slow(pmd)
 
 #define pmd_free_kernel		pmd_free
 #define pmd_alloc_kernel	pmd_alloc
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/string-486.h linux/include/asm-i386/string-486.h
--- v2.4.2/linux/include/asm-i386/string-486.h	Thu Jan  4 14:50:47 2001
+++ linux/include/asm-i386/string-486.h	Fri Mar 23 18:23:07 2001
@@ -352,11 +352,6 @@
 
 #ifdef CONFIG_X86_USE_3DNOW
 
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
 #include <asm/mmx.h>
 
 /*
@@ -365,14 +360,14 @@
 
 static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
 {
-	if(len<512 || in_interrupt())
+	if (len < 512)
 		return __memcpy_c(to, from, len);
 	return _mmx_memcpy(to, from, len);
 }
 
 static inline void *__memcpy3d(void *to, const void *from, size_t len)
 {
-	if(len<512 || in_interrupt())
+	if(len < 512)
 		return __memcpy_g(to, from, len);
 	return _mmx_memcpy(to, from, len);
 }
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.4.2/linux/include/asm-i386/string.h	Thu Jan  4 14:50:47 2001
+++ linux/include/asm-i386/string.h	Fri Mar 23 18:23:07 2001
@@ -287,13 +287,6 @@
 
 #ifdef CONFIG_X86_USE_3DNOW
 
-/* All this just for in_interrupt() ... */
-
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
 #include <asm/mmx.h>
 
 /*
@@ -302,14 +295,14 @@
 
 static inline void * __constant_memcpy3d(void * to, const void * from, size_t len)
 {
-	if(len<512 || in_interrupt())
+	if (len < 512)
 		return __constant_memcpy(to, from, len);
 	return _mmx_memcpy(to, from, len);
 }
 
 extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
 {
-	if(len<512 || in_interrupt())
+	if (len < 512)
 		return __memcpy(to, from, len);
 	return _mmx_memcpy(to, from, len);
 }
@@ -549,10 +542,10 @@
 {
 	if (!size)
 		return addr;
-	__asm__("repnz; scasb
-		jnz 1f
-		dec %%edi
-1:		"
+	__asm__("repnz; scasb\n\t"
+		"jnz 1f\n\t"
+		"dec %%edi\n"
+		"1:"
 		: "=D" (addr), "=c" (size)
 		: "0" (addr), "1" (size), "a" (c));
 	return addr;
diff -u --recursive --new-file v2.4.2/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.4.2/linux/include/asm-i386/system.h	Sat Feb  3 19:51:31 2001
+++ linux/include/asm-i386/system.h	Fri Mar 23 18:23:07 2001
@@ -144,16 +144,17 @@
 extern inline void __set_64bit (unsigned long long * ptr,
 		unsigned int low, unsigned int high)
 {
-__asm__ __volatile__ (
-	"1:	movl (%0), %%eax;
-		movl 4(%0), %%edx;
-		cmpxchg8b (%0);
-		jnz 1b"
-	::		"D"(ptr),
+	__asm__ __volatile__ (
+		"\n1:\t"
+		"movl (%0), %%eax\n\t"
+		"movl 4(%0), %%edx\n\t"
+		"cmpxchg8b (%0)\n\t"
+		"jnz 1b"
+		: /* no outputs */
+		:	"D"(ptr),
 			"b"(low),
 			"c"(high)
-	:
-			"ax","dx","memory");
+		:	"ax","dx","memory");
 }
 
 extern void inline __set_64bit_constant (unsigned long long *ptr,
diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/pci/bridge.h linux/include/asm-ia64/sn/pci/bridge.h
--- v2.4.2/linux/include/asm-ia64/sn/pci/bridge.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pci/bridge.h	Tue Mar  6 19:44:34 2001
@@ -373,7 +373,7 @@
 				    ds:2,	/* Data size	  */
 				    gbr:1,	/* GBR enable	  */
 				    vbpm:1,	/* VBPM message	  */
-				    error:1,	/* Error occured  */
+				    error:1,	/* Error occurred  */
 				    barr:1,	/* Barrier op	  */
 				    rsvd:8;
 	} berr_st;
@@ -693,7 +693,7 @@
 #define BRIDGE_INT_ADDR(x)	(BRIDGE_INT_ADDR0+(x)*BRIDGE_INT_ADDR_OFF)
 
 #define BRIDGE_INT_VIEW		0x000174	/* Interrupt view */
-#define BRIDGE_MULTIPLE_INT	0x00017c	/* Multiple interrupt occured */
+#define BRIDGE_MULTIPLE_INT	0x00017c	/* Multiple interrupt occurred */
 
 #define BRIDGE_FORCE_ALWAYS0	0x000184	/* Force an interrupt (always)*/
 #define BRIDGE_FORCE_ALWAYS_OFF 0x000008	/* Force Always offset */
diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/pci/pcibr_private.h linux/include/asm-ia64/sn/pci/pcibr_private.h
--- v2.4.2/linux/include/asm-ia64/sn/pci/pcibr_private.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/pci/pcibr_private.h	Tue Mar  6 19:44:34 2001
@@ -328,7 +328,7 @@
 #ifdef IRIX
 	toid_t                  bserr_toutid;	/* Timeout started by errintr */
 #endif
-	iopaddr_t               bserr_addr;	/* Address where error occured */
+	iopaddr_t               bserr_addr;	/* Address where error occurred */
 	bridgereg_t             bserr_intstat;	/* interrupts active at error time */
     } bs_errinfo;
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd.h linux/include/asm-ia64/sn/sn1/hubmd.h
--- v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/hubmd.h	Tue Mar  6 19:44:34 2001
@@ -2140,7 +2140,7 @@
  * corresponds to the valid bit, and bit 1 of each two-bit field        *
  * corresponds to the overrun bit.                                      *
  * The rule for the valid bit is that it gets set whenever that error   *
- * occurs, regardless of whether a higher priority error has occured.   *
+ * occurs, regardless of whether a higher priority error has occurred.   *
  * The rule for the overrun bit is that it gets set whenever we are     *
  * unable to record the address information for this particular         *
  * error, due to a previous error of the same or higher priority.       *
@@ -2221,7 +2221,7 @@
  * corresponds to the valid bit, and bit 1 of each two-bit field        *
  * corresponds to the overrun bit.                                      *
  * The rule for the valid bit is that it gets set whenever that error   *
- * occurs, regardless of whether a higher priority error has occured.   *
+ * occurs, regardless of whether a higher priority error has occurred.  *
  * The rule for the overrun bit is that it gets set whenever we are     *
  * unable to record the address information for this particular         *
  * error, due to a previous error of the same or higher priority.       *
diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd_next.h linux/include/asm-ia64/sn/sn1/hubmd_next.h
--- v2.4.2/linux/include/asm-ia64/sn/sn1/hubmd_next.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/sn1/hubmd_next.h	Tue Mar  6 19:44:34 2001
@@ -648,7 +648,7 @@
 #define MD_SDIR_MASK            0xffffffff
 
 /* When premium mode is on for probing but standard directory memory
-   is installed, the vaild directory bits depend on the phys. bank */
+   is installed, the valid directory bits depend on the phys. bank */
 #define MD_PDIR_PROBE_MASK(pb)  0xffffffffffffffff
 #define MD_SDIR_PROBE_MASK(pb)  (0xffff0000ffff << ((pb) ? 16 : 0))
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/sn/xtalk/xbow.h linux/include/asm-ia64/sn/xtalk/xbow.h
--- v2.4.2/linux/include/asm-ia64/sn/xtalk/xbow.h	Thu Jan  4 13:00:15 2001
+++ linux/include/asm-ia64/sn/xtalk/xbow.h	Tue Mar  6 19:44:34 2001
@@ -494,7 +494,7 @@
 typedef union xbw0_status_u {
     xbowreg_t               statusword;
     struct {
-       uint32_t		mult_err:1,	/* Multiple error occured */
+       uint32_t		mult_err:1,	/* Multiple error occurred */
                                 connect_tout:1, /* Connection timeout   */
                                 xtalk_err:1,    /* Xtalk pkt with error bit */
                                 /* End of Xbridge only */
@@ -524,7 +524,7 @@
 				/* End of Xbridge only */
 				xtalk_err:1,	/* Xtalk pkt with error bit */
 				connect_tout:1, /* Connection timeout	*/
-				mult_err:1;	/* Multiple error occured */
+				mult_err:1;	/* Multiple error occurred */
     } xbw0_stfield;
 } xbw0_status_t;
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h
--- v2.4.2/linux/include/asm-ia64/system.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/system.h	Tue Mar  6 19:44:34 2001
@@ -64,7 +64,7 @@
 	} console_info;
 	__u16 num_pci_vectors;	/* number of ACPI derived PCI IRQ's*/
 	__u64 pci_vectors;	/* physical address of PCI data (pci_vector_struct)*/
-	__u64 fpswa;		/* physical address of the the fpswa interface */
+	__u64 fpswa;		/* physical address of the fpswa interface */
 	__u64 initrd_start;
 	__u64 initrd_size;
 } ia64_boot_param;
diff -u --recursive --new-file v2.4.2/linux/include/asm-mips64/smp.h linux/include/asm-mips64/smp.h
--- v2.4.2/linux/include/asm-mips64/smp.h	Fri Aug  4 16:15:37 2000
+++ linux/include/asm-mips64/smp.h	Fri Mar  2 11:30:15 2001
@@ -40,6 +40,7 @@
 
 /* Good enough for toy^Wupto 64 CPU Origins.  */
 extern unsigned long cpu_present_mask;
+#define cpu_online_map cpu_present_mask
 
 #endif
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/cpm_8260.h linux/include/asm-ppc/cpm_8260.h
--- v2.4.2/linux/include/asm-ppc/cpm_8260.h	Sat Nov 11 18:23:10 2000
+++ linux/include/asm-ppc/cpm_8260.h	Sat Mar  3 10:52:14 2001
@@ -112,7 +112,7 @@
 	uint	cbd_bufaddr;	/* Buffer address in host memory */
 } cbd_t;
 
-#define BD_SC_EMPTY	((ushort)0x8000)	/* Recieve is empty */
+#define BD_SC_EMPTY	((ushort)0x8000)	/* Receive is empty */
 #define BD_SC_READY	((ushort)0x8000)	/* Transmit is ready */
 #define BD_SC_WRAP	((ushort)0x2000)	/* Last buffer descriptor */
 #define BD_SC_INTRPT	((ushort)0x1000)	/* Interrupt on change */
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/highmem.h linux/include/asm-ppc/highmem.h
--- v2.4.2/linux/include/asm-ppc/highmem.h	Wed Nov  8 19:01:34 2000
+++ linux/include/asm-ppc/highmem.h	Sat Mar  3 10:52:14 2001
@@ -4,7 +4,7 @@
  * PowerPC version, stolen from the i386 version.
  *
  * Used in CONFIG_HIGHMEM systems for memory pages which
- * are not addressable by direct kernel virtual adresses.
+ * are not addressable by direct kernel virtual addresses.
  *
  * Copyright (C) 1999 Gerhard Wichert, Siemens AG
  *		      Gerhard.Wichert@pdb.siemens.de
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.4.2/linux/include/asm-ppc/irq.h	Sat Feb  3 19:51:31 2001
+++ linux/include/asm-ppc/irq.h	Sat Mar  3 10:52:14 2001
@@ -88,23 +88,31 @@
 #define	SIU_IRQ7	(14)
 #define	SIU_LEVEL7	(15)
 
+/* Now include the board configuration specific associations.
+*/
+#include <asm/mpc8xx.h>
+
 /* The internal interrupts we can configure as we see fit.
  * My personal preference is CPM at level 2, which puts it above the
  * MBX PCI/ISA/IDE interrupts.
  */
+#ifndef PIT_INTERRUPT
 #define PIT_INTERRUPT		SIU_LEVEL0
+#endif
+#ifndef	CPM_INTERRUPT
 #define CPM_INTERRUPT		SIU_LEVEL2
+#endif
+#ifndef	PCMCIA_INTERRUPT
 #define PCMCIA_INTERRUPT	SIU_LEVEL6
+#endif
+#ifndef	DEC_INTERRUPT
 #define DEC_INTERRUPT		SIU_LEVEL7
+#endif
 
 /* Some internal interrupt registers use an 8-bit mask for the interrupt
  * level instead of a number.
  */
 #define	mk_int_int_mask(IL) (1 << (7 - (IL/2)))
-
-/* Now include the board configuration specific associations.
-*/
-#include <asm/mpc8xx.h>
 
 /* always the same on 8xx -- Cort */
 static __inline__ int irq_cannonicalize(int irq)
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/ivms8.h linux/include/asm-ppc/ivms8.h
--- v2.4.2/linux/include/asm-ppc/ivms8.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/ivms8.h	Sat Mar  3 10:52:14 2001
@@ -0,0 +1,92 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * Speech Design Integrated Voicemail Systems (IVMS8) boards.
+ *
+ * Copyright (c) 2000 Wolfgang Denk (wd@denx.de)
+ */
+#ifndef __MACH_IVMS8_DEFS
+#define __MACH_IVMS8_DEFS
+
+#ifndef __ASSEMBLY__
+
+typedef	void (interrupt_handler_t)(void *);
+
+typedef struct serial_io {
+	int	(*getc)(void);
+	int	(*tstc)(void);
+	void	(*putc)(const char c);
+	void	(*printf)(const char *fmt, ...);
+} serial_io_t;
+
+typedef struct intr_util {
+	void	(*install_hdlr)(int, interrupt_handler_t *, void *);
+	void	(*free_hdlr)(int);
+} intr_util_t;
+
+
+/* A Board Information structure that is given to a program when
+ * ppcboot starts it up.
+ */
+typedef struct bd_info {
+	 unsigned long	bi_memstart;	/* start of  DRAM memory		*/
+	 unsigned long	bi_memsize;	/* size	 of  DRAM memory in bytes	*/
+	 unsigned long	bi_flashstart;	/* start of FLASH memory		*/
+	 unsigned long	bi_flashsize;	/* size	 of FLASH memory		*/
+	 unsigned long	bi_flashoffset; /* reserved area for startup monitor	*/
+	 unsigned long	bi_sramstart;	/* start of  SRAM memory		*/
+	 unsigned long	bi_sramsize;	/* size	 of  SRAM memory		*/
+	 unsigned long	bi_immr_base;	/* base of IMMR register		*/
+	 unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS)	*/
+	 unsigned long	bi_ip_addr;	/* IP Address				*/
+	 unsigned char	bi_enetaddr[6]; /* Ethernet adress			*/
+	 unsigned char	bi_reserved[2]; /* -- just for alignment --		*/
+	 unsigned long	bi_intfreq;	/* Internal Freq, in MHz		*/
+	 unsigned long	bi_busfreq;	/* Bus Freq, in MHz			*/
+	 unsigned long	bi_baudrate;	/* Console Baudrate			*/
+	 serial_io_t	bi_serial_io;	/* Addr of monitor fnc for Console I/O	*/
+	 intr_util_t	bi_interrupt;	/* Addr of monitor fnc for Interrupts	*/
+} bd_t;
+
+#endif /* __ASSEMBLY__ */
+
+#define	IVMS_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR			*/
+#define	IVMS_IMAP_SIZE	(64 * 1024)	/* size of mapped area			*/
+
+#define	IMAP_ADDR	IVMS_IMMR_BASE	/* physical base address of IMMR area	*/
+#define IMAP_SIZE	IVMS_IMAP_SIZE	/* mapped size of IMMR area		*/
+
+#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
+
+#define	FEC_INTERRUPT	 9		/* = SIU_LEVEL4				*/
+#define IDE0_INTERRUPT	10		/* = IRQ5				*/
+#define	CPM_INTERRUPT	11		/* = SIU_LEVEL5 (was: SIU_LEVEL2)	*/
+#define PHY_INTERRUPT	12		/* = IRQ6				*/
+
+#define	MAX_HWIFS	1	/* overwrite default in include/asm-ppc/ide.h	*/
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory	*/
+#define IDE0_DATA_REG_OFFSET		0x0000
+#define IDE0_ERROR_REG_OFFSET		0x0081
+#define IDE0_NSECTOR_REG_OFFSET		0x0082
+#define IDE0_SECTOR_REG_OFFSET		0x0083
+#define IDE0_LCYL_REG_OFFSET		0x0084
+#define IDE0_HCYL_REG_OFFSET		0x0085
+#define IDE0_SELECT_REG_OFFSET		0x0086
+#define IDE0_STATUS_REG_OFFSET		0x0087
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used			*/
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+/* Generic 8xx type
+*/
+#define _MACH_8xx (_MACH_ivms8)
+
+#endif	/* __MACH_IVMS8_DEFS */
+
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/mpc8xx.h linux/include/asm-ppc/mpc8xx.h
--- v2.4.2/linux/include/asm-ppc/mpc8xx.h	Sat Nov 11 18:23:11 2000
+++ linux/include/asm-ppc/mpc8xx.h	Sat Mar  3 10:52:14 2001
@@ -33,12 +33,16 @@
 #include <asm/rpxclassic.h>
 #endif
 
-#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM860L))
-#include <asm/tqm860.h>
+#if (defined(CONFIG_TQM860) || defined(CONFIG_TQM8xxL))
+#include <asm/tqm8xx.h>
 #endif
 
-#ifdef CONFIG_TQM8xxL
-#include <asm/tqm8xxL.h>
+#if defined(CONFIG_SPD823TS)
+#include <asm/spd8xx.h>
+#endif
+
+#if defined(CONFIG_IVMS8)
+#include <asm/ivms8.h>
 #endif
 
 /* I need this to get pt_regs.......
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- v2.4.2/linux/include/asm-ppc/pci.h	Sat Feb  3 19:51:31 2001
+++ linux/include/asm-ppc/pci.h	Sat Mar  3 10:52:14 2001
@@ -34,6 +34,7 @@
  * 
  * Obsolete ! Drivers should now use pci_resource_to_bus
  */
+extern unsigned long phys_to_bus(unsigned long pa);
 extern unsigned long pci_phys_to_bus(unsigned long pa, int busnr);
 extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
     
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.4.2/linux/include/asm-ppc/processor.h	Sat Feb  3 19:51:31 2001
+++ linux/include/asm-ppc/processor.h	Sat Mar  3 10:52:14 2001
@@ -516,6 +516,8 @@
 #define _MACH_8260	0x00002000	/* Generic 8260 */
 #define _MACH_tqm860	0x00004000	/* TQM860/L */
 #define _MACH_tqm8xxL	0x00008000	/* TQM8xxL */
+#define _MACH_spd8xxL	0x00010000	/* SPD8xx */
+#define _MACH_ibms8	0x00020000	/* IVMS8 */
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.4.2/linux/include/asm-ppc/semaphore.h	Tue May  2 13:05:40 2000
+++ linux/include/asm-ppc/semaphore.h	Sat Mar  3 10:52:14 2001
@@ -132,7 +132,7 @@
 
 #define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name, 0, 0)
 #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 1, 0)
-#define DECLAER_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0, 1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name, 0, 1)
 
 extern inline void init_rwsem(struct rw_semaphore *sem)
 {
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/spd8xx.h linux/include/asm-ppc/spd8xx.h
--- v2.4.2/linux/include/asm-ppc/spd8xx.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/spd8xx.h	Sat Mar  3 10:52:14 2001
@@ -0,0 +1,105 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * Speech Design SPD8xxTS boards.
+ *
+ * Copyright (c) 2000 Wolfgang Denk (wd@denx.de)
+ */
+#ifndef __MACH_SPD8xx_DEFS
+#define __MACH_SPD8xx_DEFS
+
+#ifndef __ASSEMBLY__
+
+typedef	void (interrupt_handler_t)(void *);
+
+typedef struct serial_io {
+	int	(*getc)(void);
+	int	(*tstc)(void);
+	void	(*putc)(const char c);
+	void	(*printf)(const char *fmt, ...);
+} serial_io_t;
+
+typedef struct intr_util {
+	void	(*install_hdlr)(int, interrupt_handler_t *, void *);
+	void	(*free_hdlr)(int);
+} intr_util_t;
+
+
+/* A Board Information structure that is given to a program when
+ * ppcboot starts it up.
+ */
+typedef struct bd_info {
+	 unsigned long	bi_memstart;	/* start of  DRAM memory		*/
+	 unsigned long	bi_memsize;	/* size	 of  DRAM memory in bytes	*/
+	 unsigned long	bi_flashstart;	/* start of FLASH memory		*/
+	 unsigned long	bi_flashsize;	/* size	 of FLASH memory		*/
+	 unsigned long	bi_flashoffset; /* reserved area for startup monitor	*/
+	 unsigned long	bi_sramstart;	/* start of  SRAM memory		*/
+	 unsigned long	bi_sramsize;	/* size	 of  SRAM memory		*/
+	 unsigned long	bi_immr_base;	/* base of IMMR register		*/
+	 unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS)	*/
+	 unsigned long	bi_ip_addr;	/* IP Address				*/
+	 unsigned char	bi_enetaddr[6]; /* Ethernet adress			*/
+	 unsigned char	bi_reserved[2]; /* -- just for alignment --		*/
+	 unsigned long	bi_intfreq;	/* Internal Freq, in MHz		*/
+	 unsigned long	bi_busfreq;	/* Bus Freq, in MHz			*/
+	 unsigned long	bi_baudrate;	/* Console Baudrate			*/
+	 serial_io_t	bi_serial_io;	/* Addr of monitor fnc for Console I/O	*/
+	 intr_util_t	bi_interrupt;	/* Addr of monitor fnc for Interrupts	*/
+} bd_t;
+
+#endif /* __ASSEMBLY__ */
+
+#define	SPD_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR			*/
+#define	SPD_IMAP_SIZE	(64 * 1024)	/* size of mapped area			*/
+
+#define	IMAP_ADDR	SPD_IMMR_BASE	/* physical base address of IMMR area	*/
+#define IMAP_SIZE	SPD_IMAP_SIZE	/* mapped size of IMMR area		*/
+
+#define PCMCIA_MEM_ADDR	((uint)0xFE100000)
+#define PCMCIA_MEM_SIZE	((uint)(64 * 1024))
+
+#define IDE0_INTERRUPT	10		/* = IRQ5				*/
+#define	IDE1_INTERRUPT	12		/* = IRQ6				*/
+#define	CPM_INTERRUPT	13		/* = SIU_LEVEL6 (was: SIU_LEVEL2)	*/
+
+#define	MAX_HWIFS	2	/* overwrite default in include/asm-ppc/ide.h	*/
+
+/*
+ * Definitions for IDE0 Interface
+ */
+#define IDE0_BASE_OFFSET		0x0000	/* Offset in PCMCIA memory	*/
+#define IDE0_DATA_REG_OFFSET		0x0000
+#define IDE0_ERROR_REG_OFFSET		0x0081
+#define IDE0_NSECTOR_REG_OFFSET		0x0082
+#define IDE0_SECTOR_REG_OFFSET		0x0083
+#define IDE0_LCYL_REG_OFFSET		0x0084
+#define IDE0_HCYL_REG_OFFSET		0x0085
+#define IDE0_SELECT_REG_OFFSET		0x0086
+#define IDE0_STATUS_REG_OFFSET		0x0087
+#define IDE0_CONTROL_REG_OFFSET		0x0106
+#define IDE0_IRQ_REG_OFFSET		0x000A	/* not used			*/
+
+/*
+ * Definitions for IDE1 Interface
+ */
+#define IDE1_BASE_OFFSET		0x0C00	/* Offset in PCMCIA memory	*/
+#define IDE1_DATA_REG_OFFSET		0x0000
+#define IDE1_ERROR_REG_OFFSET		0x0081
+#define IDE1_NSECTOR_REG_OFFSET		0x0082
+#define IDE1_SECTOR_REG_OFFSET		0x0083
+#define IDE1_LCYL_REG_OFFSET		0x0084
+#define IDE1_HCYL_REG_OFFSET		0x0085
+#define IDE1_SELECT_REG_OFFSET		0x0086
+#define IDE1_STATUS_REG_OFFSET		0x0087
+#define IDE1_CONTROL_REG_OFFSET		0x0106
+#define IDE1_IRQ_REG_OFFSET		0x000A	/* not used			*/
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+/* Generic 8xx type
+*/
+#define _MACH_8xx (_MACH_spd8xx)
+
+#endif	/* __MACH_SPD8xx_DEFS */
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.4.2/linux/include/asm-ppc/system.h	Sat Nov 11 18:23:11 2000
+++ linux/include/asm-ppc/system.h	Sat Mar  3 10:52:14 2001
@@ -49,15 +49,6 @@
 
 extern void xmon_irq(int, void *, struct pt_regs *);
 extern void xmon(struct pt_regs *excp);
-
-
-/* Data cache block flush - write out the cache line containing the
-   specified address and then invalidate it in the cache. */
-extern __inline__ void dcbf(void *line)
-{
-	asm("dcbf %0,%1; sync" : : "r" (line), "r" (0));
-}
-
 extern void print_backtrace(unsigned long *);
 extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/time.h linux/include/asm-ppc/time.h
--- v2.4.2/linux/include/asm-ppc/time.h	Sat Nov 11 18:23:11 2000
+++ linux/include/asm-ppc/time.h	Sat Mar  3 10:52:14 2001
@@ -2,7 +2,7 @@
  * $Id: time.h,v 1.12 1999/08/27 04:21:23 cort Exp $
  * Common time prototypes and such for all ppc machines.
  *
- * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Written by Cort Dougan (cort@fsmlabs.com) to merge
  * Paul Mackerras' version and mine for PReP and Pmac.
  */
 
@@ -16,6 +16,7 @@
 extern unsigned tb_ticks_per_jiffy;
 extern unsigned tb_to_us;
 extern unsigned tb_last_stamp;
+extern unsigned long disarm_decr[NR_CPUS];
 
 extern void to_tm(int tim, struct rtc_time * tm);
 extern time_t last_rtc_update;
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tlb.h linux/include/asm-ppc/tlb.h
--- v2.4.2/linux/include/asm-ppc/tlb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/tlb.h	Sat Mar  3 10:52:14 2001
@@ -0,0 +1 @@
+#include <asm-generic/tlb.h>
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tqm860.h linux/include/asm-ppc/tqm860.h
--- v2.4.2/linux/include/asm-ppc/tqm860.h	Sat Nov 11 18:23:11 2000
+++ linux/include/asm-ppc/tqm860.h	Wed Dec 31 16:00:00 1969
@@ -1,67 +0,0 @@
-
-/*
- * A collection of structures, addresses, and values associated with
- * the TQ Systems TQM860 modules.  This was originally created for the
- * MBX860, and probably needs revisions for other boards (like the 821).
- * When this file gets out of control, we can split it up into more
- * meaningful pieces.
- *
- * Based on mbx.h, Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
- *
- * Copyright (c) 1999 Wolfgang Denk (wd@denx.de)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_TQM860_DEFS
-#define __MACH_TQM860_DEFS
-
-/* A Board Information structure that is given to a program when
- * EPPC-Bug starts it up.
- */
-typedef struct bd_info {
-	 unsigned long	bi_memstart;	/* start of  DRAM memory */
-	 unsigned long	bi_memsize;	/* size  of  DRAM memory in bytes */
-	 unsigned long	bi_flashstart;	/* start of FLASH memory */
-	 unsigned long	bi_flashsize;	/* size  of FLASH memory */
-	 unsigned long	bi_flashoffset;	/* reserved area for startup monitor */
-	 unsigned long	bi_sramstart;	/* start of  SRAM memory */
-	 unsigned long	bi_sramsize;	/* size  of  SRAM memory */
-	 unsigned long	bi_immr_base;	/* base of IMMR register */
-	 unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
-	 unsigned long	bi_ip_addr;	/* IP Address */
-	 unsigned char	bi_enetaddr[6];	/* Ethernet adress */
-	 unsigned char	bi_reserved[2];	/* -- just for alignment -- */
-	 unsigned long	bi_putchar;	/* Addr of monitor putchar() to Console	*/
-	 unsigned long	bi_intfreq;	/* Internal Freq, in MHz */
-	 unsigned long	bi_busfreq;	/* Bus Freq, in MHz */
-	 unsigned long	bi_baudrate;	/* Console Baudrate */
-} bd_t;
-
-/* Configuration options for TQ Systems TQM860 mini module
- */
-
-#define	TQM_RESET_ADDR	0x40000100	/* Monitor Reset Entry */
-
-#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define	TQM_CLOCKRATE	50		/* 50 MHz Clock */
-#define	TQM_BAUDRATE	115200		/* Console baud rate */
-#define	TQM_IP_ADDR	0x0A000063	/* IP addr: 10.0.0.99 */
-
-#define	TQM_SERVER_IP	"10.0.0.3"	/* NFS server IP addr */
-#define	TQM_SERVER_DIR	"/LinuxPPC"	/* NFS exported root */
-
-#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area */
-#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-/* Generic 8xx type
-*/
-#define _MACH_8xx (_MACH_tqm860)
-
-#endif	/* __MACH_TQM860_DEFS */
-
-#endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tqm8xx.h linux/include/asm-ppc/tqm8xx.h
--- v2.4.2/linux/include/asm-ppc/tqm8xx.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/tqm8xx.h	Sat Mar  3 10:52:14 2001
@@ -0,0 +1,76 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the TQ Systems TQM8xx(L) modules.  This was originally created for the
+ * MBX860, and probably needs revisions for other boards (like the 821).
+ * When this file gets out of control, we can split it up into more
+ * meaningful pieces.
+ *
+ * Based on mbx.h, Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+ *
+ * Copyright (c) 1999,2000 Wolfgang Denk (wd@denx.de)
+ */
+#ifndef __MACH_TQM8xx_DEFS
+#define __MACH_TQM8xx_DEFS
+
+#ifndef __ASSEMBLY__
+
+typedef	void (interrupt_handler_t)(void *);
+
+typedef struct serial_io {
+	int	(*getc)(void);
+	int	(*tstc)(void);
+	void	(*putc)(const char c);
+	void	(*printf)(const char *fmt, ...);
+} serial_io_t;
+
+typedef struct intr_util {
+	void	(*install_hdlr)(int, interrupt_handler_t *, void *);
+	void	(*free_hdlr)(int);
+} intr_util_t;
+
+
+/* A Board Information structure that is given to a program when
+ * ppcboot starts it up.
+ */
+typedef struct bd_info {
+	 unsigned long	bi_memstart;	/* start of  DRAM memory		*/
+	 unsigned long	bi_memsize;	/* size	 of  DRAM memory in bytes	*/
+	 unsigned long	bi_flashstart;	/* start of FLASH memory		*/
+	 unsigned long	bi_flashsize;	/* size	 of FLASH memory		*/
+	 unsigned long	bi_flashoffset; /* reserved area for startup monitor	*/
+	 unsigned long	bi_sramstart;	/* start of  SRAM memory		*/
+	 unsigned long	bi_sramsize;	/* size	 of  SRAM memory		*/
+	 unsigned long	bi_immr_base;	/* base of IMMR register		*/
+	 unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS)	*/
+	 unsigned long	bi_ip_addr;	/* IP Address				*/
+	 unsigned char	bi_enetaddr[6]; /* Ethernet adress			*/
+	 unsigned char	bi_reserved[2]; /* -- just for alignment --		*/
+	 unsigned long	bi_intfreq;	/* Internal Freq, in MHz		*/
+	 unsigned long	bi_busfreq;	/* Bus Freq, in MHz			*/
+	 unsigned long	bi_baudrate;	/* Console Baudrate			*/
+	 serial_io_t	bi_serial_io;	/* Addr of monitor fnc for Console I/O	*/
+	 intr_util_t	bi_interrupt;	/* Addr of monitor fnc for Interrupts	*/
+} bd_t;
+
+#endif /* __ASSEMBLY__ */
+
+#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR			*/
+#define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area			*/
+
+#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area	*/
+#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area		*/
+
+/* We don't use the 8259.
+*/
+#define NR_8259_INTS	0
+
+/* Generic 8xx type
+*/
+#if defined(CONFIG_TQM8xxL)
+#define _MACH_8xx (_MACH_tqm8xxL)
+#endif
+#if defined(CONFIG_TQM860)
+#define _MACH_8xx (_MACH_tqm860)
+#endif
+
+#endif	/* __MACH_TQM8xx_DEFS */
diff -u --recursive --new-file v2.4.2/linux/include/asm-ppc/tqm8xxL.h linux/include/asm-ppc/tqm8xxL.h
--- v2.4.2/linux/include/asm-ppc/tqm8xxL.h	Sat Nov 11 18:23:11 2000
+++ linux/include/asm-ppc/tqm8xxL.h	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-
-/*
- * A collection of structures, addresses, and values associated with
- * the TQ Systems TQM850L modules.  This was originally created for the
- * MBX860, and probably needs revisions for other boards (like the 821).
- * When this file gets out of control, we can split it up into more
- * meaningful pieces.
- *
- * Based on mbx.h, Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
- *
- * Copyright (c) 1999 Wolfgang Denk (wd@denx.de)
- */
-#ifdef __KERNEL__
-#ifndef __MACH_TQM8xxL_DEFS
-#define __MACH_TQM8xxL_DEFS
-
-/* A Board Information structure that is given to a program when
- * EPPC-Bug starts it up.
- */
-typedef struct bd_info {
-	 unsigned long	bi_memstart;	/* start of  DRAM memory */
-	 unsigned long	bi_memsize;	/* size  of  DRAM memory in bytes */
-	 unsigned long	bi_flashstart;	/* start of FLASH memory */
-	 unsigned long	bi_flashsize;	/* size  of FLASH memory */
-	 unsigned long	bi_flashoffset;	/* reserved area for startup monitor */
-	 unsigned long	bi_sramstart;	/* start of  SRAM memory */
-	 unsigned long	bi_sramsize;	/* size  of  SRAM memory */
-	 unsigned long	bi_immr_base;	/* base of IMMR register */
-	 unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
-	 unsigned long	bi_ip_addr;	/* IP Address */
-	 unsigned char	bi_enetaddr[6];	/* Ethernet adress */
-	 unsigned char	bi_reserved[2];	/* -- just for alignment -- */
-	 unsigned long	bi_putchar;	/* Addr of monitor putchar() to Console	*/
-	 unsigned long	bi_intfreq;	/* Internal Freq, in MHz */
-	 unsigned long	bi_busfreq;	/* Bus Freq, in MHz */
-	 unsigned long	bi_baudrate;	/* Console Baudrate */
-} bd_t;
-
-/* Configuration options for TQ Systems TQM850L mini module
- */
-
-#define	TQM_RESET_ADDR	0x40000100	/* Monitor Reset Entry */
-
-#define	TQM_IMMR_BASE	0xFFF00000	/* phys. addr of IMMR */
-#define	TQM_IMAP_SIZE	(64 * 1024)	/* size of mapped area */
-
-#define	TQM_CLOCKRATE	50		/* 50 MHz Clock */
-/*#define	TQM_BAUDRATE	115200	*/	/* Console baud rate */
-#define	TQM_BAUDRATE	38400		/* Console baud rate */
-#define	TQM_IP_ADDR	0x0A000063	/* IP addr: 10.0.0.99 */
-
-#define	TQM_SERVER_IP	"10.0.0.2"	/* NFS server IP addr */
-#define	TQM_SERVER_DIR	"/LinuxPPC"	/* NFS exported root */
-
-#define	IMAP_ADDR	TQM_IMMR_BASE	/* physical base address of IMMR area */
-#define IMAP_SIZE	TQM_IMAP_SIZE	/* mapped size of IMMR area */
-
-/* We don't use the 8259.
-*/
-#define NR_8259_INTS	0
-
-/* Generic 8xx type
-*/
-#define _MACH_8xx (_MACH_tqm8xxL)
-
-#endif	/* __MACH_TQM8xxL_DEFS */
-
-#endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h
--- v2.4.2/linux/include/asm-s390/ccwcache.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390/ccwcache.h	Fri Mar  2 11:12:06 2001
@@ -59,7 +59,7 @@
 #define CQR_STATUS_FILLED   0x01	/* request is ready to be preocessed */
 #define CQR_STATUS_QUEUED   0x02	/* request is queued to be processed */
 #define CQR_STATUS_IN_IO    0x03	/* request is currently in IO */
-#define CQR_STATUS_DONE     0x04	/* request is completed sucessfully */
+#define CQR_STATUS_DONE     0x04	/* request is completed successfully */
 #define CQR_STATUS_ERROR    0x05	/* request is completed with error */
 #define CQR_STATUS_FAILED   0x06	/* request is finally failed */
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390/lowcore.h linux/include/asm-s390/lowcore.h
--- v2.4.2/linux/include/asm-s390/lowcore.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390/lowcore.h	Fri Mar  2 11:12:06 2001
@@ -124,7 +124,7 @@
         __u8         pad3[0xD8-0xC4];          /* 0x0c4 */
 	__u32        cpu_timer_save_area[2];   /* 0x0d8 */
 	__u32        clock_comp_save_area[2];  /* 0x0e0 */
-	__u32        mcck_interuption_code[2]; /* 0x0e8 */
+	__u32        mcck_interruption_code[2]; /* 0x0e8 */
 	__u8         pad4[0xf4-0xf0];          /* 0x0f0 */
 	__u32        external_damage_code;     /* 0x0f4 */
 	__u32        failing_storage_address;  /* 0x0f8 */
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/ccwcache.h linux/include/asm-s390x/ccwcache.h
--- v2.4.2/linux/include/asm-s390x/ccwcache.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390x/ccwcache.h	Fri Mar  2 11:12:06 2001
@@ -59,7 +59,7 @@
 #define CQR_STATUS_FILLED   0x01	/* request is ready to be preocessed */
 #define CQR_STATUS_QUEUED   0x02	/* request is queued to be processed */
 #define CQR_STATUS_IN_IO    0x03	/* request is currently in IO */
-#define CQR_STATUS_DONE     0x04	/* request is completed sucessfully */
+#define CQR_STATUS_DONE     0x04	/* request is completed successfully */
 #define CQR_STATUS_ERROR    0x05	/* request is completed with error */
 #define CQR_STATUS_FAILED   0x06	/* request is finally failed */
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h
--- v2.4.2/linux/include/asm-s390x/dasd.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390x/dasd.h	Fri Mar  2 11:12:06 2001
@@ -203,7 +203,7 @@
 typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
 typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
 
-typedef int (*dasd_ck_id_fn_t) (dev_info_t *);
+typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *);
 typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
 typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
 typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
@@ -269,7 +269,7 @@
 } dasd_profile_info_t;
 
 typedef struct dasd_device_t {
-	dev_info_t devinfo;
+	s390_dev_info_t devinfo;
 	dasd_discipline_t *discipline;
 	int level;
         int open_count;
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/lowcore.h linux/include/asm-s390x/lowcore.h
--- v2.4.2/linux/include/asm-s390x/lowcore.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390x/lowcore.h	Fri Mar  2 11:12:06 2001
@@ -116,7 +116,7 @@
 	__u8         pad3[0xc8-0xc4];          /* 0x0c4 */
 	__u32        stfl_fac_list;            /* 0x0c8 */
 	__u8         pad4[0xe8-0xcc];          /* 0x0cc */
-	__u32        mcck_interuption_code[2]; /* 0x0e8 */
+	__u32        mcck_interruption_code[2]; /* 0x0e8 */
 	__u8         pad5[0xf4-0xf0];          /* 0x0f0 */
 	__u32        external_damage_code;     /* 0x0f4 */
 	addr_t       failing_storage_address;  /* 0x0f8 */
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/socket.h linux/include/asm-s390x/socket.h
--- v2.4.2/linux/include/asm-s390x/socket.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390x/socket.h	Fri Mar  2 11:12:06 2001
@@ -50,6 +50,7 @@
 #define SO_PEERNAME		28
 #define SO_TIMESTAMP		29
 #define SCM_TIMESTAMP		SO_TIMESTAMP
+#define SO_ACCEPTCONN  		30
 
 /* Nast libc5 fixup - bletch */
 #if defined(__KERNEL__)
diff -u --recursive --new-file v2.4.2/linux/include/asm-s390x/unistd.h linux/include/asm-s390x/unistd.h
--- v2.4.2/linux/include/asm-s390x/unistd.h	Wed Feb 21 18:20:42 2001
+++ linux/include/asm-s390x/unistd.h	Fri Mar  2 11:12:06 2001
@@ -330,7 +330,6 @@
 static inline _syscall1(int,delete_module,const char *,name)
 static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf)
 
-extern int sys_wait4(int, int *, int, struct rusage *);
 static inline pid_t waitpid(int pid, int * wait_stat, int flags)
 {
         return sys_wait4(pid, wait_stat, flags, NULL);
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h
--- v2.4.2/linux/include/asm-sparc/smp.h	Tue Oct 10 10:33:52 2000
+++ linux/include/asm-sparc/smp.h	Fri Mar  2 11:30:15 2001
@@ -51,6 +51,7 @@
 extern int smp_found_cpus;
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
+#define cpu_online_map cpu_present_map
 
 typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
 		       unsigned long, unsigned long);
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/asi.h linux/include/asm-sparc64/asi.h
--- v2.4.2/linux/include/asm-sparc64/asi.h	Fri Dec 13 01:37:41 1996
+++ linux/include/asm-sparc64/asi.h	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: asi.h,v 1.1 1996/11/20 12:59:45 davem Exp $ */
+/* $Id: asi.h,v 1.2 2001/03/01 21:28:37 davem Exp $ */
 #ifndef _SPARC64_ASI_H
 #define _SPARC64_ASI_H
 
@@ -23,19 +23,35 @@
 #define ASI_PNFL		0x8a /* Primary, no fault, little endian	*/
 #define ASI_SNFL		0x8b /* Secondary, no fault, little endian	*/
 
-/* SpitFire extended ASIs. */
+/* SpitFire and later extended ASIs.  The "(III)" marker designates
+ * UltraSparc-III specific ASIs.
+ */
 #define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable			*/
 #define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-cachable, E-bit		*/
 #define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian	*/
 #define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-cachable, E-bit, little endian	*/
 #define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load			*/
 #define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, little endian 	*/
+#define ASI_PCACHE_DATA_STATUS	0x30 /* (III) PCache data status RAM diag	*/
+#define ASI_PCACHE_DATA		0x31 /* (III) PCache data RAM diag		*/
+#define ASI_PCACHE_TAG		0x32 /* (III) PCache tag RAM diag		*/
+#define ASI_PCACHE_SNOOP_TAG	0x33 /* (III) PCache snoop tag RAM diag		*/
+#define ASI_WCACHE_VALID_BITS	0x38 /* (III) WCache Valid Bits diag		*/
+#define ASI_WCACHE_DATA		0x39 /* (III) WCache data RAM diag		*/
+#define ASI_WCACHE_TAG		0x3a /* (III) WCache tag RAM diag		*/
+#define ASI_WCACHE_SNOOP_TAG	0x3b /* (III) WCache snoop tag RAM diag		*/
+#define ASI_DCACHE_INVALIDATE	0x42 /* (III) DCache Invalidate diag		*/
+#define ASI_DCACHE_UTAG		0x43 /* (III) DCache uTag diag			*/
+#define ASI_DCACHE_SNOOP_TAG	0x44 /* (III) DCache snoop tag RAM diag		*/
 #define ASI_LSU_CONTROL		0x45 /* Load-store control unit			*/
+#define ASI_DCU_CONTROL_REG	0x45 /* (III) DCache Unit Control Register	*/
 #define ASI_DCACHE_DATA		0x46 /* Data cache data-ram diag access		*/
 #define ASI_DCACHE_TAG		0x47 /* Data cache tag/valid ram diag access	*/
 #define ASI_INTR_DISPATCH_STAT	0x48 /* IRQ vector dispatch status		*/
 #define ASI_INTR_RECEIVE	0x49 /* IRQ vector receive status		*/
 #define ASI_UPA_CONFIG		0x4a /* UPA config space			*/
+#define ASI_SAFARI_CONFIG	0x4a /* (III) Safari Config Register		*/
+#define ASI_SAFARI_ADDRESS	0x4a /* (III) Safari Address Register		*/
 #define ASI_ESTATE_ERROR_EN	0x4b /* E-cache error enable space		*/
 #define ASI_AFSR		0x4c /* Async fault status register		*/
 #define ASI_AFAR		0x4d /* Async fault address register		*/
@@ -55,16 +71,23 @@
 #define ASI_DTLB_DATA_ACCESS	0x5d /* Data-MMU TLB data access register	*/
 #define ASI_DTLB_TAG_READ	0x5e /* Data-MMU TLB tag read register		*/
 #define ASI_DMMU_DEMAP		0x5f /* Data-MMU TLB demap			*/
+#define ASI_IIU_INST_TRAP	0x60 /* (III) Instruction Breakpoint register	*/
 #define ASI_IC_INSTR		0x66 /* Insn cache instrucion ram diag access	*/
 #define ASI_IC_TAG		0x67 /* Insn cache tag/valid ram diag access	*/
+#define ASI_IC_STAG		0x68 /* (III) Insn cache snoop tag ram diag	*/
 #define ASI_IC_PRE_DECODE	0x6e /* Insn cache pre-decode ram diag access	*/
 #define ASI_IC_NEXT_FIELD	0x6f /* Insn cache next-field ram diag access	*/
+#define ASI_BRPRED_ARRAY	0x6f /* (III) Branch Prediction RAM diag	*/
 #define ASI_BLK_AIUP		0x70 /* Primary, user, block load/store		*/
 #define ASI_BLK_AIUS		0x71 /* Secondary, user, block load/store	*/
+#define ASI_EC_DATA		0x74 /* (III) E-cache data staging register	*/
+#define ASI_EC_CTRL		0x75 /* (III) E-cache control register		*/
 #define ASI_EC_W		0x76 /* E-cache diag write access		*/
 #define ASI_UDB_ERROR_W		0x77 /* External UDB error registers write	*/
 #define ASI_UDB_CONTROL_W	0x77 /* External UDB control registers write	*/
 #define ASI_UDB_INTR_W		0x77 /* External UDB IRQ vector dispatch write	*/
+#define ASI_INTR_DATAN_W	0x77 /* (III) Outgoing irq vector data reg N	*/
+#define ASI_INTR_DISPATCH_W	0x77 /* (III) Interrupt vector dispatch		*/
 #define ASI_BLK_AIUPL		0x78 /* Primary, user, little, blk ld/st	*/
 #define ASI_BLK_AIUSL		0x79 /* Secondary, user, little, blk ld/st	*/
 #define ASI_EC_R		0x7e /* E-cache diag read access		*/
@@ -73,6 +96,7 @@
 #define ASI_UDBH_CONTROL_R	0x7f /* External UDB control registers read hi	*/
 #define ASI_UDBL_CONTROL_R	0x7f /* External UDB control registers read low	*/
 #define ASI_UDB_INTR_R		0x7f /* External UDB IRQ vector dispatch read	*/
+#define ASI_INTR_DATAN_R	0x7f /* (III) Incoming irq vector data reg N	*/
 #define ASI_PST8_P		0xc0 /* Primary, 8 8-bit, partial		*/
 #define ASI_PST8_S		0xc1 /* Secondary, 8 8-bit, partial		*/
 #define ASI_PST16_P		0xc2 /* Primary, 4 16-bit, partial		*/
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/dcr.h linux/include/asm-sparc64/dcr.h
--- v2.4.2/linux/include/asm-sparc64/dcr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/dcr.h	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,11 @@
+/* $Id: dcr.h,v 1.3 2001/03/01 23:23:33 davem Exp $ */
+#ifndef _SPARC64_DCR_H
+#define _SPARC64_DCR_H
+
+/* UltraSparc-III Dispatch Control Register, ASR 0x12 */
+#define DCR_BPE		0x0000000000000020 /* Branch Predict Enable		*/
+#define DCR_RPE		0x0000000000000010 /* Return Address Prediction Enable*/
+#define DCR_SI		0x0000000000000008 /* Single Instruction Disable	*/
+#define DCR_MS		0x0000000000000001 /* Multi-Scalar dispatch		*/
+
+#endif /* _SPARC64_DCR_H */
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/dcu.h linux/include/asm-sparc64/dcu.h
--- v2.4.2/linux/include/asm-sparc64/dcu.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/dcu.h	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,26 @@
+/* $Id: dcu.h,v 1.2 2001/03/01 23:23:33 davem Exp $ */
+#ifndef _SPARC64_DCU_H
+#define _SPARC64_DCU_H
+
+/* UltraSparc-III Data Cache Unit Control Register */
+#define DCU_CP		0x0002000000000000 /* Physical Cache Enable w/o mmu*/
+#define DCU_CV		0x0001000000000000 /* Virtual Cache Enable	w/o mmu	*/
+#define DCU_ME		0x0000800000000000 /* NC-store Merging Enable	*/
+#define DCU_RE		0x0000400000000000 /* RAW bypass Enable		*/
+#define DCU_PE		0x0000200000000000 /* PCache Enable		*/
+#define DCU_HPE		0x0000100000000000 /* HW prefetch Enable		*/
+#define DCU_SPE		0x0000080000000000 /* SW prefetch Enable		*/
+#define DCU_SL		0x0000040000000000 /* Secondary load steering Enab	*/
+#define DCU_WE		0x0000020000000000 /* WCache enable		*/
+#define DCU_PM		0x000001fe00000000 /* PA Watchpoint Byte Mask	*/
+#define DCU_VM		0x00000001fe000000 /* VA Watchpoint Byte Mask	*/
+#define DCU_PR		0x0000000001000000 /* PA Watchpoint Read Enable	*/
+#define DCU_PW		0x0000000000800000 /* PA Watchpoint Write Enable	*/
+#define DCU_VR		0x0000000000400000 /* VA Watchpoint Read Enable	*/
+#define DCU_VW		0x0000000000200000 /* VA Watchpoint Write Enable	*/
+#define DCU_DM		0x0000000000000008 /* DMMU Enable			*/
+#define DCU_IM		0x0000000000000004 /* IMMU Enable			*/
+#define DCU_DC		0x0000000000000002 /* Data Cache Enable		*/
+#define DCU_IC		0x0000000000000001 /* Instruction Cache Enable	*/
+
+#endif /* _SPARC64_DCU_H */
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h
--- v2.4.2/linux/include/asm-sparc64/pbm.h	Sat Feb  3 19:51:32 2001
+++ linux/include/asm-sparc64/pbm.h	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.23 2001/01/11 16:26:45 davem Exp $
+/* $Id: pbm.h,v 1.25 2001/02/28 03:28:55 davem Exp $
  * pbm.h: UltraSparc PCI controller software state.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -144,6 +144,9 @@
 	struct resource			io_space;
 	struct resource			mem_space;
 
+	/* Base of PCI Config space, can be per-PBM or shared. */
+	unsigned long			config_space;
+
 	/* State of 66MHz capabilities on this PBM. */
 	int				is_66mhz_capable;
 	int				all_devs_66mhz;
@@ -164,11 +167,8 @@
 	/* List of all PCI controllers. */
 	struct pci_controller_info	*next;
 
-	/* Physical address base of controller registers
-	 * and PCI config space.
-	 */
+	/* Physical address base of controller registers. */
 	unsigned long			controller_regs;
-	unsigned long			config_space;
 
 	/* Opaque 32-bit system bus Port ID. */
 	u32				portid;
@@ -184,7 +184,7 @@
 
 	/* Operations which are controller specific. */
 	void (*scan_bus)(struct pci_controller_info *);
-	unsigned int (*irq_build)(struct pci_controller_info *, struct pci_dev *, unsigned int);
+	unsigned int (*irq_build)(struct pci_pbm_info *, struct pci_dev *, unsigned int);
 	void (*base_address_update)(struct pci_dev *, int);
 	void (*resource_adjust)(struct pci_dev *, struct resource *, struct resource *);
 
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.4.2/linux/include/asm-sparc64/pgalloc.h	Mon Dec 11 12:37:03 2000
+++ linux/include/asm-sparc64/pgalloc.h	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.14 2000/12/09 04:15:24 anton Exp $ */
+/* $Id: pgalloc.h,v 1.15 2001/03/04 18:31:00 davem Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
@@ -93,14 +93,14 @@
 
 #endif /* ! CONFIG_SMP */
 
-/* This will change for Cheetah and later chips. */
-#define VPTE_BASE	0xfffffffe00000000
+#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
+#define VPTE_BASE_CHEETAH	0xffe0000000000000
 
 extern __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start,
 					  unsigned long end)
 {
 	/* Note the signed type.  */
-	long s = start, e = end;
+	long s = start, e = end, vpte_base;
 	if (s > e)
 		/* Nobody should call us with start below VM hole and end above.
 		   See if it is really true.  */
@@ -110,9 +110,12 @@
 	s &= PMD_MASK;
 	e = (e + PMD_SIZE - 1) & PMD_MASK;
 #endif
+	vpte_base = (tlb_type == spitfire ?
+		     VPTE_BASE_SPITFIRE :
+		     VPTE_BASE_CHEETAH);
 	flush_tlb_range(mm,
-			VPTE_BASE + (s >> (PAGE_SHIFT - 3)),
-			VPTE_BASE + (e >> (PAGE_SHIFT - 3)));
+			vpte_base + (s >> (PAGE_SHIFT - 3)),
+			vpte_base + (e >> (PAGE_SHIFT - 3)));
 }
 
 /* Page table allocation/freeing. */
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.4.2/linux/include/asm-sparc64/pgtable.h	Thu Nov  9 15:57:41 2000
+++ linux/include/asm-sparc64/pgtable.h	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.135 2000/11/08 04:49:24 davem Exp $
+/* $Id: pgtable.h,v 1.137 2001/03/02 03:12:01 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -70,7 +70,7 @@
 
 #endif /* !(__ASSEMBLY__) */
 
-/* SpitFire TTE bits. */
+/* Spitfire/Cheetah TTE bits. */
 #define _PAGE_VALID	0x8000000000000000	/* Valid TTE                          */
 #define _PAGE_R		0x8000000000000000	/* Used to keep ref bit up to date    */
 #define _PAGE_SZ4MB	0x6000000000000000	/* 4MB Page                           */
@@ -79,10 +79,10 @@
 #define _PAGE_SZ8K	0x0000000000000000	/* 8K Page                            */
 #define _PAGE_NFO	0x1000000000000000	/* No Fault Only                      */
 #define _PAGE_IE	0x0800000000000000	/* Invert Endianness                  */
-#define _PAGE_SOFT2	0x07FC000000000000	/* Second set of software bits        */
-#define _PAGE_DIAG	0x0003FE0000000000	/* Diagnostic TTE bits                */
-#define _PAGE_PADDR	0x000001FFFFFFE000	/* Physical Address bits [40:13]      */
-#define _PAGE_SOFT	0x0000000000001F80	/* First set of software bits         */
+#define _PAGE_SN	0x0000800000000000	/* Snoop                              */
+#define _PAGE_PADDR_SF	0x000001FFFFFFE000	/* (Spitfire) Phys Address [40:13]    */
+#define _PAGE_PADDR	0x000007FFFFFFE000	/* (Cheetah) Phys Address [42:13]     */
+#define _PAGE_SOFT	0x0000000000001F80	/* Software bits                      */
 #define _PAGE_L		0x0000000000000040	/* Locked TTE                         */
 #define _PAGE_CP	0x0000000000000020	/* Cacheable in Physical Cache        */
 #define _PAGE_CV	0x0000000000000010	/* Cacheable in Virtual Cache         */
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.4.2/linux/include/asm-sparc64/smp.h	Tue Oct  3 09:24:41 2000
+++ linux/include/asm-sparc64/smp.h	Fri Mar  2 11:30:15 2001
@@ -60,6 +60,7 @@
  
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
+#define cpu_online_map cpu_present_map
 
 /*
  *	General functions that each host system must provide.
diff -u --recursive --new-file v2.4.2/linux/include/asm-sparc64/spitfire.h linux/include/asm-sparc64/spitfire.h
--- v2.4.2/linux/include/asm-sparc64/spitfire.h	Tue Oct 10 10:33:52 2000
+++ linux/include/asm-sparc64/spitfire.h	Tue Mar  6 22:44:16 2001
@@ -1,4 +1,4 @@
-/* $Id: spitfire.h,v 1.10 2000/10/06 13:10:29 anton Exp $
+/* $Id: spitfire.h,v 1.11 2001/03/03 10:34:45 davem Exp $
  * spitfire.h: SpitFire/BlackBird/Cheetah inline MMU operations.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -29,6 +29,21 @@
 
 #ifndef __ASSEMBLY__
 
+enum ultra_tlb_layout {
+	spitfire = 0,
+	cheetah = 1
+};
+
+extern enum ultra_tlb_layout tlb_type;
+
+#define SPITFIRE_HIGHEST_LOCKED_TLBENT	(64 - 1)
+#define CHEETAH_HIGHEST_LOCKED_TLBENT	(16 - 1)
+
+#define sparc64_highest_locked_tlbent()	\
+	(tlb_type == spitfire ? \
+	 SPITFIRE_HIGHEST_LOCKED_TLBENT : \
+	 CHEETAH_HIGHEST_LOCKED_TLBENT)
+
 extern __inline__ unsigned long spitfire_get_isfsr(void)
 {
 	unsigned long ret;
@@ -140,6 +155,10 @@
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" (entry << 3), "i" (ASI_DTLB_DATA_ACCESS));
+
+	/* Clear TTE diag bits. */
+	data &= ~0x0003fe0000000000UL;
+
 	return data;
 }
 
@@ -168,6 +187,10 @@
 	__asm__ __volatile__("ldxa	[%1] %2, %0"
 			     : "=r" (data)
 			     : "r" (entry << 3), "i" (ASI_ITLB_DATA_ACCESS));
+
+	/* Clear TTE diag bits. */
+	data &= ~0x0003fe0000000000UL;
+
 	return data;
 }
 
@@ -275,6 +298,157 @@
 	__asm__ __volatile__("stxa	%%g0, [%0] %1"
 			     : /* No outputs */
 			     : "r" (page | 0x20), "i" (ASI_IMMU_DEMAP));
+}
+
+/* Cheetah has "all non-locked" tlb flushes. */
+extern __inline__ void cheetah_flush_dtlb_all(void)
+{
+	__asm__ __volatile__("stxa	%%g0, [%0] %1"
+			     : /* No outputs */
+			     : "r" (0x80), "i" (ASI_DMMU_DEMAP));
+}
+
+extern __inline__ void cheetah_flush_itlb_all(void)
+{
+	__asm__ __volatile__("stxa	%%g0, [%0] %1"
+			     : /* No outputs */
+			     : "r" (0x80), "i" (ASI_IMMU_DEMAP));
+}
+
+/* Cheetah has a 4-tlb layout so direct access is a bit different.
+ * The first two TLBs are fully assosciative, hold 16 entries, and are
+ * used only for locked and >8K sized translations.  One exists for
+ * data accesses and one for instruction accesses.
+ *
+ * The third TLB is for data accesses to 8K non-locked translations, is
+ * 2 way assosciative, and holds 512 entries.  The fourth TLB is for
+ * instruction accesses to 8K non-locked translations, is 2 way
+ * assosciative, and holds 128 entries.
+ */
+extern __inline__ unsigned long cheetah_get_ldtlb_data(int entry)
+{
+	unsigned long data;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (data)
+			     : "r" ((0 << 16) | (entry << 3)),
+			     "i" (ASI_DTLB_DATA_ACCESS));
+
+	return data;
+}
+
+extern __inline__ unsigned long cheetah_get_litlb_data(int entry)
+{
+	unsigned long data;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (data)
+			     : "r" ((0 << 16) | (entry << 3)),
+			     "i" (ASI_ITLB_DATA_ACCESS));
+
+	return data;
+}
+
+extern __inline__ unsigned long cheetah_get_ldtlb_tag(int entry)
+{
+	unsigned long tag;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (tag)
+			     : "r" ((0 << 16) | (entry << 3)),
+			     "i" (ASI_DTLB_TAG_READ));
+
+	return tag;
+}
+
+extern __inline__ unsigned long cheetah_get_litlb_tag(int entry)
+{
+	unsigned long tag;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (tag)
+			     : "r" ((0 << 16) | (entry << 3)),
+			     "i" (ASI_ITLB_TAG_READ));
+
+	return tag;
+}
+
+extern __inline__ void cheetah_put_ldtlb_data(int entry, unsigned long data)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2"
+			     : /* No outputs */
+			     : "r" (data),
+			       "r" ((0 << 16) | (entry << 3)),
+			       "i" (ASI_DTLB_DATA_ACCESS));
+}
+
+extern __inline__ void cheetah_put_litlb_data(int entry, unsigned long data)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2"
+			     : /* No outputs */
+			     : "r" (data),
+			       "r" ((0 << 16) | (entry << 3)),
+			       "i" (ASI_ITLB_DATA_ACCESS));
+}
+
+extern __inline__ unsigned long cheetah_get_dtlb_data(int entry)
+{
+	unsigned long data;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (data)
+			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
+
+	return data;
+}
+
+extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry)
+{
+	unsigned long tag;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (tag)
+			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
+	return tag;
+}
+
+extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2"
+			     : /* No outputs */
+			     : "r" (data),
+			       "r" ((2 << 16) | (entry << 3)),
+			       "i" (ASI_DTLB_DATA_ACCESS));
+}
+
+extern __inline__ unsigned long cheetah_get_itlb_data(int entry)
+{
+	unsigned long data;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (data)
+			     : "r" ((2 << 16) | (entry << 3)),
+                               "i" (ASI_ITLB_DATA_ACCESS));
+
+	return data;
+}
+
+extern __inline__ unsigned long cheetah_get_itlb_tag(int entry)
+{
+	unsigned long tag;
+
+	__asm__ __volatile__("ldxa	[%1] %2, %0"
+			     : "=r" (tag)
+			     : "r" ((2 << 16) | (entry << 3)), "i" (ASI_ITLB_TAG_READ));
+	return tag;
+}
+
+extern __inline__ void cheetah_put_itlb_data(int entry, unsigned long data)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2"
+			     : /* No outputs */
+			     : "r" (data), "r" ((2 << 16) | (entry << 3)),
+			       "i" (ASI_ITLB_DATA_ACCESS));
 }
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.4.2/linux/include/linux/802_11.h linux/include/linux/802_11.h
--- v2.4.2/linux/include/linux/802_11.h	Mon Dec 11 13:00:51 2000
+++ linux/include/linux/802_11.h	Tue Mar  6 19:28:33 2001
@@ -188,4 +188,4 @@
 }
 
 
-#endif
\ No newline at end of file
+#endif
diff -u --recursive --new-file v2.4.2/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.4.2/linux/include/linux/blkdev.h	Sat Feb  3 19:51:32 2001
+++ linux/include/linux/blkdev.h	Fri Mar 23 18:23:15 2001
@@ -180,7 +180,7 @@
 extern atomic_t queued_sectors;
 
 #define MAX_SEGMENTS 128
-#define MAX_SECTORS (MAX_SEGMENTS*8)
+#define MAX_SECTORS 255
 
 #define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK)
 
diff -u --recursive --new-file v2.4.2/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v2.4.2/linux/include/linux/cdrom.h	Thu Jan  4 14:50:47 2001
+++ linux/include/linux/cdrom.h	Fri Mar 23 18:23:08 2001
@@ -524,10 +524,12 @@
 	__u32 end_sector_l0;
 };
 
+#define DVD_LAYERS	4
+
 struct dvd_physical {
 	__u8 type;
 	__u8 layer_num;
-	struct dvd_layer layer[4];
+	struct dvd_layer layer[DVD_LAYERS];
 };
 
 struct dvd_copyright {
diff -u --recursive --new-file v2.4.2/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.4.2/linux/include/linux/dcache.h	Wed Feb 21 18:20:45 2001
+++ linux/include/linux/dcache.h	Fri Mar 23 18:23:07 2001
@@ -217,7 +217,7 @@
 extern struct dentry * d_lookup(struct dentry *, struct qstr *);
 
 /* validate "insecure" dentry pointer */
-extern int d_validate(struct dentry *, struct dentry *, unsigned int, unsigned int);
+extern int d_validate(struct dentry *, struct dentry *);
 
 extern char * __d_path(struct dentry *, struct vfsmount *, struct dentry *,
 	struct vfsmount *, char *, int);
diff -u --recursive --new-file v2.4.2/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h
--- v2.4.2/linux/include/linux/etherdevice.h	Fri Oct 27 12:22:34 2000
+++ linux/include/linux/etherdevice.h	Thu Mar 22 09:09:32 2001
@@ -45,6 +45,14 @@
 	memcpy (dest->data, src, len);
 }
 
+/* Check that the ethernet address (MAC) is not 00:00:00:00:00:00 and is not
+ * a multicast address.  Return true if the address is valid.
+ */
+static __inline__ int is_valid_ether_addr( u8 *addr )
+{
+	return !(addr[0]&1) && memcmp( addr, "\0\0\0\0\0\0", 6);
+}
+
 #endif
 
 #endif	/* _LINUX_ETHERDEVICE_H */
diff -u --recursive --new-file v2.4.2/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.2/linux/include/linux/fs.h	Wed Feb 21 18:20:45 2001
+++ linux/include/linux/fs.h	Fri Mar 23 18:23:08 2001
@@ -244,7 +244,7 @@
 	struct buffer_head *b_reqnext;	/* request queue */
 
 	struct buffer_head **b_pprev;	/* doubly linked list of hash-queue */
-	char * b_data;			/* pointer to data block (512 byte) */
+	char * b_data;			/* pointer to data block */
 	struct page *b_page;		/* the page this bh is mapped to */
 	void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
  	void *b_private;		/* reserved for b_end_io */
@@ -381,6 +381,7 @@
 	struct vm_area_struct	*i_mmap;	/* list of private mappings */
 	struct vm_area_struct	*i_mmap_shared; /* list of shared mappings */
 	spinlock_t		i_shared_lock;  /* and spinlock protecting it */
+	int			gfp_mask;	/* how to allocate the pages */
 };
 
 struct block_device {
@@ -504,6 +505,8 @@
 
 extern int init_private_file(struct file *, struct dentry *, int);
 
+#define	MAX_NON_LFS	((1UL<<31) - 1)
+
 #define FL_POSIX	1
 #define FL_FLOCK	2
 #define FL_BROKEN	4	/* broken flock() emulation */
@@ -651,6 +654,7 @@
 	unsigned char		s_blocksize_bits;
 	unsigned char		s_lock;
 	unsigned char		s_dirt;
+	unsigned long long	s_maxbytes;	/* Max file size */
 	struct file_system_type	*s_type;
 	struct super_operations	*s_op;
 	struct dquot_operations	*dq_op;
diff -u --recursive --new-file v2.4.2/linux/include/linux/fs_struct.h linux/include/linux/fs_struct.h
--- v2.4.2/linux/include/linux/fs_struct.h	Wed Jul  5 11:31:00 2000
+++ linux/include/linux/fs_struct.h	Thu Mar 15 09:56:07 2001
@@ -13,7 +13,7 @@
 #define INIT_FS { \
 	ATOMIC_INIT(1), \
 	RW_LOCK_UNLOCKED, \
-	0022, \
+	0000, \
 	NULL, NULL, NULL, NULL, NULL, NULL \
 }
 
diff -u --recursive --new-file v2.4.2/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v2.4.2/linux/include/linux/genhd.h	Thu Jan  4 14:50:47 2001
+++ linux/include/linux/genhd.h	Fri Mar 23 18:23:08 2001
@@ -223,6 +223,11 @@
 
 #endif /* CONFIG_UNIXWARE_DISKLABEL */
 
+#ifdef CONFIG_MINIX_SUBPARTITION
+#   define MINIX_PARTITION         0x81  /* Minix Partition ID */
+#   define MINIX_NR_SUBPARTITIONS  4
+#endif /* CONFIG_MINIX_SUBPARTITION */
+
 #ifdef __KERNEL__
 extern struct gendisk *gendisk_head;	/* linked list of disks */
 
diff -u --recursive --new-file v2.4.2/linux/include/linux/hdlc.h linux/include/linux/hdlc.h
--- v2.4.2/linux/include/linux/hdlc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/hdlc.h	Tue Mar  6 19:44:37 2001
@@ -0,0 +1,336 @@
+/*
+ * Generic HDLC support routines for Linux
+ *
+ * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ */
+
+#ifndef __HDLC_H
+#define __HDLC_H
+
+/* Ioctls - to be changed */
+#define HDLCGSLOTMAP	(0x89F4) /* E1/T1 slot bitmap */
+#define HDLCGCLOCK	(0x89F5) /* clock sources */
+#define HDLCGCLOCKRATE	(0x89F6) /* clock rate */
+#define HDLCGMODE	(0x89F7) /* internal to hdlc.c - protocol used */
+#define HDLCGLINE	(0x89F8) /* physical interface */
+#define HDLCSSLOTMAP	(0x89F9)
+#define HDLCSCLOCK	(0x89FA)
+#define HDLCSCLOCKRATE	(0x89FB)
+#define HDLCSMODE	(0x89FC) /* internal to hdlc.c - select protocol */
+#define HDLCPVC		(0x89FD) /* internal to hdlc.c - create/delete PVC */
+#define HDLCSLINE	(0x89FE)
+#define HDLCRUN		(0x89FF) /* Download firmware and run board */
+
+/* Modes */
+#define MODE_NONE	0x00000000 /* Not initialized */
+#define MODE_DCE	0x00000080 /* DCE */
+#define MODE_HDLC	0x00000100 /* Raw HDLC frames */
+#define MODE_CISCO	0x00000200
+#define MODE_PPP	0x00000400
+#define MODE_FR		0x00000800 /* Any LMI */
+#define MODE_FR_ANSI	0x00000801
+#define MODE_FR_CCITT	0x00000802
+#define MODE_X25	0x00001000
+#define MODE_MASK	0x0000FF00
+#define MODE_SOFT	0x80000000 /* Driver modes, using hardware HDLC */
+
+/* Lines */
+#define LINE_DEFAULT	0x00000000
+#define LINE_V35	0x00000001
+#define LINE_RS232	0x00000002
+#define LINE_X21	0x00000003
+#define LINE_T1		0x00000004
+#define LINE_E1		0x00000005
+#define LINE_MASK	0x000000FF
+#define LINE_LOOPBACK	0x80000000 /* On-card loopback */
+
+#define CLOCK_EXT	0	/* External TX and RX clock - DTE */
+#define CLOCK_INT	1	/* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT	2	/* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX	3	/* TX clock derived from external RX clock */
+
+
+#define HDLC_MAX_MTU 1500	/* Ethernet 1500 bytes */
+#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
+
+#ifdef __KERNEL__
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/syncppp.h>
+
+#define MAXLEN_LMISTAT  20	/* max size of status enquiry frame */
+
+#define LINK_STATE_RELIABLE 0x01
+#define LINK_STATE_REQUEST  0x02 /* full stat sent (DCE) / req pending (DTE) */
+#define LINK_STATE_CHANGED  0x04 /* change in PVCs state, send full report */
+#define LINK_STATE_FULLREP_SENT 0x08 /* full report sent */
+
+#define PVC_STATE_NEW       0x01
+#define PVC_STATE_ACTIVE    0x02
+#define PVC_STATE_FECN	    0x08 /* FECN condition */
+#define PVC_STATE_BECN      0x10 /* BECN condition */
+
+
+#define FR_UI              0x03
+#define FR_PAD             0x00
+
+#define NLPID_IP           0xCC
+#define NLPID_IPV6         0x8E
+#define NLPID_SNAP         0x80
+#define NLPID_PAD          0x00
+#define NLPID_Q933         0x08
+
+
+#define LMI_DLCI                   0 /* LMI DLCI */
+#define LMI_PROTO               0x08
+#define LMI_CALLREF             0x00 /* Call Reference */
+#define LMI_ANSI_LOCKSHIFT      0x95 /* ANSI lockshift */
+#define LMI_REPTYPE                1 /* report type */
+#define LMI_CCITT_REPTYPE       0x51
+#define LMI_ALIVE                  3 /* keep alive */
+#define LMI_CCITT_ALIVE         0x53
+#define LMI_PVCSTAT                7 /* pvc status */
+#define LMI_CCITT_PVCSTAT       0x57
+#define LMI_FULLREP                0 /* full report  */
+#define LMI_INTEGRITY              1 /* link integrity report */
+#define LMI_SINGLE                 2 /* single pvc report */
+#define LMI_STATUS_ENQUIRY      0x75
+#define LMI_STATUS              0x7D /* reply */
+
+#define LMI_REPT_LEN               1 /* report type element length */
+#define LMI_INTEG_LEN              2 /* link integrity element length */
+
+#define LMI_LENGTH                13 /* standard LMI frame length */
+#define LMI_ANSI_LENGTH           14
+
+
+
+typedef struct {
+	unsigned ea1  : 1;
+	unsigned cr   : 1;
+	unsigned dlcih: 6;
+  
+	unsigned ea2  : 1;
+	unsigned de   : 1;
+	unsigned becn : 1;
+	unsigned fecn : 1;
+	unsigned dlcil: 4;
+}__attribute__ ((packed)) fr_hdr;
+
+
+
+typedef struct {		/* Used in Cisco and PPP mode */
+	u8 address;
+	u8 control;
+	u16 protocol;
+}__attribute__ ((packed)) hdlc_header;
+
+
+
+typedef struct {
+	u32 type;		/* code */
+	u32 par1;
+	u32 par2;
+	u16 rel;		/* reliability */
+	u32 time;
+}__attribute__ ((packed)) cisco_packet;
+#define	CISCO_PACKET_LEN	18
+#define	CISCO_BIG_PACKET_LEN	20
+
+
+
+typedef struct pvc_device_struct {
+	struct net_device netdev; /* PVC net device - must be first */
+	struct net_device_stats stats;
+	struct hdlc_device_struct *master;
+	struct pvc_device_struct *next;
+
+	u8 state;
+	u8 newstate;
+}pvc_device;
+
+
+
+typedef struct {
+	u32 last_errors;	/* last errors bit list */
+	int last_poll;		/* ! */
+	u8 T391;		/* ! link integrity verification polling timer */
+	u8 T392;		/* ! polling verification timer */
+	u8 N391;		/* full status polling counter */
+	u8 N392;		/* error threshold */
+	u8 N393;		/* monitored events count */
+	u8 N391cnt;
+
+	u8 state;		/* ! */
+	u32 txseq;		/* ! TX sequence number - Cisco uses 4 bytes */
+	u32 rxseq;		/* ! RX sequence number */
+}fr_lmi;			/* ! means used in Cisco HDLC as well */
+
+
+typedef struct hdlc_device_struct {
+	/* to be initialized by hardware driver: */
+	struct net_device netdev; /* master net device - must be first */
+	struct net_device_stats stats;
+
+	struct ppp_device pppdev;
+	struct ppp_device *syncppp_ptr;
+
+	/* set_mode may be NULL if HDLC-only board */
+	int (*set_mode)(struct hdlc_device_struct *hdlc, int mode);
+	int (*open)(struct hdlc_device_struct *hdlc);
+	void (*close)(struct hdlc_device_struct *hdlc);
+	int (*xmit)(struct hdlc_device_struct *hdlc, struct sk_buff *skb);
+	int (*ioctl)(struct hdlc_device_struct *hdlc, struct ifreq *ifr,
+		     int cmd);
+  
+	/* Only in "hardware" FR modes etc. - may be NULL */
+	int (*create_pvc)(pvc_device *pvc);
+	void (*destroy_pvc)(pvc_device *pvc);
+	int (*open_pvc)(pvc_device *pvc);
+	void (*close_pvc)(pvc_device *pvc);
+
+	/* for hdlc.c internal use only */
+	pvc_device *first_pvc;
+	u16 pvc_count;
+	int mode;
+
+	struct timer_list timer;
+	fr_lmi lmi;
+}hdlc_device;
+
+
+int register_hdlc_device(hdlc_device *hdlc);
+void unregister_hdlc_device(hdlc_device *hdlc);
+void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
+
+
+extern __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
+{
+	return &hdlc->netdev;
+}
+
+
+extern __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+{
+	return (hdlc_device*)dev;
+}
+
+
+extern __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
+{
+	return &pvc->netdev;
+}
+
+
+extern __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+{
+	return (pvc_device*)dev;
+}
+
+
+extern __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
+{
+	return hdlc_to_dev(hdlc)->name;
+}
+
+
+extern __inline__ const char *pvc_to_name(pvc_device *pvc)
+{
+	return pvc_to_dev(pvc)->name;
+}
+
+
+extern __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
+{
+	*state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
+	if (status[2] & 0x08)
+		*state |= PVC_STATE_NEW;
+	else if (status[2] & 0x02)
+		*state |= PVC_STATE_ACTIVE;
+
+	return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
+}
+
+
+extern __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+				      u8 state)
+{
+	status[0] = (dlci>>4) & 0x3F;
+	status[1] = ((dlci<<3) & 0x78) | 0x80;
+	status[2] = 0x80;
+
+	if (state & PVC_STATE_NEW)
+		status[2] |= 0x08;
+	else if (state & PVC_STATE_ACTIVE)
+		status[2] |= 0x02;
+}
+
+
+
+extern __inline__ u16 netdev_dlci(struct net_device *dev)
+{
+	return ntohs(*(u16*)dev->dev_addr);
+}
+
+
+
+extern __inline__ u16 q922_to_dlci(u8 *hdr)
+{
+	return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
+}
+
+
+
+extern __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
+{
+	hdr[0] = (dlci>>2) & 0xFC;
+	hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
+}
+
+
+
+extern __inline__ int mode_is(hdlc_device *hdlc, int mask)
+{
+	return (hdlc->mode & mask) == mask;
+}
+
+
+
+extern __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+{
+	pvc_device *pvc=hdlc->first_pvc;
+	
+	while (pvc) {
+		if (netdev_dlci(&pvc->netdev) == dlci)
+			return pvc;
+		pvc=pvc->next;
+	}
+
+	return NULL;
+}
+
+
+
+extern __inline__ void debug_frame(const struct sk_buff *skb)
+{
+	int i;
+
+	for (i=0; i<skb->len; i++) {
+		if (i == 100) {
+			printk("...\n");
+			return;
+		}
+		printk(" %02X", skb->data[i]);
+	}
+	printk("\n");
+}
+
+
+#endif /* __KERNEL */
+#endif /* __HDLC_H */
diff -u --recursive --new-file v2.4.2/linux/include/linux/hysdn_if.h linux/include/linux/hysdn_if.h
--- v2.4.2/linux/include/linux/hysdn_if.h	Tue Feb 15 11:40:43 2000
+++ linux/include/linux/hysdn_if.h	Tue Mar  6 19:44:37 2001
@@ -30,7 +30,7 @@
 /****************/
 /* error values */
 /****************/
-#define ERR_NONE             0 /* no error occured */
+#define ERR_NONE             0 /* no error occurred */
 #define ERR_ALREADY_BOOT  1000 /* we are already booting */
 #define EPOF_BAD_MAGIC    1001 /* bad magic in POF header */
 #define ERR_BOARD_DPRAM   1002 /* board DPRAM failed */
diff -u --recursive --new-file v2.4.2/linux/include/linux/i2c.h linux/include/linux/i2c.h
--- v2.4.2/linux/include/linux/i2c.h	Fri Dec 29 14:35:47 2000
+++ linux/include/linux/i2c.h	Tue Mar  6 19:44:37 2001
@@ -454,7 +454,7 @@
  *	corresponding header files.
  */
 				/* -> bit-adapter specific ioctls	*/
-#define I2C_RETRIES	0x0701	/* number times a device adress should	*/
+#define I2C_RETRIES	0x0701	/* number times a device address should	*/
 				/* be polled when not acknowledging 	*/
 #define I2C_TIMEOUT	0x0702	/* set timeout - call with int 		*/
 
@@ -471,7 +471,7 @@
 #define I2C_FUNCS	0x0705	/* Get the adapter functionality */
 #define I2C_RDWR	0x0707	/* Combined R/W transfer (one stop only)*/
 #if 0
-#define I2C_ACK_TEST	0x0710	/* See if a slave is at a specific adress */
+#define I2C_ACK_TEST	0x0710	/* See if a slave is at a specific address */
 #endif
 
 #define I2C_SMBUS	0x0720	/* SMBus-level access */
diff -u --recursive --new-file v2.4.2/linux/include/linux/if_bonding.h linux/include/linux/if_bonding.h
--- v2.4.2/linux/include/linux/if_bonding.h	Sun Feb 27 18:45:10 2000
+++ linux/include/linux/if_bonding.h	Tue Mar  6 19:44:37 2001
@@ -9,7 +9,7 @@
  * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov
  *
  *	This software may be used and distributed according to the terms
- *	of the GNU Public License, incorporated herein by reference.
+ *	of the GNU General Public License, incorporated herein by reference.
  * 
  */
 
diff -u --recursive --new-file v2.4.2/linux/include/linux/if_eql.h linux/include/linux/if_eql.h
--- v2.4.2/linux/include/linux/if_eql.h	Mon Dec 11 13:02:12 2000
+++ linux/include/linux/if_eql.h	Tue Mar  6 19:44:37 2001
@@ -6,7 +6,7 @@
  *
  *
  *	This software may be used and distributed according to the terms
- *	of the GNU Public License, incorporated herein by reference.
+ *	of the GNU General Public License, incorporated herein by reference.
  * 
  * The author may be reached as simon@ncm.com, or C/O
  *    NCM
diff -u --recursive --new-file v2.4.2/linux/include/linux/if_frad.h linux/include/linux/if_frad.h
--- v2.4.2/linux/include/linux/if_frad.h	Mon Dec 11 13:00:06 2000
+++ linux/include/linux/if_frad.h	Tue Mar  6 19:28:33 2001
@@ -192,9 +192,9 @@
 int register_frad(const char *name);
 int unregister_frad(const char *name);
 
-int (*dlci_ioctl_hook)(unsigned int, void *);
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
 
-#endif __KERNEL__
+#endif /* __KERNEL__ */
 
 #endif /* CONFIG_DLCI || CONFIG_DLCI_MODULE */
 
diff -u --recursive --new-file v2.4.2/linux/include/linux/init.h linux/include/linux/init.h
--- v2.4.2/linux/include/linux/init.h	Thu Jan  4 14:50:46 2001
+++ linux/include/linux/init.h	Fri Mar 23 18:23:07 2001
@@ -86,7 +86,27 @@
 #define __FINIT		.previous
 #define __INITDATA	.section	".data.init","aw"
 
+/**
+ * module_init() - driver initialization entry point
+ * @x: function to be run at kernel boot time or module insertion
+ * 
+ * module_init() will add the driver initialization routine in
+ * the "__initcall.int" code segment if the driver is checked as
+ * "y" or static, or else it will wrap the driver initialization
+ * routine with init_module() which is used by insmod and
+ * modprobe when the driver is used as a module.
+ */
 #define module_init(x)	__initcall(x);
+
+/**
+ * module_exit() - driver exit entry point
+ * @x: function to be run when driver is removed
+ * 
+ * module_exit() will wrap the driver clean-up code
+ * with cleanup_module() when used with rmmod when
+ * the driver is a module.  If the driver is statically
+ * compiled into the kernel, module_exit() has no effect.
+ */
 #define module_exit(x)	__exitcall(x);
 
 #else
diff -u --recursive --new-file v2.4.2/linux/include/linux/loop.h linux/include/linux/loop.h
--- v2.4.2/linux/include/linux/loop.h	Mon Dec 11 12:50:30 2000
+++ linux/include/linux/loop.h	Tue Mar  6 19:35:36 2001
@@ -9,17 +9,23 @@
  * Written by Theodore Ts'o, 3/29/93.
  *
  * Copyright 1993 by Theodore Ts'o.  Redistribution of this file is
- * permitted under the GNU Public License.
+ * permitted under the GNU General Public License.
  */
 
 #define LO_NAME_SIZE	64
 #define LO_KEY_SIZE	32
 
 #ifdef __KERNEL__
-       
+
+/* Possible states of device */
+enum {
+	Lo_unbound,
+	Lo_bound,
+	Lo_rundown,
+};
+
 struct loop_device {
 	int		lo_number;
-	struct dentry	*lo_dentry;
 	int		lo_refcnt;
 	kdev_t		lo_device;
 	int		lo_offset;
@@ -39,19 +45,38 @@
 	struct file *	lo_backing_file;
 	void		*key_data; 
 	char		key_reserved[48]; /* for use by the filter modules */
+
+	int		old_gfp_mask;
+
+	spinlock_t		lo_lock;
+	struct buffer_head	*lo_bh;
+	struct buffer_head	*lo_bhtail;
+	int			lo_state;
+	struct semaphore	lo_sem;
+	struct semaphore	lo_ctl_mutex;
+	struct semaphore	lo_bh_mutex;
+	atomic_t		lo_pending;
 };
 
 typedef	int (* transfer_proc_t)(struct loop_device *, int cmd,
 				char *raw_buf, char *loop_buf, int size,
 				int real_block);
 
+extern inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
+				 char *lbuf, int size, int rblock)
+{
+	if (!lo->transfer)
+		return 0;
+
+	return lo->transfer(lo, cmd, rbuf, lbuf, size, rblock);
+}
 #endif /* __KERNEL__ */
 
 /*
  * Loop flags
  */
-#define LO_FLAGS_DO_BMAP	0x00000001
-#define LO_FLAGS_READ_ONLY	0x00000002
+#define LO_FLAGS_DO_BMAP	1
+#define LO_FLAGS_READ_ONLY	2
 
 /* 
  * Note that this structure gets the wrong offsets when directly used
@@ -102,9 +127,8 @@
 /* Support for loadable transfer modules */
 struct loop_func_table {
 	int number; 	/* filter type */ 
-	int (*transfer)(struct loop_device *lo, int cmd, 
-			char *raw_buf, char *loop_buf, int size,
-			int real_block);
+	int (*transfer)(struct loop_device *lo, int cmd, char *raw_buf,
+			char *loop_buf, int size, int real_block);
 	int (*init)(struct loop_device *, struct loop_info *); 
 	/* release is called from loop_unregister_transfer or clr_fd */
 	int (*release)(struct loop_device *); 
diff -u --recursive --new-file v2.4.2/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.4.2/linux/include/linux/mm.h	Wed Feb 21 18:20:45 2001
+++ linux/include/linux/mm.h	Fri Mar 23 18:23:08 2001
@@ -395,12 +395,26 @@
 extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
 
 extern void vmtruncate(struct inode * inode, loff_t offset);
+extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address));
+extern pte_t *FASTCALL(pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address));
 extern int handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
 
+/*
+ * On a two-level page table, this ends up being trivial. Thus the
+ * inlining and the symmetry break with pte_alloc() that does all
+ * of this out-of-line.
+ */
+static inline pmd_t *pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
+{
+	if (!pgd_present(*pgd))
+		return __pmd_alloc(mm, pgd, address);
+	return pmd_offset(pgd, address);
+}
+
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
 
@@ -481,11 +495,6 @@
 
 #define GFP_DMA		__GFP_DMA
 
-/* Flag - indicates that the buffer can be taken from high memory which is not
-   permanently mapped by the kernel */
-
-#define GFP_HIGHMEM	__GFP_HIGHMEM
-
 /* vma is the first one with  address < vma->vm_end,
  * and even  address < vma->vm_start. Have to extend vma. */
 static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
@@ -497,11 +506,13 @@
 	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
 	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
+	spin_lock(&vma->vm_mm->page_table_lock);
 	vma->vm_start = address;
 	vma->vm_pgoff -= grow;
 	vma->vm_mm->total_vm += grow;
 	if (vma->vm_flags & VM_LOCKED)
 		vma->vm_mm->locked_vm += grow;
+	spin_unlock(&vma->vm_mm->page_table_lock);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.2/linux/include/linux/mmzone.h linux/include/linux/mmzone.h
--- v2.4.2/linux/include/linux/mmzone.h	Thu Jan  4 14:50:46 2001
+++ linux/include/linux/mmzone.h	Fri Mar 23 18:23:07 2001
@@ -21,6 +21,14 @@
 
 struct pglist_data;
 
+/*
+ * On machines where it is needed (eg PCs) we divide physical memory
+ * into multiple physical zones. On a PC we have 3 zones:
+ *
+ * ZONE_DMA	  < 16 MB	ISA DMA capable memory
+ * ZONE_NORMAL	16-896 MB	direct mapped by the kernel
+ * ZONE_HIGHMEM	 > 896 MB	only page cache and user processes
+ */
 typedef struct zone_struct {
 	/*
 	 * Commonly accessed fields:
@@ -75,6 +83,17 @@
 
 #define NR_GFPINDEX		0x100
 
+/*
+ * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
+ * (mostly NUMA machines?) to denote a higher-level memory zone than the
+ * zone_struct denotes.
+ *
+ * On NUMA machines, each NUMA node would have a pg_data_t to describe
+ * it's memory layout.
+ *
+ * XXX: we need to move the global memory statistics (active_list, ...)
+ *      into the pg_data_t to properly support NUMA.
+ */
 struct bootmem_data;
 typedef struct pglist_data {
 	zone_t node_zones[MAX_NR_ZONES];
diff -u --recursive --new-file v2.4.2/linux/include/linux/n_r3964.h linux/include/linux/n_r3964.h
--- v2.4.2/linux/include/linux/n_r3964.h	Mon Dec 11 12:52:22 2000
+++ linux/include/linux/n_r3964.h	Tue Mar  6 19:44:37 2001
@@ -7,7 +7,7 @@
  * http://www.pap-philips.de
  * -----------------------------------------------------------
  * This software may be used and distributed according to the terms of
- * the GNU Public License, incorporated herein by reference.
+ * the GNU General Public License, incorporated herein by reference.
  *
  * Author:
  * L. Haag
diff -u --recursive --new-file v2.4.2/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.4.2/linux/include/linux/netdevice.h	Thu Jan  4 14:51:20 2001
+++ linux/include/linux/netdevice.h	Fri Mar 23 18:23:23 2001
@@ -630,7 +630,6 @@
 extern void		tr_setup(struct net_device *dev);
 extern void		fc_setup(struct net_device *dev);
 extern void		fc_freedev(struct net_device *dev);
-extern int		ether_config(struct net_device *dev, struct ifmap *map);
 /* Support for loadable net-drivers */
 extern int		register_netdev(struct net_device *dev);
 extern void		unregister_netdev(struct net_device *dev);
diff -u --recursive --new-file v2.4.2/linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h
--- v2.4.2/linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_TCPMSS.h	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,10 @@
+#ifndef _IPT_TCPMSS_H
+#define _IPT_TCPMSS_H
+
+struct ipt_tcpmss_info {
+	u_int16_t mss;
+};
+
+#define IPT_TCPMSS_CLAMP_PMTU 0xffff
+
+#endif /*_IPT_TCPMSS_H*/
diff -u --recursive --new-file v2.4.2/linux/include/linux/netfilter_ipv4/ipt_tcpmss.h linux/include/linux/netfilter_ipv4/ipt_tcpmss.h
--- v2.4.2/linux/include/linux/netfilter_ipv4/ipt_tcpmss.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_tcpmss.h	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,9 @@
+#ifndef _IPT_TCPMSS_MATCH_H
+#define _IPT_TCPMSS_MATCH_H
+
+struct ipt_tcpmss_match_info {
+    u_int16_t mss_min, mss_max;
+    u_int8_t invert;
+};
+
+#endif /*_IPT_TCPMSS_MATCH_H*/
diff -u --recursive --new-file v2.4.2/linux/include/linux/openpic.h linux/include/linux/openpic.h
--- v2.4.2/linux/include/linux/openpic.h	Wed Feb  9 19:43:47 2000
+++ linux/include/linux/openpic.h	Wed Dec 31 16:00:00 1969
@@ -1,367 +0,0 @@
-/*
- *  linux/openpic.h -- OpenPIC definitions
- *
- *  Copyright (C) 1997 Geert Uytterhoeven
- *
- *  This file is based on the following documentation:
- *
- *	The Open Programmable Interrupt Controller (PIC)
- *	Register Interface Specification Revision 1.2
- *
- *	Issue Date: October 1995
- *
- *	Issued jointly by Advanced Micro Devices and Cyrix Corporation
- *
- *	AMD is a registered trademark of Advanced Micro Devices, Inc.
- *	Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
- *	All Rights Reserved.
- *
- *  To receive a copy of this documentation, send an email to openpic@amd.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.
- */
-
-#ifndef _LINUX_OPENPIC_H
-#define _LINUX_OPENPIC_H
-
-#if !defined(__powerpc__) && !defined(__i386__)
-#error Unsupported OpenPIC platform
-#endif
-
-
-#ifdef __KERNEL__
-
-    /*
-     *  OpenPIC supports up to 2048 interrupt sources and up to 32 processors
-     */
-
-#define OPENPIC_MAX_SOURCES	2048
-#define OPENPIC_MAX_PROCESSORS	32
-
-#define OPENPIC_NUM_TIMERS	4
-#define OPENPIC_NUM_IPI		4
-#define OPENPIC_NUM_PRI		16
-#define OPENPIC_NUM_VECTORS	256
-
-
-    /*
-     *  Vector numbers
-     */
-
-#define OPENPIC_VEC_SOURCE      16    /* and up */
-#define OPENPIC_VEC_TIMER       64    /* and up */
-#define OPENPIC_VEC_IPI         72    /* and up */
-#define OPENPIC_VEC_SPURIOUS    127
-
-
-    /*
-     *  OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
-     */
-
-typedef struct _OpenPIC_Reg {
-    u_int Reg;					/* Little endian! */
-    char Pad[0xc];
-} OpenPIC_Reg;
-
-
-    /*
-     *  Per Processor Registers
-     */
-
-typedef struct _OpenPIC_Processor {
-    /*
-     *  Private Shadow Registers (for SLiC backwards compatibility)
-     */
-    u_int IPI0_Dispatch_Shadow;			/* Write Only */
-    char Pad1[0x4];
-    u_int IPI0_Vector_Priority_Shadow;		/* Read/Write */
-    char Pad2[0x34];
-    /*
-     *  Interprocessor Interrupt Command Ports
-     */
-    OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI];	/* Write Only */
-    /*
-     *  Current Task Priority Register
-     */
-    OpenPIC_Reg _Current_Task_Priority;		/* Read/Write */
-#ifndef __powerpc__
-    /*
-     *  Who Am I Register
-     */
-    OpenPIC_Reg _Who_Am_I;			/* Read Only */
-#else
-    char Pad3[0x10];
-#endif
-#ifndef __i386__
-    /*
-     *  Interrupt Acknowledge Register
-     */
-    OpenPIC_Reg _Interrupt_Acknowledge;		/* Read Only */
-#else
-    char Pad4[0x10];
-#endif
-    /*
-     *  End of Interrupt (EOI) Register
-     */
-    OpenPIC_Reg _EOI;				/* Read/Write */
-    char Pad5[0xf40];
-} OpenPIC_Processor;
-
-
-    /*
-     *  Timer Registers
-     */
-
-typedef struct _OpenPIC_Timer {
-    OpenPIC_Reg _Current_Count;			/* Read Only */
-    OpenPIC_Reg _Base_Count;			/* Read/Write */
-    OpenPIC_Reg _Vector_Priority;		/* Read/Write */
-    OpenPIC_Reg _Destination;			/* Read/Write */
-} OpenPIC_Timer;
-
-
-    /*
-     *  Global Registers
-     */
-
-typedef struct _OpenPIC_Global {
-    /*
-     *  Feature Reporting Registers
-     */
-    OpenPIC_Reg _Feature_Reporting0;		/* Read Only */
-    OpenPIC_Reg _Feature_Reporting1;		/* Future Expansion */
-    /*
-     *  Global Configuration Registers
-     */
-    OpenPIC_Reg _Global_Configuration0;		/* Read/Write */
-    OpenPIC_Reg _Global_Configuration1;		/* Future Expansion */
-    /*
-     *  Vendor Specific Registers
-     */
-    OpenPIC_Reg _Vendor_Specific[4];
-    /*
-     *  Vendor Identification Register
-     */
-    OpenPIC_Reg _Vendor_Identification;		/* Read Only */
-    /*
-     *  Processor Initialization Register
-     */
-    OpenPIC_Reg _Processor_Initialization;	/* Read/Write */
-    /*
-     *  IPI Vector/Priority Registers
-     */
-    OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI];	/* Read/Write */
-    /*
-     *  Spurious Vector Register
-     */
-    OpenPIC_Reg _Spurious_Vector;		/* Read/Write */
-    /*
-     *  Global Timer Registers
-     */
-    OpenPIC_Reg _Timer_Frequency;		/* Read/Write */
-    OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
-    char Pad1[0xee00];
-} OpenPIC_Global;
-
-
-    /*
-     *  Interrupt Source Registers
-     */
-
-typedef struct _OpenPIC_Source {
-    OpenPIC_Reg _Vector_Priority;		/* Read/Write */
-    OpenPIC_Reg _Destination;			/* Read/Write */
-} OpenPIC_Source;
-
-
-    /*
-     *  OpenPIC Register Map
-     */
-
-struct OpenPIC {
-#ifndef __powerpc__
-    /*
-     *  Per Processor Registers --- Private Access
-     */
-    OpenPIC_Processor Private;
-#else
-    char Pad1[0x1000];
-#endif
-    /*
-     *  Global Registers
-     */
-    OpenPIC_Global Global;
-    /*
-     *  Interrupt Source Configuration Registers
-     */
-    OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
-    /*
-     *  Per Processor Registers
-     */
-    OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
-};
-
-extern volatile struct OpenPIC *OpenPIC;
-extern u_int OpenPIC_NumInitSenses;
-extern u_char *OpenPIC_InitSenses;
-
-
-    /*
-     *  Current Task Priority Register
-     */
-
-#define OPENPIC_CURRENT_TASK_PRIORITY_MASK	0x0000000f
-
-    /*
-     *  Who Am I Register
-     */
-
-#define OPENPIC_WHO_AM_I_ID_MASK		0x0000001f
-
-    /*
-     *  Feature Reporting Register 0
-     */
-
-#define OPENPIC_FEATURE_LAST_SOURCE_MASK	0x07ff0000
-#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT	16
-#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK	0x00001f00
-#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT	8
-#define OPENPIC_FEATURE_VERSION_MASK		0x000000ff
-
-    /*
-     *  Global Configuration Register 0
-     */
-
-#define OPENPIC_CONFIG_RESET			0x80000000
-#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE	0x20000000
-#define OPENPIC_CONFIG_BASE_MASK		0x000fffff
-
-    /*
-     *  Vendor Identification Register
-     */
-
-#define OPENPIC_VENDOR_ID_STEPPING_MASK		0x00ff0000
-#define OPENPIC_VENDOR_ID_STEPPING_SHIFT	16
-#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK	0x0000ff00
-#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT	8
-#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK	0x000000ff
-
-    /*
-     *  Vector/Priority Registers
-     */
-
-#define OPENPIC_MASK				0x80000000
-#define OPENPIC_ACTIVITY			0x40000000	/* Read Only */
-#define OPENPIC_PRIORITY_MASK			0x000f0000
-#define OPENPIC_PRIORITY_SHIFT			16
-#define OPENPIC_VECTOR_MASK			0x000000ff
-
-
-    /*
-     *  Interrupt Source Registers
-     */
-
-#define OPENPIC_POLARITY_POSITIVE		0x00800000
-#define OPENPIC_POLARITY_NEGATIVE		0x00000000
-#define OPENPIC_POLARITY_MASK			0x00800000
-#define OPENPIC_SENSE_LEVEL			0x00400000
-#define OPENPIC_SENSE_EDGE			0x00000000
-#define OPENPIC_SENSE_MASK			0x00400000
-
-
-    /*
-     *  Timer Registers
-     */
-
-#define OPENPIC_COUNT_MASK			0x7fffffff
-#define OPENPIC_TIMER_TOGGLE			0x80000000
-#define OPENPIC_TIMER_COUNT_INHIBIT		0x80000000
-
-
-    /*
-     *  Aliases to make life simpler
-     */
-
-/* Per Processor Registers */
-#define IPI_Dispatch(i)			_IPI_Dispatch[i].Reg
-#define Current_Task_Priority		_Current_Task_Priority.Reg
-#ifndef __powerpc__
-#define Who_Am_I			_Who_Am_I.Reg
-#endif
-#ifndef __i386__
-#define Interrupt_Acknowledge		_Interrupt_Acknowledge.Reg
-#endif
-#define EOI				_EOI.Reg
-
-/* Global Registers */
-#define Feature_Reporting0		_Feature_Reporting0.Reg
-#define Feature_Reporting1		_Feature_Reporting1.Reg
-#define Global_Configuration0		_Global_Configuration0.Reg
-#define Global_Configuration1		_Global_Configuration1.Reg
-#define Vendor_Specific(i)		_Vendor_Specific[i].Reg
-#define Vendor_Identification		_Vendor_Identification.Reg
-#define Processor_Initialization	_Processor_Initialization.Reg
-#define IPI_Vector_Priority(i)		_IPI_Vector_Priority[i].Reg
-#define Spurious_Vector			_Spurious_Vector.Reg
-#define Timer_Frequency			_Timer_Frequency.Reg
-
-/* Timer Registers */
-#define Current_Count			_Current_Count.Reg
-#define Base_Count			_Base_Count.Reg
-#define Vector_Priority			_Vector_Priority.Reg
-#define Destination			_Destination.Reg
-
-/* Interrupt Source Registers */
-#define Vector_Priority			_Vector_Priority.Reg
-#define Destination			_Destination.Reg
-
-    /*
-     *  OpenPIC Operations
-     */
-
-/* Global Operations */
-extern void openpic_init(int);
-extern void openpic_reset(void);
-extern void openpic_enable_8259_pass_through(void);
-extern void openpic_disable_8259_pass_through(void);
-#ifndef __i386__
-extern u_int openpic_irq(u_int cpu);
-#endif
-#ifndef __powerpc__
-extern void openpic_eoi(void);
-extern u_int openpic_get_priority(void);
-extern void openpic_set_priority(u_int pri);
-#else
-extern void openpic_eoi(u_int cpu);
-extern u_int openpic_get_priority(u_int cpu);
-extern void openpic_set_priority(u_int cpu, u_int pri);
-#endif
-extern u_int openpic_get_spurious(void);
-extern void openpic_set_spurious(u_int vector);
-extern void openpic_init_processor(u_int cpumask);
-
-/* Interprocessor Interrupts */
-extern void openpic_initipi(u_int ipi, u_int pri, u_int vector);
-#ifndef __powerpc__
-extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
-#else
-extern void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask);
-#endif
-
-/* Timer Interrupts */
-extern void openpic_inittimer(u_int timer, u_int pri, u_int vector);
-extern void openpic_maptimer(u_int timer, u_int cpumask);
-
-/* Interrupt Sources */
-extern void openpic_enable_irq(u_int irq);
-extern void openpic_disable_irq(u_int irq);
-extern void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
-			    int is_level);
-extern void openpic_mapirq(u_int irq, u_int cpumask);
-extern void openpic_set_sense(u_int irq, int sense);
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_OPENPIC_H */
diff -u --recursive --new-file v2.4.2/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.4.2/linux/include/linux/pagemap.h	Thu Jan  4 14:50:47 2001
+++ linux/include/linux/pagemap.h	Fri Mar 23 18:23:10 2001
@@ -29,9 +29,13 @@
 #define PAGE_CACHE_ALIGN(addr)	(((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK)
 
 #define page_cache_get(x)	get_page(x)
-#define page_cache_alloc()	alloc_pages(GFP_HIGHUSER, 0)
 #define page_cache_free(x)	__free_page(x)
 #define page_cache_release(x)	__free_page(x)
+
+static inline struct page *page_cache_alloc(struct address_space *x)
+{
+	return alloc_pages(x->gfp_mask, 0);
+}
 
 /*
  * From a kernel address, get the "struct page *"
diff -u --recursive --new-file v2.4.2/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.4.2/linux/include/linux/pci.h	Wed Feb 21 18:20:45 2001
+++ linux/include/linux/pci.h	Fri Mar 23 18:23:39 2001
@@ -527,6 +527,7 @@
 
 int pci_enable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
+int pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask);
 int pci_set_power_state(struct pci_dev *dev, int state);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
@@ -539,6 +540,9 @@
 unsigned long pci_bridge_check_io(struct pci_dev *);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
+#define HAVE_PCI_REQ_REGIONS
+int pci_request_regions(struct pci_dev *, char *);
+void pci_release_regions(struct pci_dev *);
 
 /* New-style probing supporting hot-pluggable devices */
 int pci_register_driver(struct pci_driver *);
diff -u --recursive --new-file v2.4.2/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.2/linux/include/linux/pci_ids.h	Wed Feb 21 18:20:46 2001
+++ linux/include/linux/pci_ids.h	Sat Mar  3 10:52:14 2001
@@ -505,7 +505,10 @@
 #define PCI_DEVICE_ID_APPLE_BANDIT	0x0001
 #define PCI_DEVICE_ID_APPLE_GC		0x0002
 #define PCI_DEVICE_ID_APPLE_HYDRA	0x000e
-#define PCI_DEVICE_ID_APPLE_UNINORTH	0x0020
+#define PCI_DEVICE_ID_APPLE_UNI_N_FW	0x0018
+#define PCI_DEVICE_ID_APPLE_KL_USB	0x0019
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP	0x0020
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC	0x0021
 
 #define PCI_VENDOR_ID_YAMAHA		0x1073
 #define PCI_DEVICE_ID_YAMAHA_724	0x0004
diff -u --recursive --new-file v2.4.2/linux/include/linux/pg.h linux/include/linux/pg.h
--- v2.4.2/linux/include/linux/pg.h	Sat Jun 13 12:08:20 1998
+++ linux/include/linux/pg.h	Tue Mar  6 19:44:37 2001
@@ -1,5 +1,5 @@
 /* 	pg.h (c) 1998  Grant R. Guenther <grant@torque.net>
- 		       Under the terms of the GNU public license
+ 		       Under the terms of the GNU General Public License
 
 
 	pg.h defines the user interface to the generic ATAPI packet
diff -u --recursive --new-file v2.4.2/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.4.2/linux/include/linux/sched.h	Wed Feb 21 18:20:46 2001
+++ linux/include/linux/sched.h	Fri Mar 23 18:23:08 2001
@@ -167,7 +167,7 @@
  */
 struct files_struct {
 	atomic_t count;
-	rwlock_t file_lock;
+	rwlock_t file_lock;	/* Protects all the below members.  Nests inside tsk->alloc_lock */
 	int max_fds;
 	int max_fdset;
 	int next_fd;
@@ -208,10 +208,13 @@
 	atomic_t mm_users;			/* How many users with user space? */
 	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
 	int map_count;				/* number of VMAs */
-	struct semaphore mmap_sem;
-	spinlock_t page_table_lock;
+	struct rw_semaphore mmap_sem;
+	spinlock_t page_table_lock;		/* Protects task page tables and mm->rss */
 
-	struct list_head mmlist;		/* List of all active mm's */
+	struct list_head mmlist;		/* List of all active mm's.  These are globally strung
+						 * together off init_mm.mmlist, and are protected
+						 * by mmlist_lock
+						 */
 
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
@@ -236,7 +239,7 @@
 	mm_users:	ATOMIC_INIT(2), 		\
 	mm_count:	ATOMIC_INIT(1), 		\
 	map_count:	1, 				\
-	mmap_sem:	__MUTEX_INITIALIZER(name.mmap_sem), \
+	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem, RW_LOCK_BIAS), \
 	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
 	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
 }
@@ -857,6 +860,7 @@
 	write_unlock_irq(&tasklist_lock);
 }
 
+/* Protects ->fs, ->files, ->mm, and synchronises with wait4().  Nests inside tasklist_lock */
 static inline void task_lock(struct task_struct *p)
 {
 	spin_lock(&p->alloc_lock);
diff -u --recursive --new-file v2.4.2/linux/include/linux/serial.h linux/include/linux/serial.h
--- v2.4.2/linux/include/linux/serial.h	Wed Feb 21 18:20:46 2001
+++ linux/include/linux/serial.h	Fri Mar 23 18:23:07 2001
@@ -139,7 +139,7 @@
 #define ASYNC_CHECK_CD		0x02000000 /* i.e., CLOCAL */
 #define ASYNC_SHARE_IRQ		0x01000000 /* for multifunction cards
 					     --- no longer used */
-#define ASYNC_NO_FLOW		0x00800000 /* No flow control serial console */
+#define ASYNC_CONS_FLOW		0x00800000 /* flow control for console  */
 
 #define ASYNC_INTERNAL_FLAGS	0xFF800000 /* Internal flags */
 
@@ -180,5 +180,6 @@
 
 /* Allow complicated architectures to specify rs_table[] at run time */
 extern int early_serial_setup(struct serial_struct *req);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SERIAL_H */
diff -u --recursive --new-file v2.4.2/linux/include/linux/serialP.h linux/include/linux/serialP.h
--- v2.4.2/linux/include/linux/serialP.h	Thu Jan  4 14:51:38 2001
+++ linux/include/linux/serialP.h	Fri Mar 23 18:25:07 2001
@@ -52,6 +52,7 @@
 	struct termios		callout_termios;
 	int	io_type;
 	struct async_struct *info;
+	struct pci_dev	*dev;
 };
 
 struct async_struct {
diff -u --recursive --new-file v2.4.2/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h
--- v2.4.2/linux/include/linux/serial_reg.h	Wed Jun 21 12:43:38 2000
+++ linux/include/linux/serial_reg.h	Tue Mar  6 19:28:35 2001
@@ -156,8 +156,8 @@
  * These register definitions are for the 16C950
  */
 #define UART_ASR	0x01	/* Additional Status Register */
-#define UART_RFL	0x03	/* Transmitter FIFO level */
-#define UART_TFL 	0x04	/* Receiver FIFO level */
+#define UART_RFL	0x03	/* Receiver FIFO level */
+#define UART_TFL 	0x04	/* Transmitter FIFO level */
 #define UART_ICR	0x05	/* Index Control Register */
 
 /* The 16950 ICR registers */
diff -u --recursive --new-file v2.4.2/linux/include/linux/synclink.h linux/include/linux/synclink.h
--- v2.4.2/linux/include/linux/synclink.h	Tue Nov  7 10:36:45 2000
+++ linux/include/linux/synclink.h	Tue Mar  6 19:44:37 2001
@@ -6,7 +6,7 @@
  * Copyright (C) 1998-2000 by Microgate Corporation
  * 
  * Redistribution of this file is permitted under 
- * the terms of the GNU Public License (GPL)
+ * the terms of the GNU General Public License (GPL)
  */
 
 #ifndef _SYNCLINK_H_
diff -u --recursive --new-file v2.4.2/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
--- v2.4.2/linux/include/linux/tqueue.h	Thu Jan  4 14:50:46 2001
+++ linux/include/linux/tqueue.h	Fri Mar 23 18:23:08 2001
@@ -42,6 +42,25 @@
 	void *data;			/* argument to function */
 };
 
+/*
+ * Emit code to initialise a tq_struct's routine and data pointers
+ */
+#define PREPARE_TQUEUE(_tq, _routine, _data)			\
+	do {							\
+		(_tq)->routine = _routine;			\
+		(_tq)->data = _data;				\
+	} while (0)
+
+/*
+ * Emit code to initialise all of a tq_struct
+ */
+#define INIT_TQUEUE(_tq, _routine, _data)			\
+	do {							\
+		INIT_LIST_HEAD(&(_tq)->list);			\
+		(_tq)->sync = 0;				\
+		PREPARE_TQUEUE((_tq), (_routine), (_data));	\
+	} while (0)
+
 typedef struct list_head task_queue;
 
 #define DECLARE_TASK_QUEUE(q)	LIST_HEAD(q)
diff -u --recursive --new-file v2.4.2/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.4.2/linux/include/linux/tty.h	Thu Jan  4 14:50:47 2001
+++ linux/include/linux/tty.h	Fri Mar 23 18:23:08 2001
@@ -307,6 +307,8 @@
 	struct semaphore atomic_read;
 	struct semaphore atomic_write;
 	spinlock_t read_lock;
+	/* If the tty has a pending do_SAK, queue it here - akpm */
+	struct tq_struct SAK_tq;
 };
 
 /* tty magic number */
diff -u --recursive --new-file v2.4.2/linux/include/linux/usb.h linux/include/linux/usb.h
--- v2.4.2/linux/include/linux/usb.h	Thu Jan  4 14:52:19 2001
+++ linux/include/linux/usb.h	Fri Mar 23 18:24:40 2001
@@ -555,11 +555,17 @@
 	int (*unlink_urb) (struct urb* purb);
 };
 
+#define DEVNUM_ROUND_ROBIN	/***** OPTION *****/
+
 /*
  * Allocated per bus we have
  */
 struct usb_bus {
 	int busnum;			/* Bus number (in order of reg) */
+
+#ifdef DEVNUM_ROUND_ROBIN
+	int devnum_next;                /* Next open device number in round-robin allocation */
+#endif /* DEVNUM_ROUND_ROBIN */
 
 	struct usb_devmap devmap;       /* Device map */
 	struct usb_operations *op;      /* Operations (specific to the HC) */
diff -u --recursive --new-file v2.4.2/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.4.2/linux/include/linux/videodev.h	Mon Dec 11 13:15:36 2000
+++ linux/include/linux/videodev.h	Fri Mar  2 11:12:10 2001
@@ -6,13 +6,12 @@
 
 #ifdef __KERNEL__
 
-#if LINUX_VERSION_CODE >= 0x020100
 #include <linux/poll.h>
-#endif
 #include <linux/devfs_fs_kernel.h>
 
 struct video_device
 {
+	struct module *owner;
 	char name[32];
 	int type;
 	int hardware;
diff -u --recursive --new-file v2.4.2/linux/include/net/syncppp.h linux/include/net/syncppp.h
--- v2.4.2/linux/include/net/syncppp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/syncppp.h	Tue Mar  6 19:44:37 2001
@@ -0,0 +1,98 @@
+/*
+ * Defines for synchronous PPP/Cisco link level subroutines.
+ *
+ * Copyright (C) 1994 Cronyx Ltd.
+ * Author: Serge Vakulenko, <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organizations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * Version 1.7, Wed Jun  7 22:12:02 MSD 1995
+ *
+ *
+ *
+ */
+
+#ifndef _SYNCPPP_H_
+#define _SYNCPPP_H_ 1
+
+#ifdef __KERNEL__
+struct slcp {
+	u16	state;          /* state machine */
+	u32	magic;          /* local magic number */
+	u_char	echoid;         /* id of last keepalive echo request */
+	u_char	confid;         /* id of last configuration request */
+};
+
+struct sipcp {
+	u16	state;          /* state machine */
+	u_char  confid;         /* id of last configuration request */
+};
+
+struct sppp 
+{
+	struct sppp *	pp_next;	/* next interface in keepalive list */
+	u32		pp_flags;	/* use Cisco protocol instead of PPP */
+	u16		pp_alivecnt;	/* keepalive packets counter */
+	u16		pp_loopcnt;	/* loopback detection counter */
+	u32		pp_seq;		/* local sequence number */
+	u32		pp_rseq;	/* remote sequence number */
+	struct slcp	lcp;		/* LCP params */
+	struct sipcp	ipcp;		/* IPCP params */
+	u32		ibytes,obytes;	/* Bytes in/out */
+	u32		ipkts,opkts;	/* Packets in/out */
+	struct timer_list	pp_timer;
+	struct net_device	*pp_if;
+	char		pp_link_state;	/* Link status */
+};
+
+struct ppp_device
+{	
+	struct net_device *dev;	/* Network device pointer */
+	struct sppp sppp;	/* Synchronous PPP */
+};
+
+#define sppp_of(dev)	\
+	    (&((struct ppp_device *)(*(unsigned long *)((dev)->priv)))->sppp)
+
+#define PP_KEEPALIVE    0x01    /* use keepalive protocol */
+#define PP_CISCO        0x02    /* use Cisco protocol instead of PPP */
+#define PP_TIMO         0x04    /* cp_timeout routine active */
+#define PP_DEBUG	0x08
+
+#define PPP_MTU          1500    /* max. transmit unit */
+
+#define LCP_STATE_CLOSED        0       /* LCP state: closed (conf-req sent) */
+#define LCP_STATE_ACK_RCVD      1       /* LCP state: conf-ack received */
+#define LCP_STATE_ACK_SENT      2       /* LCP state: conf-ack sent */
+#define LCP_STATE_OPENED        3       /* LCP state: opened */
+
+#define IPCP_STATE_CLOSED       0       /* IPCP state: closed (conf-req sent) */
+#define IPCP_STATE_ACK_RCVD     1       /* IPCP state: conf-ack received */
+#define IPCP_STATE_ACK_SENT     2       /* IPCP state: conf-ack sent */
+#define IPCP_STATE_OPENED       3       /* IPCP state: opened */
+
+#define SPPP_LINK_DOWN		0	/* link down - no keepalive */
+#define SPPP_LINK_UP		1	/* link is up - keepalive ok */
+
+void sppp_attach (struct ppp_device *pd);
+void sppp_detach (struct net_device *dev);
+void sppp_input (struct net_device *dev, struct sk_buff *m);
+int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
+struct sk_buff *sppp_dequeue (struct net_device *dev);
+int sppp_isempty (struct net_device *dev);
+void sppp_flush (struct net_device *dev);
+int sppp_open (struct net_device *dev);
+int sppp_reopen (struct net_device *dev);
+int sppp_close (struct net_device *dev);
+#endif
+
+#define SPPPIOCCISCO	(SIOCDEVPRIVATE)
+#define SPPPIOCPPP	(SIOCDEVPRIVATE+1)
+#define SPPPIOCDEBUG	(SIOCDEVPRIVATE+2)
+
+#endif /* _SYNCPPP_H_ */
diff -u --recursive --new-file v2.4.2/linux/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h
--- v2.4.2/linux/include/pcmcia/ciscode.h	Wed Feb 21 18:20:46 2001
+++ linux/include/pcmcia/ciscode.h	Fri Mar  2 11:02:15 2001
@@ -112,10 +112,12 @@
 #define PRODID_SOCKET_DUAL_RS232	0x0006
 #define PRODID_SOCKET_EIO		0x000a
 #define PRODID_SOCKET_LPE		0x000d
+#define PRODID_SOCKET_LPE_CF		0x0075
 
 #define MANFID_SUNDISK			0x0045
 
 #define MANFID_TDK			0x0105
+#define PRODID_TDK_CF010		0x0900
 
 #define MANFID_TOSHIBA			0x0098
 
diff -u --recursive --new-file v2.4.2/linux/init/main.c linux/init/main.c
--- v2.4.2/linux/init/main.c	Wed Jan  3 20:45:26 2001
+++ linux/init/main.c	Mon Mar 19 12:26:25 2001
@@ -151,6 +151,7 @@
 	{ "nfs",     0x00ff },
 	{ "hda",     0x0300 },
 	{ "hdb",     0x0340 },
+	{ "loop",    0x0700 },
 	{ "hdc",     0x1600 },
 	{ "hdd",     0x1640 },
 	{ "hde",     0x2100 },
diff -u --recursive --new-file v2.4.2/linux/ipc/shm.c linux/ipc/shm.c
--- v2.4.2/linux/ipc/shm.c	Wed Feb 21 18:20:46 2001
+++ linux/ipc/shm.c	Mon Mar 19 12:35:08 2001
@@ -71,7 +71,9 @@
 void __init shm_init (void)
 {
 	ipc_init_ids(&shm_ids, 1);
+#ifdef CONFIG_PROC_FS
 	create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL);
+#endif
 }
 
 static inline int shm_checkid(struct shmid_kernel *s, int id)
@@ -605,9 +607,9 @@
 	shp->shm_nattch++;
 	shm_unlock(shmid);
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	user_addr = (void *) do_mmap (file, addr, file->f_dentry->d_inode->i_size, prot, flags, 0);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 
 	down (&shm_ids.sem);
 	if(!(shp = shm_lock(shmid)))
@@ -636,14 +638,14 @@
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *shmd, *shmdnext;
 
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 	for (shmd = mm->mmap; shmd; shmd = shmdnext) {
 		shmdnext = shmd->vm_next;
 		if (shmd->vm_ops == &shm_vm_ops
 		    && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr)
 			do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start);
 	}
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.2/linux/kernel/acct.c linux/kernel/acct.c
--- v2.4.2/linux/kernel/acct.c	Wed Feb 21 18:20:46 2001
+++ linux/kernel/acct.c	Mon Mar 19 12:35:08 2001
@@ -315,13 +315,13 @@
 	vsize = 0;
 	if (current->mm) {
 		struct vm_area_struct *vma;
-		down(&current->mm->mmap_sem);
+		down_read(&current->mm->mmap_sem);
 		vma = current->mm->mmap;
 		while (vma) {
 			vsize += vma->vm_end - vma->vm_start;
 			vma = vma->vm_next;
 		}
-		up(&current->mm->mmap_sem);
+		up_read(&current->mm->mmap_sem);
 	}
 	vsize = vsize / 1024;
 	ac.ac_mem = encode_comp_t(vsize);
diff -u --recursive --new-file v2.4.2/linux/kernel/fork.c linux/kernel/fork.c
--- v2.4.2/linux/kernel/fork.c	Wed Feb 21 18:20:46 2001
+++ linux/kernel/fork.c	Mon Mar 19 12:35:08 2001
@@ -201,7 +201,7 @@
 {
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
-	init_MUTEX(&mm->mmap_sem);
+	init_rwsem(&mm->mmap_sem);
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
 	mm->pgd = pgd_alloc();
 	if (mm->pgd)
@@ -314,9 +314,9 @@
 	if (!mm_init(mm))
 		goto fail_nomem;
 
-	down(&oldmm->mmap_sem);
+	down_write(&oldmm->mmap_sem);
 	retval = dup_mmap(mm);
-	up(&oldmm->mmap_sem);
+	up_write(&oldmm->mmap_sem);
 
 	/*
 	 * Add it to the mmlist after the parent.
diff -u --recursive --new-file v2.4.2/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.2/linux/kernel/ksyms.c	Wed Feb 21 18:20:46 2001
+++ linux/kernel/ksyms.c	Fri Mar  2 15:16:59 2001
@@ -121,6 +121,7 @@
 EXPORT_SYMBOL(kmap_high);
 EXPORT_SYMBOL(kunmap_high);
 EXPORT_SYMBOL(highmem_start_page);
+EXPORT_SYMBOL(create_bounce);
 #endif
 
 /* filesystem internal functions */
diff -u --recursive --new-file v2.4.2/linux/kernel/pm.c linux/kernel/pm.c
--- v2.4.2/linux/kernel/pm.c	Fri May 12 11:21:20 2000
+++ linux/kernel/pm.c	Tue Mar  6 19:44:37 2001
@@ -25,7 +25,19 @@
 
 int pm_active;
 
-static spinlock_t pm_devs_lock = SPIN_LOCK_UNLOCKED;
+/*
+ *	Locking notes:
+ *		pm_devs_lock can be a semaphore providing pm ops are not called
+ *	from an interrupt handler (already a bad idea so no change here). Each
+ *	change must be protected so that an unlink of an entry doesnt clash
+ *	with a pm send - which is permitted to sleep in the current architecture
+ *
+ *	Module unloads clashing with pm events now work out safely, the module 
+ *	unload path will block until the event has been sent. It may well block
+ *	until a resume but that will be fine.
+ */
+ 
+static DECLARE_MUTEX(pm_devs_lock);
 static LIST_HEAD(pm_devs);
 
 /**
@@ -45,16 +57,14 @@
 {
 	struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
 	if (dev) {
-		unsigned long flags;
-
 		memset(dev, 0, sizeof(*dev));
 		dev->type = type;
 		dev->id = id;
 		dev->callback = callback;
 
-		spin_lock_irqsave(&pm_devs_lock, flags);
+		down(&pm_devs_lock);
 		list_add(&dev->entry, &pm_devs);
-		spin_unlock_irqrestore(&pm_devs_lock, flags);
+		up(&pm_devs_lock);
 	}
 	return dev;
 }
@@ -70,16 +80,22 @@
 void pm_unregister(struct pm_dev *dev)
 {
 	if (dev) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&pm_devs_lock, flags);
+		down(&pm_devs_lock);
 		list_del(&dev->entry);
-		spin_unlock_irqrestore(&pm_devs_lock, flags);
+		up(&pm_devs_lock);
 
 		kfree(dev);
 	}
 }
 
+static void __pm_unregister(struct pm_dev *dev)
+{
+	if (dev) {
+		list_del(&dev->entry);
+		kfree(dev);
+	}
+}
+
 /**
  *	pm_unregister_all - unregister all devices with matching callback
  *	@callback: callback function pointer
@@ -97,13 +113,15 @@
 	if (!callback)
 		return;
 
+	down(&pm_devs_lock);
 	entry = pm_devs.next;
 	while (entry != &pm_devs) {
 		struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
 		entry = entry->next;
 		if (dev->callback == callback)
-			pm_unregister(dev);
+			__pm_unregister(dev);
 	}
+	up(&pm_devs_lock);
 }
 
 /**
@@ -119,6 +137,13 @@
  *
  *	BUGS: what stops two power management requests occuring in parallel
  *	and conflicting.
+ *
+ *	WARNING: Calling pm_send directly is not generally recommended, in
+ *	paticular there is no locking against the pm_dev going away. The
+ *	caller must maintain all needed locking or have 'inside knowledge'
+ *	on the safety. Also remember that this function is not locked against
+ *	pm_unregister. This means that you must handle SMP races on callback
+ *	execution and unload yourself.
  */
  
 int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
@@ -183,6 +208,12 @@
  *	during the processing of this request are restored to their
  *	previous state.
  *
+ *	WARNING:  This function takes the pm_devs_lock. The lock is not dropped until
+ *	the callbacks have completed. This prevents races against pm locking
+ *	functions, races against module unload pm_unregister code. It does
+ *	mean however that you must not issue pm_ functions within the callback
+ *	or you will deadlock and users will hate you.
+ *
  *	Zero is returned on success. If a suspend fails then the status
  *	from the device that vetoes the suspend is returned.
  *
@@ -192,7 +223,10 @@
  
 int pm_send_all(pm_request_t rqst, void *data)
 {
-	struct list_head *entry = pm_devs.next;
+	struct list_head *entry;
+	
+	down(&pm_devs_lock);
+	entry = pm_devs.next;
 	while (entry != &pm_devs) {
 		struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
 		if (dev->callback) {
@@ -203,11 +237,13 @@
 				 */
 				if (rqst == PM_SUSPEND)
 					pm_undo_all(dev);
+				up(&pm_devs_lock);
 				return status;
 			}
 		}
 		entry = entry->next;
 	}
+	up(&pm_devs_lock);
 	return 0;
 }
 
@@ -222,6 +258,10 @@
  *	of the list. 
  *
  *	To search from the beginning pass %NULL as the @from value.
+ *
+ *	The caller MUST hold the pm_devs_lock lock when calling this 
+ *	function. The instant that the lock is dropped all pointers returned
+ *	may become invalid.
  */
  
 struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
diff -u --recursive --new-file v2.4.2/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.4.2/linux/kernel/ptrace.c	Wed Nov  8 19:01:34 2000
+++ linux/kernel/ptrace.c	Mon Mar 19 12:35:08 2001
@@ -28,6 +28,7 @@
 	struct page *page;
 
 repeat:
+	spin_lock(&mm->page_table_lock);
 	pgdir = pgd_offset(vma->vm_mm, addr);
 	if (pgd_none(*pgdir))
 		goto fault_in_page;
@@ -47,9 +48,13 @@
 
 	/* ZERO_PAGE is special: reads from it are ok even though it's marked reserved */
 	if (page != ZERO_PAGE(addr) || write) {
-		if ((!VALID_PAGE(page)) || PageReserved(page))
+		if ((!VALID_PAGE(page)) || PageReserved(page)) {
+			spin_unlock(&mm->page_table_lock);
 			return 0;
+		}
 	}
+	get_page(page);
+	spin_unlock(&mm->page_table_lock);
 	flush_cache_page(vma, addr);
 
 	if (write) {
@@ -64,19 +69,23 @@
 		flush_page_to_ram(page);
 		kunmap(page);
 	}
+	put_page(page);
 	return len;
 
 fault_in_page:
+	spin_unlock(&mm->page_table_lock);
 	/* -1: out of memory. 0 - unmapped page */
 	if (handle_mm_fault(mm, vma, addr, write) > 0)
 		goto repeat;
 	return 0;
 
 bad_pgd:
+	spin_unlock(&mm->page_table_lock);
 	pgd_ERROR(*pgdir);
 	return 0;
 
 bad_pmd:
+	spin_unlock(&mm->page_table_lock);
 	pmd_ERROR(*pgmiddle);
 	return 0;
 }
@@ -131,13 +140,13 @@
 	if (!mm)
 		return 0;
 
-	down(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
 	vma = find_extend_vma(mm, addr);
 	copied = 0;
 	if (vma)
 		copied = access_mm(mm, vma, addr, buf, len, write);
 
-	up(&mm->mmap_sem);
+	up_read(&mm->mmap_sem);
 	mmput(mm);
 	return copied;
 }
diff -u --recursive --new-file v2.4.2/linux/kernel/sched.c linux/kernel/sched.c
--- v2.4.2/linux/kernel/sched.c	Wed Feb 21 18:20:46 2001
+++ linux/kernel/sched.c	Thu Mar 22 09:20:45 2001
@@ -82,6 +82,8 @@
  *
  * If both locks are to be concurrently held, the runqueue_lock
  * nests inside the tasklist_lock.
+ *
+ * task->alloc_lock nests inside tasklist_lock.
  */
 spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;  /* inner */
 rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;	/* outer */
@@ -339,7 +341,7 @@
 	if (task_on_runqueue(p))
 		goto out;
 	add_to_runqueue(p);
-	if (!synchronous)
+	if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id())))
 		reschedule_idle(p);
 	success = 1;
 out:
@@ -359,6 +361,32 @@
 	wake_up_process(p);
 }
 
+/**
+ * schedule_timeout - sleep until timeout
+ * @timeout: timeout value in jiffies
+ *
+ * Make the current task sleep until @timeout jiffies have
+ * elapsed. The routine will return immediately unless
+ * the current task state has been set (see set_current_state()).
+ *
+ * You can set the task state as follows -
+ *
+ * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to
+ * pass before the routine returns. The routine will return 0
+ *
+ * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
+ * delivered to the current task. In this case the remaining time
+ * in jiffies will be returned, or 0 if the timer expired in time
+ *
+ * The current task state is guaranteed to be TASK_RUNNING when this 
+ * routine returns.
+ *
+ * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule
+ * the CPU away without a bound on the timeout. In this case the return
+ * value will be %MAX_SCHEDULE_TIMEOUT.
+ *
+ * In all cases the return value is guaranteed to be non-negative.
+ */
 signed long schedule_timeout(signed long timeout)
 {
 	struct timer_list timer;
@@ -473,7 +501,7 @@
 			goto out_unlock;
 
 		spin_lock_irqsave(&runqueue_lock, flags);
-		if (prev->state == TASK_RUNNING)
+		if ((prev->state == TASK_RUNNING) && !prev->has_cpu)
 			reschedule_idle(prev);
 		spin_unlock_irqrestore(&runqueue_lock, flags);
 		goto out_unlock;
@@ -541,7 +569,7 @@
 			}
 		default:
 			del_from_runqueue(prev);
-		case TASK_RUNNING:
+		case TASK_RUNNING:;
 	}
 	prev->need_resched = 0;
 
diff -u --recursive --new-file v2.4.2/linux/kernel/sys.c linux/kernel/sys.c
--- v2.4.2/linux/kernel/sys.c	Mon Oct 16 12:58:51 2000
+++ linux/kernel/sys.c	Tue Mar  6 19:44:37 2001
@@ -330,6 +330,12 @@
 	return 0;
 }
 
+static void deferred_cad(void *dummy)
+{
+	notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+	machine_restart(NULL);
+}
+
 /*
  * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
  * As it's called within an interrupt, it may NOT sync: the only choice
@@ -337,10 +343,13 @@
  */
 void ctrl_alt_del(void)
 {
-	if (C_A_D) {
-		notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
-		machine_restart(NULL);
-	} else
+	static struct tq_struct cad_tq = {
+		routine: deferred_cad,
+	};
+
+	if (C_A_D)
+		schedule_task(&cad_tq);
+	else
 		kill_proc(1, SIGINT, 1);
 }
 	
@@ -367,12 +376,14 @@
 {
 	int old_rgid = current->gid;
 	int old_egid = current->egid;
+	int new_rgid = old_rgid;
+	int new_egid = old_egid;
 
 	if (rgid != (gid_t) -1) {
 		if ((old_rgid == rgid) ||
 		    (current->egid==rgid) ||
 		    capable(CAP_SETGID))
-			current->gid = rgid;
+			new_rgid = rgid;
 		else
 			return -EPERM;
 	}
@@ -381,18 +392,22 @@
 		    (current->egid == egid) ||
 		    (current->sgid == egid) ||
 		    capable(CAP_SETGID))
-			current->fsgid = current->egid = egid;
+			new_egid = egid;
 		else {
-			current->gid = old_rgid;
 			return -EPERM;
 		}
 	}
+	if (new_egid != old_egid)
+	{
+		current->dumpable = 0;
+		wmb();
+	}
 	if (rgid != (gid_t) -1 ||
 	    (egid != (gid_t) -1 && egid != old_rgid))
-		current->sgid = current->egid;
-	current->fsgid = current->egid;
-	if (current->egid != old_egid)
-		current->dumpable = 0;
+		current->sgid = new_egid;
+	current->fsgid = new_egid;
+	current->egid = new_egid;
+	current->gid = new_rgid;
 	return 0;
 }
 
@@ -406,14 +421,25 @@
 	int old_egid = current->egid;
 
 	if (capable(CAP_SETGID))
+	{
+		if(old_egid != gid)
+		{
+			current->dumpable=0;
+			wmb();
+		}
 		current->gid = current->egid = current->sgid = current->fsgid = gid;
+	}
 	else if ((gid == current->gid) || (gid == current->sgid))
+	{
+		if(old_egid != gid)
+		{
+			current->dumpable=0;
+			wmb();
+		}
 		current->egid = current->fsgid = gid;
+	}
 	else
 		return -EPERM;
-
-	if (current->egid != old_egid)
-		current->dumpable = 0;
 	return 0;
 }
   
@@ -463,7 +489,7 @@
 	}
 }
 
-static int set_user(uid_t new_ruid)
+static int set_user(uid_t new_ruid, int dumpclear)
 {
 	struct user_struct *new_user, *old_user;
 
@@ -479,6 +505,11 @@
 	atomic_dec(&old_user->processes);
 	atomic_inc(&new_user->processes);
 
+	if(dumpclear)
+	{
+		current->dumpable = 0;
+		wmb();
+	}
 	current->uid = new_ruid;
 	current->user = new_user;
 	free_uid(old_user);
@@ -525,16 +556,19 @@
 			return -EPERM;
 	}
 
-	if (new_ruid != old_ruid && set_user(new_ruid) < 0)
+	if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
 		return -EAGAIN;
 
+	if (new_euid != old_euid)
+	{
+		current->dumpable=0;
+		wmb();
+	}
 	current->fsuid = current->euid = new_euid;
 	if (ruid != (uid_t) -1 ||
 	    (euid != (uid_t) -1 && euid != old_ruid))
 		current->suid = current->euid;
 	current->fsuid = current->euid;
-	if (current->euid != old_euid)
-		current->dumpable = 0;
 
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
@@ -559,21 +593,26 @@
 asmlinkage long sys_setuid(uid_t uid)
 {
 	int old_euid = current->euid;
-	int old_ruid, old_suid, new_ruid;
+	int old_ruid, old_suid, new_ruid, new_suid;
 
 	old_ruid = new_ruid = current->uid;
 	old_suid = current->suid;
+	new_suid = old_suid;
+	
 	if (capable(CAP_SETUID)) {
-		if (uid != old_ruid && set_user(uid) < 0)
+		if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
 			return -EAGAIN;
-		current->suid = uid;
-	} else if ((uid != current->uid) && (uid != current->suid))
+		new_suid = uid;
+	} else if ((uid != current->uid) && (uid != new_suid))
 		return -EPERM;
 
-	current->fsuid = current->euid = uid;
-
 	if (old_euid != uid)
+	{
 		current->dumpable = 0;
+		wmb();
+	}
+	current->fsuid = current->euid = uid;
+	current->suid = new_suid;
 
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
@@ -605,12 +644,15 @@
 			return -EPERM;
 	}
 	if (ruid != (uid_t) -1) {
-		if (ruid != current->uid && set_user(ruid) < 0)
+		if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
 			return -EAGAIN;
 	}
 	if (euid != (uid_t) -1) {
 		if (euid != current->euid)
+		{
 			current->dumpable = 0;
+			wmb();
+		}
 		current->euid = euid;
 		current->fsuid = euid;
 	}
@@ -640,7 +682,7 @@
  */
 asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 {
-       if (!capable(CAP_SETGID)) {
+	if (!capable(CAP_SETGID)) {
 		if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
 		    (rgid != current->egid) && (rgid != current->sgid))
 			return -EPERM;
@@ -651,14 +693,17 @@
 		    (sgid != current->egid) && (sgid != current->sgid))
 			return -EPERM;
 	}
-	if (rgid != (gid_t) -1)
-		current->gid = rgid;
 	if (egid != (gid_t) -1) {
 		if (egid != current->egid)
+		{
 			current->dumpable = 0;
+			wmb();
+		}
 		current->egid = egid;
 		current->fsgid = egid;
 	}
+	if (rgid != (gid_t) -1)
+		current->gid = rgid;
 	if (sgid != (gid_t) -1)
 		current->sgid = sgid;
 	return 0;
@@ -690,9 +735,14 @@
 	if (uid == current->uid || uid == current->euid ||
 	    uid == current->suid || uid == current->fsuid || 
 	    capable(CAP_SETUID))
+	{
+		if (uid != old_fsuid)
+		{
+			current->dumpable = 0;
+			wmb();
+		}
 		current->fsuid = uid;
-	if (current->fsuid != old_fsuid)
-		current->dumpable = 0;
+	}
 
 	/* We emulate fsuid by essentially doing a scaled-down version
 	 * of what we did in setresuid and friends. However, we only
@@ -727,10 +777,14 @@
 	if (gid == current->gid || gid == current->egid ||
 	    gid == current->sgid || gid == current->fsgid || 
 	    capable(CAP_SETGID))
+	{
+		if (gid != old_fsgid)
+		{
+			current->dumpable = 0;
+			wmb();
+		}
 		current->fsgid = gid;
-	if (current->fsgid != old_fsgid)
-		current->dumpable = 0;
-
+	}
 	return old_fsgid;
 }
 
diff -u --recursive --new-file v2.4.2/linux/lib/inflate.c linux/lib/inflate.c
--- v2.4.2/linux/lib/inflate.c	Fri Jan 14 17:56:38 2000
+++ linux/lib/inflate.c	Tue Mar  6 19:44:37 2001
@@ -11,7 +11,7 @@
  *   Little mods for all variable to reside either into rodata or bss segments
  *   by marking constant variables with 'const' and initializing all the others
  *   at run-time only.  This allows for the kernel uncompressor to run
- *   directly from Flash or ROM memory on embeded systems.
+ *   directly from Flash or ROM memory on embedded systems.
  */
 
 /*
diff -u --recursive --new-file v2.4.2/linux/lib/string.c linux/lib/string.c
--- v2.4.2/linux/lib/string.c	Thu Aug 10 13:10:14 2000
+++ linux/lib/string.c	Tue Mar  6 19:44:37 2001
@@ -20,6 +20,12 @@
 #include <linux/ctype.h>
 
 #ifndef __HAVE_ARCH_STRNICMP
+/**
+ * strnicmp - Case insensitive, length-limited string comparison
+ * @s1: One string
+ * @s2: The other string
+ * @len: the maximum number of characters to compare
+ */
 int strnicmp(const char *s1, const char *s2, size_t len)
 {
 	/* Yes, Virginia, it had better be unsigned */
@@ -49,6 +55,11 @@
 char * ___strtok;
 
 #ifndef __HAVE_ARCH_STRCPY
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
 char * strcpy(char * dest,const char *src)
 {
 	char *tmp = dest;
@@ -60,6 +71,16 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRNCPY
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: The maximum number of bytes to copy
+ *
+ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
+ * However, the result is not %NUL-terminated if the source exceeds
+ * @count bytes.
+ */
 char * strncpy(char * dest,const char *src,size_t count)
 {
 	char *tmp = dest;
@@ -72,6 +93,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRCAT
+/**
+ * strcat - Append one %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ */
 char * strcat(char * dest, const char * src)
 {
 	char *tmp = dest;
@@ -86,6 +112,15 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRNCAT
+/**
+ * strncat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The maximum numbers of bytes to copy
+ *
+ * Note that in contrast to strncpy, strncat ensures the result is
+ * terminated.
+ */
 char * strncat(char *dest, const char *src, size_t count)
 {
 	char *tmp = dest;
@@ -106,6 +141,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRCMP
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ */
 int strcmp(const char * cs,const char * ct)
 {
 	register signed char __res;
@@ -120,6 +160,12 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRNCMP
+/**
+ * strncmp - Compare two length-limited strings
+ * @cs: One string
+ * @ct: Another string
+ * @count: The maximum number of bytes to compare
+ */
 int strncmp(const char * cs,const char * ct,size_t count)
 {
 	register signed char __res = 0;
@@ -135,6 +181,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRCHR
+/**
+ * strchr - Find the first occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
 char * strchr(const char * s, int c)
 {
 	for(; *s != (char) c; ++s)
@@ -145,6 +196,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRRCHR
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
 char * strrchr(const char * s, int c)
 {
        const char *p = s + strlen(s);
@@ -157,6 +213,10 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRLEN
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ */
 size_t strlen(const char * s)
 {
 	const char *sc;
@@ -168,6 +228,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRNLEN
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @count: The maximum number of bytes to search
+ */
 size_t strnlen(const char * s, size_t count)
 {
 	const char *sc;
@@ -179,6 +244,12 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRSPN
+/**
+ * strspn - Calculate the length of the initial substring of @s which only
+ * 	contain letters in @accept
+ * @s: The string to be searched
+ * @accept: The string to search for
+ */
 size_t strspn(const char *s, const char *accept)
 {
 	const char *p;
@@ -200,6 +271,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRPBRK
+/**
+ * strpbrk - Find the first occurrence of a set of characters
+ * @cs: The string to be searched
+ * @ct: The characters to search for
+ */
 char * strpbrk(const char * cs,const char * ct)
 {
 	const char *sc1,*sc2;
@@ -215,6 +291,13 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRTOK
+/**
+ * strtok - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * WARNING: strtok is deprecated, use strsep instead.
+ */
 char * strtok(char * s,const char * ct)
 {
 	char *sbegin, *send;
@@ -237,7 +320,13 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRSEP
-
+/**
+ * strsep - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ *
+ * strsep() updates @s to point after the token, ready for the next call.
+ */
 char * strsep(char **s, const char * ct)
 {
 	char *sbegin=*s;
@@ -256,6 +345,12 @@
 #endif
 
 #ifndef __HAVE_ARCH_MEMSET
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @count: The size of the area.
+ */
 void * memset(void * s,int c,size_t count)
 {
 	char *xs = (char *) s;
@@ -268,6 +363,18 @@
 #endif
 
 #ifndef __HAVE_ARCH_BCOPY
+/**
+ * bcopy - Copy one area of memory to another
+ * @src: Where to copy from
+ * @dest: Where to copy to
+ * @count: The size of the area.
+ *
+ * When using copies for I/O remember that bcopy and memcpy are entitled
+ * to do out of order writes and may well exactly that.
+ *
+ * Note that this is the same as memcpy, with the arguments reversed. memcpy
+ * is the standard, bcopy is a legacy BSD function.
+ */
 char * bcopy(const char * src, char * dest, int count)
 {
 	char *tmp = dest;
@@ -280,6 +387,15 @@
 #endif
 
 #ifndef __HAVE_ARCH_MEMCPY
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * When using copies for I/O remember that bcopy and memcpy are entitled
+ * to do out of order writes and may well exactly that.
+ */
 void * memcpy(void * dest,const void *src,size_t count)
 {
 	char *tmp = (char *) dest, *s = (char *) src;
@@ -292,6 +408,14 @@
 #endif
 
 #ifndef __HAVE_ARCH_MEMMOVE
+/**
+ * memmove - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @count: The size of the area.
+ *
+ * memmove copes with overlapping areas.
+ */
 void * memmove(void * dest,const void *src,size_t count)
 {
 	char *tmp, *s;
@@ -314,6 +438,12 @@
 #endif
 
 #ifndef __HAVE_ARCH_MEMCMP
+/**
+ * memmove - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
 int memcmp(const void * cs,const void * ct,size_t count)
 {
 	const unsigned char *su1, *su2;
@@ -326,10 +456,16 @@
 }
 #endif
 
-/*
- * find the first occurrence of byte 'c', or 1 past the area if none
- */
 #ifndef __HAVE_ARCH_MEMSCAN
+/**
+ * memscan - Find a character in an area of memory.
+ * @addr: The memory area
+ * @c: The byte to search for
+ * @size: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or 1 byte past
+ * the area if @c is not found
+ */
 void * memscan(void * addr, int c, size_t size)
 {
 	unsigned char * p = (unsigned char *) addr;
@@ -345,6 +481,11 @@
 #endif
 
 #ifndef __HAVE_ARCH_STRSTR
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
 char * strstr(const char * s1,const char * s2)
 {
 	int l1, l2;
@@ -364,6 +505,15 @@
 #endif
 
 #ifndef __HAVE_ARCH_MEMCHR
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
 void *memchr(const void *s, int c, size_t n)
 {
 	const unsigned char *p = s;
diff -u --recursive --new-file v2.4.2/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.4.2/linux/lib/vsprintf.c	Mon Nov 27 17:44:26 2000
+++ linux/lib/vsprintf.c	Tue Mar  6 19:44:37 2001
@@ -16,6 +16,12 @@
 
 #include <asm/div64.h>
 
+/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
 {
 	unsigned long result = 0,value;
@@ -41,6 +47,12 @@
 	return result;
 }
 
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
 long simple_strtol(const char *cp,char **endp,unsigned int base)
 {
 	if(*cp=='-')
@@ -48,6 +60,12 @@
 	return simple_strtoul(cp,endp,base);
 }
 
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
 unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
 {
 	unsigned long long result = 0,value;
@@ -73,6 +91,12 @@
 	return result;
 }
 
+/**
+ * simple_strtoll - convert a string to a signed long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
 long long simple_strtoll(const char *cp,char **endp,unsigned int base)
 {
 	if(*cp=='-')
@@ -163,9 +187,15 @@
 	return str;
 }
 
-/* Forward decl. needed for IP address printing stuff... */
-int sprintf(char * buf, const char *fmt, ...);
-
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
 int vsprintf(char *buf, const char *fmt, va_list args)
 {
 	int len;
@@ -343,6 +373,12 @@
 	return str-buf;
 }
 
+/**
+ * sprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ */
 int sprintf(char * buf, const char *fmt, ...)
 {
 	va_list args;
diff -u --recursive --new-file v2.4.2/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.2/linux/mm/filemap.c	Wed Feb 21 18:20:46 2001
+++ linux/mm/filemap.c	Fri Mar 23 14:38:48 2001
@@ -559,7 +559,7 @@
 	if (page)
 		return 0;
 
-	page = page_cache_alloc();
+	page = page_cache_alloc(mapping);
 	if (!page)
 		return -ENOMEM;
 
@@ -659,7 +659,7 @@
 
 /*
  * a rather lightweight function, finding and getting a reference to a
- * hashed page atomically, waiting for it if it's locked.
+ * hashed page atomically.
  */
 struct page * __find_get_page(struct address_space *mapping,
 			      unsigned long offset, struct page **hash)
@@ -679,7 +679,8 @@
 }
 
 /*
- * Get the lock to a page atomically.
+ * Same as the above, but lock the page too, verifying that
+ * it's still valid once we own it.
  */
 struct page * __find_lock_page (struct address_space *mapping,
 				unsigned long offset, struct page **hash)
@@ -1174,7 +1175,7 @@
 		 */
 		if (!cached_page) {
 			spin_unlock(&pagecache_lock);
-			cached_page = page_cache_alloc();
+			cached_page = page_cache_alloc(mapping);
 			if (!cached_page) {
 				desc->error = -ENOMEM;
 				break;
@@ -1474,7 +1475,7 @@
 	 */
 	old_page = page;
 	if (no_share) {
-		struct page *new_page = page_cache_alloc();
+		struct page *new_page = alloc_page(GFP_HIGHUSER);
 
 		if (new_page) {
 			copy_user_highpage(new_page, old_page, address);
@@ -1752,7 +1753,7 @@
 	struct vm_area_struct * vma;
 	int unmapped_error, error = -EINVAL;
 
-	down(&current->mm->mmap_sem);
+	down_read(&current->mm->mmap_sem);
 	if (start & ~PAGE_MASK)
 		goto out;
 	len = (len + ~PAGE_MASK) & PAGE_MASK;
@@ -1798,7 +1799,7 @@
 		vma = vma->vm_next;
 	}
 out:
-	up(&current->mm->mmap_sem);
+	up_read(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -2097,7 +2098,7 @@
 	int unmapped_error = 0;
 	int error = -EINVAL;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 
 	if (start & ~PAGE_MASK)
 		goto out;
@@ -2148,7 +2149,7 @@
 	}
 
 out:
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -2250,7 +2251,7 @@
 	int unmapped_error = 0;
 	long error = -EINVAL;
 
-	down(&current->mm->mmap_sem);
+	down_read(&current->mm->mmap_sem);
 
 	if (start & ~PAGE_CACHE_MASK)
 		goto out;
@@ -2302,7 +2303,7 @@
 	}
 
 out:
-	up(&current->mm->mmap_sem);
+	up_read(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -2319,7 +2320,7 @@
 	page = __find_get_page(mapping, index, hash);
 	if (!page) {
 		if (!cached_page) {
-			cached_page = page_cache_alloc();
+			cached_page = page_cache_alloc(mapping);
 			if (!cached_page)
 				return ERR_PTR(-ENOMEM);
 		}
@@ -2382,7 +2383,7 @@
 	page = __find_lock_page(mapping, index, hash);
 	if (!page) {
 		if (!*cached_page) {
-			*cached_page = page_cache_alloc();
+			*cached_page = page_cache_alloc(mapping);
 			if (!*cached_page)
 				return NULL;
 		}
diff -u --recursive --new-file v2.4.2/linux/mm/memory.c linux/mm/memory.c
--- v2.4.2/linux/mm/memory.c	Wed Feb 21 18:20:46 2001
+++ linux/mm/memory.c	Thu Mar 22 09:22:15 2001
@@ -42,11 +42,11 @@
 #include <linux/smp_lock.h>
 #include <linux/swapctl.h>
 #include <linux/iobuf.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
 
 unsigned long max_mapnr;
 unsigned long num_physpages;
@@ -160,6 +160,7 @@
 	src_pgd = pgd_offset(src, address)-1;
 	dst_pgd = pgd_offset(dst, address)-1;
 	
+	spin_lock(&dst->page_table_lock);		
 	for (;;) {
 		pmd_t * src_pmd, * dst_pmd;
 
@@ -177,13 +178,11 @@
 				goto out;
 			continue;
 		}
-		if (pgd_none(*dst_pgd)) {
-			if (!pmd_alloc(dst_pgd, 0))
-				goto nomem;
-		}
-		
+
 		src_pmd = pmd_offset(src_pgd, address);
-		dst_pmd = pmd_offset(dst_pgd, address);
+		dst_pmd = pmd_alloc(dst, dst_pgd, address);
+		if (!dst_pmd)
+			goto nomem;
 
 		do {
 			pte_t * src_pte, * dst_pte;
@@ -200,13 +199,11 @@
 					goto out;
 				goto cont_copy_pmd_range;
 			}
-			if (pmd_none(*dst_pmd)) {
-				if (!pte_alloc(dst_pmd, 0))
-					goto nomem;
-			}
-			
+
 			src_pte = pte_offset(src_pmd, address);
-			dst_pte = pte_offset(dst_pmd, address);
+			dst_pte = pte_alloc(dst, dst_pmd, address);
+			if (!dst_pte)
+				goto nomem;
 
 			spin_lock(&src->page_table_lock);			
 			do {
@@ -251,14 +248,14 @@
 			dst_pmd++;
 		} while ((unsigned long)src_pmd & PMD_TABLE_MASK);
 	}
-out:
-	return 0;
-
 out_unlock:
 	spin_unlock(&src->page_table_lock);
+out:
+	spin_unlock(&dst->page_table_lock);
 	return 0;
 
 nomem:
+	spin_unlock(&dst->page_table_lock);
 	return -ENOMEM;
 }
 
@@ -377,7 +374,6 @@
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
-	spin_unlock(&mm->page_table_lock);
 	/*
 	 * Update rss for the mm_struct (not necessarily current->mm)
 	 * Notice that rss is an unsigned long.
@@ -386,6 +382,7 @@
 		mm->rss -= freed;
 	else
 		mm->rss = 0;
+	spin_unlock(&mm->page_table_lock);
 }
 
 
@@ -450,7 +447,7 @@
 	if (err)
 		return err;
 
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 
 	err = -EFAULT;
 	iobuf->locked = 0;
@@ -501,12 +498,12 @@
 		ptr += PAGE_SIZE;
 	}
 
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	dprintk ("map_user_kiobuf: end OK\n");
 	return 0;
 
  out_unlock:
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	unmap_kiobuf(iobuf);
 	dprintk ("map_user_kiobuf: end %d\n", err);
 	return err;
@@ -658,7 +655,7 @@
 	} while (address && (address < end));
 }
 
-static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address,
+static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address,
                                     unsigned long size, pgprot_t prot)
 {
 	unsigned long end;
@@ -668,7 +665,7 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	do {
-		pte_t * pte = pte_alloc(pmd, address);
+		pte_t * pte = pte_alloc(mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		zeromap_pte_range(pte, address, end - address, prot);
@@ -684,23 +681,27 @@
 	pgd_t * dir;
 	unsigned long beg = address;
 	unsigned long end = address + size;
+	struct mm_struct *mm = current->mm;
 
-	dir = pgd_offset(current->mm, address);
-	flush_cache_range(current->mm, beg, end);
+	dir = pgd_offset(mm, address);
+	flush_cache_range(mm, beg, end);
 	if (address >= end)
 		BUG();
+
+	spin_lock(&mm->page_table_lock);
 	do {
-		pmd_t *pmd = pmd_alloc(dir, address);
+		pmd_t *pmd = pmd_alloc(mm, dir, address);
 		error = -ENOMEM;
 		if (!pmd)
 			break;
-		error = zeromap_pmd_range(pmd, address, end - address, prot);
+		error = zeromap_pmd_range(mm, pmd, address, end - address, prot);
 		if (error)
 			break;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
-	flush_tlb_range(current->mm, beg, end);
+	spin_unlock(&mm->page_table_lock);
+	flush_tlb_range(mm, beg, end);
 	return error;
 }
 
@@ -733,7 +734,7 @@
 	} while (address && (address < end));
 }
 
-static inline int remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size,
+static inline int remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
 	unsigned long phys_addr, pgprot_t prot)
 {
 	unsigned long end;
@@ -744,7 +745,7 @@
 		end = PGDIR_SIZE;
 	phys_addr -= address;
 	do {
-		pte_t * pte = pte_alloc(pmd, address);
+		pte_t * pte = pte_alloc(mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_pte_range(pte, address, end - address, address + phys_addr, prot);
@@ -761,24 +762,28 @@
 	pgd_t * dir;
 	unsigned long beg = from;
 	unsigned long end = from + size;
+	struct mm_struct *mm = current->mm;
 
 	phys_addr -= from;
-	dir = pgd_offset(current->mm, from);
-	flush_cache_range(current->mm, beg, end);
+	dir = pgd_offset(mm, from);
+	flush_cache_range(mm, beg, end);
 	if (from >= end)
 		BUG();
+
+	spin_lock(&mm->page_table_lock);
 	do {
-		pmd_t *pmd = pmd_alloc(dir, from);
+		pmd_t *pmd = pmd_alloc(mm, dir, from);
 		error = -ENOMEM;
 		if (!pmd)
 			break;
-		error = remap_pmd_range(pmd, from, end - from, phys_addr + from, prot);
+		error = remap_pmd_range(mm, pmd, from, end - from, phys_addr + from, prot);
 		if (error)
 			break;
 		from = (from + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (from && (from < end));
-	flush_tlb_range(current->mm, beg, end);
+	spin_unlock(&mm->page_table_lock);
+	flush_tlb_range(mm, beg, end);
 	return error;
 }
 
@@ -787,6 +792,8 @@
  *  - flush the old one
  *  - update the page tables
  *  - inform the TLB about the new one
+ *
+ * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
  */
 static inline void establish_pte(struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t entry)
 {
@@ -795,6 +802,9 @@
 	update_mmu_cache(vma, address, entry);
 }
 
+/*
+ * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
+ */
 static inline void break_cow(struct vm_area_struct * vma, struct page *	old_page, struct page * new_page, unsigned long address, 
 		pte_t *page_table)
 {
@@ -862,7 +872,6 @@
 			break;
 		flush_cache_page(vma, address);
 		establish_pte(vma, address, page_table, pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
-		spin_unlock(&mm->page_table_lock);
 		return 1;	/* Minor fault */
 	}
 
@@ -870,10 +879,10 @@
 	 * Ok, we need to copy. Oh, well..
 	 */
 	spin_unlock(&mm->page_table_lock);
-	new_page = page_cache_alloc();
+	new_page = alloc_page(GFP_HIGHUSER);
+	spin_lock(&mm->page_table_lock);
 	if (!new_page)
 		return -1;
-	spin_lock(&mm->page_table_lock);
 
 	/*
 	 * Re-check the pte - we dropped the lock
@@ -886,12 +895,10 @@
 		/* Free the old page.. */
 		new_page = old_page;
 	}
-	spin_unlock(&mm->page_table_lock);
 	page_cache_release(new_page);
 	return 1;	/* Minor fault */
 
 bad_wp_page:
-	spin_unlock(&mm->page_table_lock);
 	printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
 	return -1;
 }
@@ -1021,63 +1028,100 @@
 	return;
 }
 
+/*
+ * We hold the mm semaphore and the page_table_lock on entry and exit.
+ */
 static int do_swap_page(struct mm_struct * mm,
 	struct vm_area_struct * vma, unsigned long address,
 	pte_t * page_table, swp_entry_t entry, int write_access)
 {
-	struct page *page = lookup_swap_cache(entry);
+	struct page *page;
 	pte_t pte;
 
+	spin_unlock(&mm->page_table_lock);
+	page = lookup_swap_cache(entry);
 	if (!page) {
 		lock_kernel();
 		swapin_readahead(entry);
 		page = read_swap_cache(entry);
 		unlock_kernel();
-		if (!page)
+		if (!page) {
+			spin_lock(&mm->page_table_lock);
 			return -1;
+		}
 
 		flush_page_to_ram(page);
 		flush_icache_page(vma, page);
 	}
 
-	mm->rss++;
-
-	pte = mk_pte(page, vma->vm_page_prot);
-
 	/*
 	 * Freeze the "shared"ness of the page, ie page_count + swap_count.
 	 * Must lock page before transferring our swap count to already
 	 * obtained page count.
 	 */
 	lock_page(page);
+
+	/*
+	 * Back out if somebody else faulted in this pte while we
+	 * released the page table lock.
+	 */
+	spin_lock(&mm->page_table_lock);
+	if (pte_present(*page_table)) {
+		UnlockPage(page);
+		page_cache_release(page);
+		return 1;
+	}
+		
+	/* The page isn't present yet, go ahead with the fault. */
+	mm->rss++;
+	pte = mk_pte(page, vma->vm_page_prot);
+
 	swap_free(entry);
 	if (write_access && !is_page_shared(page))
 		pte = pte_mkwrite(pte_mkdirty(pte));
 	UnlockPage(page);
 
 	set_pte(page_table, pte);
+
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, address, pte);
 	return 1;	/* Minor fault */
 }
 
 /*
- * This only needs the MM semaphore
+ * We are called with the MM semaphore and page_table_lock
+ * spinlock held to protect against concurrent faults in
+ * multithreaded programs. 
  */
 static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
 {
-	struct page *page = NULL;
-	pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
+	pte_t entry;
+
+	/* Read-only mapping of ZERO_PAGE. */
+	entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
+
+	/* ..except if it's a write access */
 	if (write_access) {
+		struct page *page;
+
+		/* Allocate our own private page. */
+		spin_unlock(&mm->page_table_lock);
 		page = alloc_page(GFP_HIGHUSER);
+		spin_lock(&mm->page_table_lock);
 		if (!page)
 			return -1;
-		clear_user_highpage(page, addr);
-		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+		if (!pte_none(*page_table)) {
+			page_cache_release(page);
+			return 1;
+		}
 		mm->rss++;
+		clear_user_highpage(page, addr);
 		flush_page_to_ram(page);
+		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	}
+
 	set_pte(page_table, entry);
+
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, addr, entry);
 	return 1;	/* Minor fault */
@@ -1092,7 +1136,8 @@
  * As this is called only for pages that do not currently exist, we
  * do not need to flush old virtual caches or the TLB.
  *
- * This is called with the MM semaphore held.
+ * This is called with the MM semaphore held and the page table
+ * spinlock held.
  */
 static int do_no_page(struct mm_struct * mm, struct vm_area_struct * vma,
 	unsigned long address, int write_access, pte_t *page_table)
@@ -1102,6 +1147,7 @@
 
 	if (!vma->vm_ops || !vma->vm_ops->nopage)
 		return do_anonymous_page(mm, vma, page_table, write_access, address);
+	spin_unlock(&mm->page_table_lock);
 
 	/*
 	 * The third argument is "no_share", which tells the low-level code
@@ -1109,11 +1155,12 @@
 	 * essentially an early COW detection.
 	 */
 	new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
+
+	spin_lock(&mm->page_table_lock);
 	if (new_page == NULL)	/* no page was available -- SIGBUS */
 		return 0;
 	if (new_page == NOPAGE_OOM)
 		return -1;
-	++mm->rss;
 	/*
 	 * This silly early PAGE_DIRTY setting removes a race
 	 * due to the bad i386 page protection. But it's valid
@@ -1124,15 +1171,23 @@
 	 * so we can make it writable and dirty to avoid having to
 	 * handle that later.
 	 */
-	flush_page_to_ram(new_page);
-	flush_icache_page(vma, new_page);
-	entry = mk_pte(new_page, vma->vm_page_prot);
-	if (write_access) {
-		entry = pte_mkwrite(pte_mkdirty(entry));
-	} else if (page_count(new_page) > 1 &&
-		   !(vma->vm_flags & VM_SHARED))
-		entry = pte_wrprotect(entry);
-	set_pte(page_table, entry);
+	/* Only go through if we didn't race with anybody else... */
+	if (pte_none(*page_table)) {
+		++mm->rss;
+		flush_page_to_ram(new_page);
+		flush_icache_page(vma, new_page);
+		entry = mk_pte(new_page, vma->vm_page_prot);
+		if (write_access) {
+			entry = pte_mkwrite(pte_mkdirty(entry));
+		} else if (page_count(new_page) > 1 &&
+			   !(vma->vm_flags & VM_SHARED))
+			entry = pte_wrprotect(entry);
+		set_pte(page_table, entry);
+	} else {
+		/* One of our sibling threads was faster, back out. */
+		page_cache_release(new_page);
+	}
+
 	/* no need to invalidate: a not-present page shouldn't be cached */
 	update_mmu_cache(vma, address, entry);
 	return 2;	/* Major fault */
@@ -1162,11 +1217,6 @@
 {
 	pte_t entry;
 
-	/*
-	 * We need the page table lock to synchronize with kswapd
-	 * and the SMP-safe atomic PTE updates.
-	 */
-	spin_lock(&mm->page_table_lock);
 	entry = *pte;
 	if (!pte_present(entry)) {
 		/*
@@ -1174,7 +1224,6 @@
 		 * and the PTE updates will not touch it later. So
 		 * drop the lock.
 		 */
-		spin_unlock(&mm->page_table_lock);
 		if (pte_none(entry))
 			return do_no_page(mm, vma, address, write_access, pte);
 		return do_swap_page(mm, vma, address, pte, pte_to_swp_entry(entry), write_access);
@@ -1188,7 +1237,6 @@
 	}
 	entry = pte_mkyoung(entry);
 	establish_pte(vma, address, pte, entry);
-	spin_unlock(&mm->page_table_lock);
 	return 1;
 }
 
@@ -1204,14 +1252,92 @@
 
 	current->state = TASK_RUNNING;
 	pgd = pgd_offset(mm, address);
-	pmd = pmd_alloc(pgd, address);
+
+	/*
+	 * We need the page table lock to synchronize with kswapd
+	 * and the SMP-safe atomic PTE updates.
+	 */
+	spin_lock(&mm->page_table_lock);
+	pmd = pmd_alloc(mm, pgd, address);
 
 	if (pmd) {
-		pte_t * pte = pte_alloc(pmd, address);
+		pte_t * pte = pte_alloc(mm, pmd, address);
 		if (pte)
 			ret = handle_pte_fault(mm, vma, address, write_access, pte);
 	}
+	spin_unlock(&mm->page_table_lock);
 	return ret;
+}
+
+/*
+ * Allocate page middle directory.
+ *
+ * We've already handled the fast-path in-line, and we own the
+ * page table lock.
+ *
+ * On a two-level page table, this ends up actually being entirely
+ * optimized away.
+ */
+pmd_t *__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
+{
+	pmd_t *new;
+
+	/* "fast" allocation can happen without dropping the lock.. */
+	new = pmd_alloc_one_fast();
+	if (!new) {
+		spin_unlock(&mm->page_table_lock);
+		new = pmd_alloc_one();
+		spin_lock(&mm->page_table_lock);
+		if (!new)
+			return NULL;
+
+		/*
+		 * Because we dropped the lock, we should re-check the
+		 * entry, as somebody else could have populated it..
+		 */
+		if (pgd_present(*pgd)) {
+			pmd_free(new);
+			goto out;
+		}
+	}
+	pgd_populate(pgd, new);
+out:
+	return pmd_offset(pgd, address);
+}
+
+/*
+ * Allocate the page table directory.
+ *
+ * We've already handled the fast-path in-line, and we own the
+ * page table lock.
+ */
+pte_t *pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
+{
+	if (!pmd_present(*pmd)) {
+		pte_t *new;
+
+		/* "fast" allocation can happen without dropping the lock.. */
+		new = pte_alloc_one_fast();
+		if (!new) {
+			spin_unlock(&mm->page_table_lock);
+			new = pte_alloc_one();
+			spin_lock(&mm->page_table_lock);
+			if (!new)
+				return NULL;
+
+			/*
+			 * Because we dropped the lock, we should re-check the
+			 * entry, as somebody else could have populated it..
+			 */
+			if (pmd_present(*pmd)) {
+				pte_free(new);
+				goto out;
+			}
+		}
+		pmd_populate(pmd, new);
+	}
+out:
+	return pte_offset(pmd, address);
 }
 
 /*
diff -u --recursive --new-file v2.4.2/linux/mm/mlock.c linux/mm/mlock.c
--- v2.4.2/linux/mm/mlock.c	Fri Dec 29 14:07:24 2000
+++ linux/mm/mlock.c	Mon Mar 19 12:35:08 2001
@@ -198,7 +198,7 @@
 	unsigned long lock_limit;
 	int error = -ENOMEM;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 	start &= PAGE_MASK;
 
@@ -219,7 +219,7 @@
 
 	error = do_mlock(start, len, 1);
 out:
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return error;
 }
 
@@ -227,11 +227,11 @@
 {
 	int ret;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 	start &= PAGE_MASK;
 	ret = do_mlock(start, len, 0);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return ret;
 }
 
@@ -268,7 +268,7 @@
 	unsigned long lock_limit;
 	int ret = -EINVAL;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 		goto out;
 
@@ -286,7 +286,7 @@
 
 	ret = do_mlockall(flags);
 out:
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return ret;
 }
 
@@ -294,8 +294,8 @@
 {
 	int ret;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	ret = do_mlockall(0);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return ret;
 }
diff -u --recursive --new-file v2.4.2/linux/mm/mmap.c linux/mm/mmap.c
--- v2.4.2/linux/mm/mmap.c	Wed Feb 21 18:20:46 2001
+++ linux/mm/mmap.c	Fri Mar 23 18:50:53 2001
@@ -133,7 +133,7 @@
 	unsigned long newbrk, oldbrk;
 	struct mm_struct *mm = current->mm;
 
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 
 	if (brk < mm->end_code)
 		goto out;
@@ -169,7 +169,7 @@
 	mm->brk = brk;
 out:
 	retval = mm->brk;
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	return retval;
 }
 
@@ -177,7 +177,7 @@
  * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
  * into "VM_xxx".
  */
-static inline unsigned long vm_flags(unsigned long prot, unsigned long flags)
+static inline unsigned long calc_vm_flags(unsigned long prot, unsigned long flags)
 {
 #define _trans(x,bit1,bit2) \
 ((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
@@ -200,12 +200,10 @@
 {
 	struct mm_struct * mm = current->mm;
 	struct vm_area_struct * vma;
+	unsigned int vm_flags;
 	int correct_wcount = 0;
 	int error;
 
-	if (file && (!file->f_op || !file->f_op->mmap))
-		return -ENODEV;
-
 	if ((len = PAGE_ALIGN(len)) == 0)
 		return addr;
 
@@ -220,19 +218,36 @@
 	if (mm->map_count > MAX_MAP_COUNT)
 		return -ENOMEM;
 
+	/* Obtain the address to map to. we verify (or select) it and ensure
+	 * that it represents a valid section of the address space.
+	 */
+	if (flags & MAP_FIXED) {
+		if (addr & ~PAGE_MASK)
+			return -EINVAL;
+	} else {
+		addr = get_unmapped_area(addr, len);
+		if (!addr)
+			return -ENOMEM;
+	}
+
+	/* Do simple checking here so the lower-level routines won't have
+	 * to. we assume access permissions have been handled by the open
+	 * of the memory object, so we don't do any here.
+	 */
+	vm_flags = calc_vm_flags(prot,flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+
 	/* mlock MCL_FUTURE? */
-	if (mm->def_flags & VM_LOCKED) {
+	if (vm_flags & VM_LOCKED) {
 		unsigned long locked = mm->locked_vm << PAGE_SHIFT;
 		locked += len;
 		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
 			return -EAGAIN;
 	}
 
-	/* Do simple checking here so the lower-level routines won't have
-	 * to. we assume access permissions have been handled by the open
-	 * of the memory object, so we don't do any here.
-	 */
-	if (file != NULL) {
+	if (file) {
+		if (!file->f_op || !file->f_op->mmap)
+			return -ENODEV;
+
 		switch (flags & MAP_TYPE) {
 		case MAP_SHARED:
 			if ((prot & PROT_WRITE) && !(file->f_mode & FMODE_WRITE))
@@ -246,6 +261,10 @@
 			if (locks_verify_locked(file->f_dentry->d_inode))
 				return -EAGAIN;
 
+			vm_flags |= VM_SHARED | VM_MAYSHARE;
+			if (!(file->f_mode & FMODE_WRITE))
+				vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
+
 			/* fall through */
 		case MAP_PRIVATE:
 			if (!(file->f_mode & FMODE_READ))
@@ -255,18 +274,43 @@
 		default:
 			return -EINVAL;
 		}
+	} else {
+		vm_flags |= VM_SHARED | VM_MAYSHARE;
+		switch (flags & MAP_TYPE) {
+		default:
+			return -EINVAL;
+		case MAP_PRIVATE:
+			vm_flags &= ~(VM_SHARED | VM_MAYSHARE);
+			/* fall through */
+		case MAP_SHARED:
+			break;
+		}
 	}
 
-	/* Obtain the address to map to. we verify (or select) it and ensure
-	 * that it represents a valid section of the address space.
-	 */
-	if (flags & MAP_FIXED) {
-		if (addr & ~PAGE_MASK)
-			return -EINVAL;
-	} else {
-		addr = get_unmapped_area(addr, len);
-		if (!addr)
-			return -ENOMEM;
+	/* Clear old maps */
+	error = -ENOMEM;
+	if (do_munmap(mm, addr, len))
+		return -ENOMEM;
+
+	/* Check against address space limit. */
+	if ((mm->total_vm << PAGE_SHIFT) + len
+	    > current->rlim[RLIMIT_AS].rlim_cur)
+		return -ENOMEM;
+
+	/* Private writable mapping? Check memory availability.. */
+	if ((vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
+	    !(flags & MAP_NORESERVE)				 &&
+	    !vm_enough_memory(len >> PAGE_SHIFT))
+		return -ENOMEM;
+
+	/* Can we just expand an old anonymous mapping? */
+	if (addr && !file && !(vm_flags & VM_SHARED)) {
+		struct vm_area_struct * vma = find_vma(mm, addr-1);
+		if (vma && vma->vm_end == addr && !vma->vm_file && 
+		    vma->vm_flags == vm_flags) {
+			vma->vm_end = addr + len;
+			goto out;
+		}
 	}
 
 	/* Determine the object being mapped and call the appropriate
@@ -280,58 +324,16 @@
 	vma->vm_mm = mm;
 	vma->vm_start = addr;
 	vma->vm_end = addr + len;
-	vma->vm_flags = vm_flags(prot,flags) | mm->def_flags;
-
-	if (file) {
-		VM_ClearReadHint(vma);
-		vma->vm_raend = 0;
-
-		if (file->f_mode & FMODE_READ)
-			vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
-		if (flags & MAP_SHARED) {
-			vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
-
-			/* This looks strange, but when we don't have the file open
-			 * for writing, we can demote the shared mapping to a simpler
-			 * private mapping. That also takes care of a security hole
-			 * with ptrace() writing to a shared mapping without write
-			 * permissions.
-			 *
-			 * We leave the VM_MAYSHARE bit on, just to get correct output
-			 * from /proc/xxx/maps..
-			 */
-			if (!(file->f_mode & FMODE_WRITE))
-				vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
-		}
-	} else {
-		vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
-		if (flags & MAP_SHARED)
-			vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
-	}
-	vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
+	vma->vm_flags = vm_flags;
+	vma->vm_page_prot = protection_map[vm_flags & 0x0f];
 	vma->vm_ops = NULL;
 	vma->vm_pgoff = pgoff;
 	vma->vm_file = NULL;
 	vma->vm_private_data = NULL;
-
-	/* Clear old maps */
-	error = -ENOMEM;
-	if (do_munmap(mm, addr, len))
-		goto free_vma;
-
-	/* Check against address space limit. */
-	if ((mm->total_vm << PAGE_SHIFT) + len
-	    > current->rlim[RLIMIT_AS].rlim_cur)
-		goto free_vma;
-
-	/* Private writable mapping? Check memory availability.. */
-	if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
-	    !(flags & MAP_NORESERVE)				 &&
-	    !vm_enough_memory(len >> PAGE_SHIFT))
-		goto free_vma;
+	vma->vm_raend = 0;
 
 	if (file) {
-		if (vma->vm_flags & VM_DENYWRITE) {
+		if (vm_flags & VM_DENYWRITE) {
 			error = deny_write_access(file);
 			if (error)
 				goto free_vma;
@@ -353,15 +355,15 @@
 	 * Answer: Yes, several device drivers can do it in their
 	 *         f_op->mmap method. -DaveM
 	 */
-	flags = vma->vm_flags;
 	addr = vma->vm_start;
 
 	insert_vm_struct(mm, vma);
 	if (correct_wcount)
 		atomic_inc(&file->f_dentry->d_inode->i_writecount);
-	
+
+out:	
 	mm->total_vm += len >> PAGE_SHIFT;
-	if (flags & VM_LOCKED) {
+	if (vm_flags & VM_LOCKED) {
 		mm->locked_vm += len >> PAGE_SHIFT;
 		make_pages_present(addr, addr + len);
 	}
@@ -776,9 +778,9 @@
 	int ret;
 	struct mm_struct *mm = current->mm;
 
-	down(&mm->mmap_sem);
+	down_write(&mm->mmap_sem);
 	ret = do_munmap(mm, addr, len);
-	up(&mm->mmap_sem);
+	up_write(&mm->mmap_sem);
 	return ret;
 }
 
@@ -825,12 +827,11 @@
 	if (!vm_enough_memory(len >> PAGE_SHIFT))
 		return -ENOMEM;
 
-	flags = vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC,
+	flags = calc_vm_flags(PROT_READ|PROT_WRITE|PROT_EXEC,
 				MAP_FIXED|MAP_PRIVATE) | mm->def_flags;
 
 	flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 	
-
 	/* Can we just expand an old anonymous mapping? */
 	if (addr) {
 		struct vm_area_struct * vma = find_vma(mm, addr-1);
@@ -841,7 +842,6 @@
 		}
 	}	
 
-
 	/*
 	 * create a vma struct for an anonymous mapping
 	 */
@@ -889,8 +889,8 @@
 	spin_lock(&mm->page_table_lock);
 	mpnt = mm->mmap;
 	mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
-	spin_unlock(&mm->page_table_lock);
 	mm->rss = 0;
+	spin_unlock(&mm->page_table_lock);
 	mm->total_vm = 0;
 	mm->locked_vm = 0;
 
diff -u --recursive --new-file v2.4.2/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.4.2/linux/mm/mprotect.c	Fri Dec 29 14:07:24 2000
+++ linux/mm/mprotect.c	Mon Mar 19 12:35:08 2001
@@ -242,7 +242,8 @@
 	if (end == start)
 		return 0;
 
-	down(&current->mm->mmap_sem);
+	/* XXX: maybe this could be down_read ??? - Rik */
+	down_write(&current->mm->mmap_sem);
 
 	vma = find_vma(current->mm, start);
 	error = -EFAULT;
@@ -278,6 +279,6 @@
 		}
 	}
 out:
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return error;
 }
diff -u --recursive --new-file v2.4.2/linux/mm/mremap.c linux/mm/mremap.c
--- v2.4.2/linux/mm/mremap.c	Fri Dec 29 14:07:24 2000
+++ linux/mm/mremap.c	Mon Mar 19 17:17:43 2001
@@ -51,9 +51,9 @@
 	pmd_t * pmd;
 	pte_t * pte = NULL;
 
-	pmd = pmd_alloc(pgd_offset(mm, addr), addr);
+	pmd = pmd_alloc(mm, pgd_offset(mm, addr), addr);
 	if (pmd)
-		pte = pte_alloc(pmd, addr);
+		pte = pte_alloc(mm, pmd, addr);
 	return pte;
 }
 
@@ -62,7 +62,6 @@
 	int error = 0;
 	pte_t pte;
 
-	spin_lock(&mm->page_table_lock);
 	if (!pte_none(*src)) {
 		pte = ptep_get_and_clear(src);
 		if (!dst) {
@@ -72,7 +71,6 @@
 		}
 		set_pte(dst, pte);
 	}
-	spin_unlock(&mm->page_table_lock);
 	return error;
 }
 
@@ -81,9 +79,11 @@
 	int error = 0;
 	pte_t * src;
 
+	spin_lock(&mm->page_table_lock);
 	src = get_one_pte(mm, old_addr);
 	if (src)
 		error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr));
+	spin_unlock(&mm->page_table_lock);
 	return error;
 }
 
@@ -292,8 +292,8 @@
 {
 	unsigned long ret;
 
-	down(&current->mm->mmap_sem);
+	down_write(&current->mm->mmap_sem);
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
-	up(&current->mm->mmap_sem);
+	up_write(&current->mm->mmap_sem);
 	return ret;
 }
diff -u --recursive --new-file v2.4.2/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.4.2/linux/mm/page_alloc.c	Sat Feb  3 19:51:32 2001
+++ linux/mm/page_alloc.c	Tue Mar 20 15:05:46 2001
@@ -455,8 +455,7 @@
 			memory_pressure++;
 			try_to_free_pages(gfp_mask);
 			wakeup_bdflush(0);
-			if (!order)
-				goto try_again;
+			goto try_again;
 		}
 	}
 
diff -u --recursive --new-file v2.4.2/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.2/linux/mm/shmem.c	Sat Feb  3 19:51:32 2001
+++ linux/mm/shmem.c	Fri Mar  2 15:16:59 2001
@@ -321,7 +321,7 @@
 		inode->i_sb->u.shmem_sb.free_blocks--;
 		spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
 		/* Ok, get a new page */
-		page = page_cache_alloc();
+		page = page_cache_alloc(mapping);
 		if (!page)
 			goto oom;
 		clear_user_highpage(page, address);
@@ -338,7 +338,7 @@
 	up(&inode->i_sem);
 
 	if (no_share) {
-		struct page *new_page = page_cache_alloc();
+		struct page *new_page = page_cache_alloc(inode->i_mapping);
 
 		if (new_page) {
 			copy_user_highpage(new_page, page, address);
diff -u --recursive --new-file v2.4.2/linux/mm/slab.c linux/mm/slab.c
--- v2.4.2/linux/mm/slab.c	Sat Feb  3 19:51:32 2001
+++ linux/mm/slab.c	Fri Mar  2 11:29:39 2001
@@ -814,28 +814,6 @@
 	return cachep;
 }
 
-/*
- * This check if the kmem_cache_t pointer is chained in the cache_cache
- * list. -arca
- */
-static int is_chained_kmem_cache(kmem_cache_t * cachep)
-{
-	struct list_head *p;
-	int ret = 0;
-
-	/* Find the cache in the chain of caches. */
-	down(&cache_chain_sem);
-	list_for_each(p, &cache_chain) {
-		if (p == &cachep->next) {
-			ret = 1;
-			break;
-		}
-	}
-	up(&cache_chain_sem);
-
-	return ret;
-}
-
 #ifdef CONFIG_SMP
 /*
  * Waits for all CPUs to execute func().
@@ -938,7 +916,7 @@
  */
 int kmem_cache_shrink(kmem_cache_t *cachep)
 {
-	if (!cachep || in_interrupt() || !is_chained_kmem_cache(cachep))
+	if (!cachep || in_interrupt())
 		BUG();
 
 	return __kmem_cache_shrink(cachep);
diff -u --recursive --new-file v2.4.2/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.4.2/linux/mm/swapfile.c	Wed Feb 21 18:20:46 2001
+++ linux/mm/swapfile.c	Thu Mar 22 09:22:15 2001
@@ -209,6 +209,7 @@
  * share this swap entry, so be cautious and let do_wp_page work out
  * what to do if a write is requested later.
  */
+/* tasklist_lock and vma->vm_mm->page_table_lock are held */
 static inline void unuse_pte(struct vm_area_struct * vma, unsigned long address,
 	pte_t *dir, swp_entry_t entry, struct page* page)
 {
@@ -234,6 +235,7 @@
 	++vma->vm_mm->rss;
 }
 
+/* tasklist_lock and vma->vm_mm->page_table_lock are held */
 static inline void unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
 	unsigned long address, unsigned long size, unsigned long offset,
 	swp_entry_t entry, struct page* page)
@@ -261,6 +263,7 @@
 	} while (address && (address < end));
 }
 
+/* tasklist_lock and vma->vm_mm->page_table_lock are held */
 static inline void unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
 	unsigned long address, unsigned long size,
 	swp_entry_t entry, struct page* page)
@@ -291,6 +294,7 @@
 	} while (address && (address < end));
 }
 
+/* tasklist_lock and vma->vm_mm->page_table_lock are held */
 static void unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
 			swp_entry_t entry, struct page* page)
 {
diff -u --recursive --new-file v2.4.2/linux/mm/vmalloc.c linux/mm/vmalloc.c
--- v2.4.2/linux/mm/vmalloc.c	Wed Feb 21 18:20:46 2001
+++ linux/mm/vmalloc.c	Fri Mar 23 16:14:00 2001
@@ -102,9 +102,11 @@
 		end = PMD_SIZE;
 	do {
 		struct page * page;
+		spin_unlock(&init_mm.page_table_lock);
+		page = alloc_page(gfp_mask);
+		spin_lock(&init_mm.page_table_lock);
 		if (!pte_none(*pte))
 			printk(KERN_ERR "alloc_area_pte: page already exists\n");
-		page = alloc_page(gfp_mask);
 		if (!page)
 			return -ENOMEM;
 		set_pte(pte, mk_pte(page, prot));
@@ -123,7 +125,7 @@
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		if (alloc_area_pte(pte, address, end - address, gfp_mask, prot))
@@ -143,11 +145,11 @@
 
 	dir = pgd_offset_k(address);
 	flush_cache_all();
-	lock_kernel();
+	spin_lock(&init_mm.page_table_lock);
 	do {
 		pmd_t *pmd;
 		
-		pmd = pmd_alloc_kernel(dir, address);
+		pmd = pmd_alloc(&init_mm, dir, address);
 		ret = -ENOMEM;
 		if (!pmd)
 			break;
@@ -161,7 +163,7 @@
 
 		ret = 0;
 	} while (address && (address < end));
-	unlock_kernel();
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
 	return ret;
 }
diff -u --recursive --new-file v2.4.2/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.4.2/linux/mm/vmscan.c	Sat Feb  3 19:51:32 2001
+++ linux/mm/vmscan.c	Thu Mar 22 11:00:51 2001
@@ -25,16 +25,15 @@
 #include <asm/pgalloc.h>
 
 /*
- * The swap-out functions return 1 if they successfully
- * threw something out, and we got a free page. It returns
- * zero if it couldn't do anything, and any other value
- * indicates it decreased rss, but the page was shared.
+ * The swap-out function returns 1 if it successfully
+ * scanned all the pages it was asked to (`count').
+ * It returns zero if it couldn't do anything,
  *
- * NOTE! If it sleeps, it *must* return 1 to make sure we
- * don't continue with the swap-out. Otherwise we may be
- * using a process that no longer actually exists (it might
- * have died while we slept).
+ * rss may decrease because pages are shared, but this
+ * doesn't count as having freed a page.
  */
+
+/* mm->page_table_lock is held. mmap_sem is not held */
 static void try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page)
 {
 	pte_t pte;
@@ -129,6 +128,7 @@
 	return;
 }
 
+/* mm->page_table_lock is held. mmap_sem is not held */
 static int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count)
 {
 	pte_t * pte;
@@ -165,6 +165,7 @@
 	return count;
 }
 
+/* mm->page_table_lock is held. mmap_sem is not held */
 static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count)
 {
 	pmd_t * pmd;
@@ -194,6 +195,7 @@
 	return count;
 }
 
+/* mm->page_table_lock is held. mmap_sem is not held */
 static int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count)
 {
 	pgd_t *pgdir;
@@ -218,6 +220,9 @@
 	return count;
 }
 
+/*
+ * Returns non-zero if we scanned all `count' pages
+ */
 static int swap_out_mm(struct mm_struct * mm, int count)
 {
 	unsigned long address;
diff -u --recursive --new-file v2.4.2/linux/net/Config.in linux/net/Config.in
--- v2.4.2/linux/net/Config.in	Wed Feb 21 18:20:47 2001
+++ linux/net/Config.in	Tue Mar  6 22:44:15 2001
@@ -81,7 +81,7 @@
 
 mainmenu_option next_comment
 comment 'QoS and/or fair queueing'
-bool 'QoS and/or fair queueing (EXPERIMENTAL)' CONFIG_NET_SCHED
+bool 'QoS and/or fair queueing' CONFIG_NET_SCHED
 if [ "$CONFIG_NET_SCHED" = "y" ]; then
    source net/sched/Config.in
 fi
diff -u --recursive --new-file v2.4.2/linux/net/atm/lec.c linux/net/atm/lec.c
--- v2.4.2/linux/net/atm/lec.c	Sat Feb  3 19:51:33 2001
+++ linux/net/atm/lec.c	Tue Mar  6 19:28:33 2001
@@ -51,9 +51,9 @@
 #define DPRINTK(format,args...)
 #endif
 
-struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
+extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
 	unsigned char *addr);
-void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
 
 
 #define DUMP_PACKETS 0 /* 0 = None,
diff -u --recursive --new-file v2.4.2/linux/net/core/dev.c linux/net/core/dev.c
--- v2.4.2/linux/net/core/dev.c	Mon Dec 11 13:29:35 2000
+++ linux/net/core/dev.c	Fri Mar  2 11:02:15 2001
@@ -349,7 +349,7 @@
 /*
  * Saves at boot time configured settings for any netdevice.
  */
-static int __init netdev_boot_setup(char *str)
+int __init netdev_boot_setup(char *str)
 {
 	int ints[5];
 	struct ifmap map;
@@ -359,7 +359,7 @@
 		return 0;
 
 	/* Save settings */
-	memset(&map, -1, sizeof(map));
+	memset(&map, 0, sizeof(map));
 	if (ints[0] > 0)
 		map.irq = ints[1];
 	if (ints[0] > 1)
diff -u --recursive --new-file v2.4.2/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v2.4.2/linux/net/ethernet/eth.c	Tue Aug 22 08:59:00 2000
+++ linux/net/ethernet/eth.c	Fri Mar  2 11:02:15 2001
@@ -30,6 +30,7 @@
  *		Alan Cox	: Protect against forwarding explosions with
  *				  older network drivers and IFF_ALLMULTI.
  *	Christer Weinigel	: Better rebuild header message.
+ *             Andrew Morton    : 26Feb01: kill ether_setup() - use netdev_boot_setup().
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -60,31 +61,9 @@
 #include <asm/system.h>
 #include <asm/checksum.h>
 
-static int __init eth_setup(char *str)
-{
-	int ints[5];
-	struct ifmap map;
+extern int __init netdev_boot_setup(char *str);
 
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	if (!str || !*str)
-		return 0;
-
- 	/* Save settings */
- 	memset(&map, -1, sizeof(map));
-	if (ints[0] > 0)
-		map.irq = ints[1];
-	if (ints[0] > 1)
-		map.base_addr = ints[2];
-	if (ints[0] > 2)
-		map.mem_start = ints[3];
-	if (ints[0] > 3)
-		map.mem_end = ints[4];
-
-	/* Add new entry to the list */
-	return netdev_boot_setup_add(str, &map);
-}
-
-__setup("ether=", eth_setup);
+__setup("ether=", netdev_boot_setup);
 
 /*
  *	 Create the Ethernet MAC header for an arbitrary protocol layer 
diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- v2.4.2/linux/net/ipv4/netfilter/Config.in	Sat Feb  3 19:51:33 2001
+++ linux/net/ipv4/netfilter/Config.in	Tue Mar  6 22:44:16 2001
@@ -20,6 +20,7 @@
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
   if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
     dep_tristate '  Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES 
   fi
@@ -45,7 +46,7 @@
       # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y), 
       # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker.  Argh.
       if [ "$CONFIG_IP_NF_FTP" = "m" ]; then
-        define_tristate CONFIG_IP_NF_NAT_FTP m
+	define_tristate CONFIG_IP_NF_NAT_FTP m
       else
         if [ "$CONFIG_IP_NF_FTP" = "y" ]; then
           define_tristate CONFIG_IP_NF_NAT_FTP $CONFIG_IP_NF_NAT
@@ -60,6 +61,7 @@
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
 fi
 
 # Backwards compatibility modules: only if you don't build in the others.
diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
--- v2.4.2/linux/net/ipv4/netfilter/Makefile	Sat Feb  3 19:51:33 2001
+++ linux/net/ipv4/netfilter/Makefile	Tue Mar  6 22:44:16 2001
@@ -54,6 +54,7 @@
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
+obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
@@ -63,6 +64,7 @@
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 
 # backwards compatibility 
 obj-$(CONFIG_IP_NF_COMPAT_IPCHAINS) += ipchains.o
diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/ipt_TCPMSS.c linux/net/ipv4/netfilter/ipt_TCPMSS.c
--- v2.4.2/linux/net/ipv4/netfilter/ipt_TCPMSS.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_TCPMSS.c	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,245 @@
+/*
+ * This is a module which is used for setting the MSS option in TCP packets.
+ *
+ * Copyright (c) 2000 Marc Boucher
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/ip.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_TCPMSS.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+static u_int16_t
+cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
+{
+	u_int32_t diffs[] = { oldvalinv, newval };
+	return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
+                                      oldcheck^0xFFFF));
+}
+
+static inline unsigned int
+optlen(const u_int8_t *opt, unsigned int offset)
+{
+	/* Beware zero-length options: make finite progress */
+	if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0) return 1;
+	else return opt[offset+1];
+}
+
+static unsigned int
+ipt_tcpmss_target(struct sk_buff **pskb,
+		  unsigned int hooknum,
+		  const struct net_device *in,
+		  const struct net_device *out,
+		  const void *targinfo,
+		  void *userinfo)
+{
+	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
+	struct tcphdr *tcph;
+	struct iphdr *iph = (*pskb)->nh.iph;
+	u_int16_t tcplen, newtotlen, oldval, newmss;
+	unsigned int i;
+	u_int8_t *opt;
+
+	tcplen = (*pskb)->len - iph->ihl*4;
+
+	tcph = (void *)iph + iph->ihl*4;
+
+	/* Since it passed flags test in tcp match, we know it is is
+	   not a fragment, and has data >= tcp header length.  SYN
+	   packets should not contain data: if they did, then we risk
+	   running over MTU, sending Frag Needed and breaking things
+	   badly. --RR */
+	if (tcplen != tcph->doff*4) {
+		if (net_ratelimit())
+			printk(KERN_ERR
+			       "ipt_tcpmss_target: bad length (%d bytes)\n",
+			       (*pskb)->len);
+		return NF_DROP;
+	}
+
+	if(tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) {
+		if(!(*pskb)->dst) {
+			if (net_ratelimit())
+				printk(KERN_ERR
+			       		"ipt_tcpmss_target: no dst?! can't determine path-MTU\n");
+			return NF_DROP; /* or IPT_CONTINUE ?? */
+		}
+
+		if((*pskb)->dst->pmtu <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
+			if (net_ratelimit())
+				printk(KERN_ERR
+		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", (*pskb)->dst->pmtu);
+			return NF_DROP; /* or IPT_CONTINUE ?? */
+		}
+
+		newmss = (*pskb)->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
+	} else
+		newmss = tcpmssinfo->mss;
+
+ 	opt = (u_int8_t *)tcph;
+	for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)){
+		if ((opt[i] == TCPOPT_MSS) &&
+		    ((tcph->doff*4 - i) >= TCPOLEN_MSS) &&
+		    (opt[i+1] == TCPOLEN_MSS)) {
+			u_int16_t oldmss;
+
+			oldmss = (opt[i+2] << 8) | opt[i+3];
+
+			if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) &&
+				(oldmss <= newmss))
+					return IPT_CONTINUE;
+
+			opt[i+2] = (newmss & 0xff00) >> 8;
+			opt[i+3] = (newmss & 0x00ff);
+
+			tcph->check = cheat_check(htons(oldmss)^0xFFFF,
+						  htons(newmss),
+						  tcph->check);
+
+			DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
+			       "->%u.%u.%u.%u:%hu changed TCP MSS option"
+			       " (from %u to %u)\n", 
+			       NIPQUAD((*pskb)->nh.iph->saddr),
+			       ntohs(tcph->source),
+			       NIPQUAD((*pskb)->nh.iph->daddr),
+			       ntohs(tcph->dest),
+			       oldmss, newmss);
+			goto retmodified;
+		}
+	}
+
+	/*
+	 * MSS Option not found ?! add it..
+	 */
+	if (skb_tailroom((*pskb)) < TCPOLEN_MSS) {
+		struct sk_buff *newskb;
+
+		newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
+					 TCPOLEN_MSS, GFP_ATOMIC);
+		if (!newskb) {
+			if (net_ratelimit())
+				printk(KERN_ERR "ipt_tcpmss_target:"
+				       " unable to allocate larger skb\n");
+			return NF_DROP;
+		}
+
+		kfree_skb(*pskb);
+		*pskb = newskb;
+		iph = (*pskb)->nh.iph;
+		tcph = (void *)iph + iph->ihl*4;
+	}
+
+	skb_put((*pskb), TCPOLEN_MSS);
+
+ 	opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
+	memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+
+	tcph->check = cheat_check(htons(tcplen) ^ 0xFFFF,
+				  htons(tcplen + TCPOLEN_MSS), tcph->check);
+	tcplen += TCPOLEN_MSS;
+
+	opt[0] = TCPOPT_MSS;
+	opt[1] = TCPOLEN_MSS;
+	opt[2] = (newmss & 0xff00) >> 8;
+	opt[3] = (newmss & 0x00ff);
+
+	tcph->check = cheat_check(~0, *((u_int32_t *)opt), tcph->check);
+
+	oldval = ((u_int16_t *)tcph)[6];
+	tcph->doff += TCPOLEN_MSS/4;
+	tcph->check = cheat_check(oldval ^ 0xFFFF,
+				  ((u_int16_t *)tcph)[6], tcph->check);
+
+	newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
+	iph->check = cheat_check(iph->tot_len ^ 0xFFFF,
+				 newtotlen, iph->check);
+	iph->tot_len = newtotlen;
+
+	DEBUGP(KERN_INFO "ipt_tcpmss_target: %u.%u.%u.%u:%hu"
+	       "->%u.%u.%u.%u:%hu added TCP MSS option (%u)\n",
+	       NIPQUAD((*pskb)->nh.iph->saddr),
+	       ntohs(tcph->source),
+	       NIPQUAD((*pskb)->nh.iph->daddr),
+	       ntohs(tcph->dest),
+	       newmss);
+
+ retmodified:
+	/* If we had a hardware checksum before, it's now invalid */
+	(*pskb)->ip_summed = CHECKSUM_NONE;
+	(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
+	return IPT_CONTINUE;
+}
+
+#define TH_SYN 0x02
+
+static inline int find_syn_match(const struct ipt_entry_match *m)
+{
+	const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
+
+	if (strcmp(m->u.kernel.match->name, "tcp") == 0
+	    && (tcpinfo->flg_cmp & TH_SYN)
+	    && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
+		return 1;
+
+	return 0;
+}
+
+/* Must specify -p tcp --syn/--tcp-flags SYN */
+static int
+ipt_tcpmss_checkentry(const char *tablename,
+		      const struct ipt_entry *e,
+		      void *targinfo,
+		      unsigned int targinfosize,
+		      unsigned int hook_mask)
+{
+	const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
+		DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
+		       targinfosize, IPT_ALIGN(sizeof(struct ipt_tcpmss_info)));
+		return 0;
+	}
+
+
+	if((tcpmssinfo->mss == IPT_TCPMSS_CLAMP_PMTU) && 
+			((hook_mask & ~((1 << NF_IP_FORWARD)
+			   	| (1 << NF_IP_LOCAL_OUT)
+			   	| (1 << NF_IP_POST_ROUTING))) != 0)) {
+		printk("TCPMSS: path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
+		return 0;
+	}
+
+	if (e->ip.proto == IPPROTO_TCP
+	    && !(e->ip.invflags & IPT_INV_PROTO)
+	    && IPT_MATCH_ITERATE(e, find_syn_match))
+		return 1;
+
+	printk("TCPMSS: Only works on TCP SYN packets\n");
+	return 0;
+}
+
+static struct ipt_target ipt_tcpmss_reg
+= { { NULL, NULL }, "TCPMSS",
+    ipt_tcpmss_target, ipt_tcpmss_checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_target(&ipt_tcpmss_reg);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_target(&ipt_tcpmss_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff -u --recursive --new-file v2.4.2/linux/net/ipv4/netfilter/ipt_tcpmss.c linux/net/ipv4/netfilter/ipt_tcpmss.c
--- v2.4.2/linux/net/ipv4/netfilter/ipt_tcpmss.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_tcpmss.c	Tue Mar  6 22:44:16 2001
@@ -0,0 +1,108 @@
+/* Kernel module to match TCP MSS values. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/ipt_tcpmss.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#define TH_SYN 0x02
+
+/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
+static inline int
+mssoption_match(u_int16_t min, u_int16_t max,
+		const struct tcphdr *tcp,
+		u_int16_t datalen,
+		int invert,
+		int *hotdrop)
+{
+	unsigned int i;
+	const u_int8_t *opt = (u_int8_t *)tcp;
+
+	/* If we don't have the whole header, drop packet. */
+	if (tcp->doff * 4 > datalen) {
+		*hotdrop = 1;
+		return 0;
+	}
+
+	for (i = sizeof(struct tcphdr); i < tcp->doff * 4; ) {
+		if ((opt[i] == TCPOPT_MSS)
+		    && ((tcp->doff * 4 - i) >= TCPOLEN_MSS)
+		    && (opt[i+1] == TCPOLEN_MSS)) {
+			u_int16_t mssval;
+
+			mssval = (opt[i+2] << 8) | opt[i+3];
+			
+			return (mssval >= min && mssval <= max) ^ invert;
+		}
+		if (opt[i] < 2) i++;
+		else i += opt[i+1]?:1;
+	}
+
+	return invert;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ipt_tcpmss_match_info *info = matchinfo;
+	const struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl*4;
+
+	return mssoption_match(info->mss_min, info->mss_max, tcph,
+			       skb->len - skb->nh.iph->ihl*4,
+			       info->invert, hotdrop);
+}
+
+static inline int find_syn_match(const struct ipt_entry_match *m)
+{
+	const struct ipt_tcp *tcpinfo = (const struct ipt_tcp *)m->data;
+
+	if (strcmp(m->u.kernel.match->name, "tcp") == 0
+	    && (tcpinfo->flg_cmp & TH_SYN)
+	    && !(tcpinfo->invflags & IPT_TCP_INV_FLAGS))
+		return 1;
+
+	return 0;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ipt_ip *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+	if (matchsize != IPT_ALIGN(sizeof(struct ipt_tcpmss_match_info)))
+		return 0;
+
+	/* Must specify -p tcp */
+	if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
+		printk("tcpmss: Only works on TCP packets\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match tcpmss_match
+= { { NULL, NULL }, "tcpmss", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&tcpmss_match);
+}
+
+static void __exit fini(void)
+{
+	ipt_unregister_match(&tcpmss_match);
+}
+
+module_init(init);
+module_exit(fini);
diff -u --recursive --new-file v2.4.2/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.4.2/linux/net/ipx/af_ipx.c	Wed Feb 21 18:20:47 2001
+++ linux/net/ipx/af_ipx.c	Tue Mar  6 19:28:33 2001
@@ -450,11 +450,12 @@
 	spin_lock_bh(&ipx_interfaces_lock);
 	for (i = ipx_interfaces; i;) {
 		tmp = i->if_next;
-		if (i->if_dev == dev)
+		if (i->if_dev == dev) {
 			if (event == NETDEV_UP)
 				ipxitf_hold(i);
 			else
 				__ipxitf_put(i);
+		}
 		i = tmp;
 	}
 	spin_unlock_bh(&ipx_interfaces_lock);
diff -u --recursive --new-file v2.4.2/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.4.2/linux/net/irda/af_irda.c	Sat Feb  3 19:51:33 2001
+++ linux/net/irda/af_irda.c	Fri Mar  2 11:12:12 2001
@@ -146,7 +146,7 @@
 
 	/* Close our TSAP.
 	 * If we leave it open, IrLMP put it back into the list of
-	 * unconnected LSAPs. The problem is that any incomming request
+	 * unconnected LSAPs. The problem is that any incoming request
 	 * can then be matched to this socket (and it will be, because
 	 * it is at the head of the list). This would prevent any
 	 * listening socket waiting on the same TSAP to get those requests.
@@ -229,7 +229,7 @@
 /*
  * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata)
  *
- *    Incomming connection
+ *    Incoming connection
  *
  */
 static void irda_connect_indication(void *instance, void *sap, 
@@ -285,7 +285,7 @@
 /*
  * Function irda_connect_response (handle)
  *
- *    Accept incomming connection
+ *    Accept incoming connection
  *
  */
 void irda_connect_response(struct irda_sock *self)
@@ -836,7 +836,7 @@
 /*
  * Function irda_accept (sock, newsock, flags)
  *
- *    Wait for incomming connection
+ *    Wait for incoming connection
  *
  */
 static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
@@ -1995,6 +1995,9 @@
 	if (get_user(len, optlen))
 		return -EFAULT;
 
+	if(optlen < 0)
+		return -EINVAL;
+		
 	switch (optname) {
 	case IRLMP_ENUMDEVICES:
 		/* Ask lmp for the current discovery log */
diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_core.c linux/net/irda/ircomm/ircomm_core.c
--- v2.4.2/linux/net/irda/ircomm/ircomm_core.c	Mon Nov 27 18:07:31 2000
+++ linux/net/irda/ircomm/ircomm_core.c	Fri Mar  2 11:12:12 2001
@@ -220,7 +220,7 @@
 /*
  * Function ircomm_connect_indication (self, qos, skb)
  *
- *    Notify user layer about the incomming connection
+ *    Notify user layer about the incoming connection
  *
  */
 void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_event.c linux/net/irda/ircomm/ircomm_event.c
--- v2.4.2/linux/net/irda/ircomm/ircomm_event.c	Tue Dec 21 10:17:58 1999
+++ linux/net/irda/ircomm/ircomm_event.c	Fri Mar  2 11:12:12 2001
@@ -151,7 +151,7 @@
 /*
  * Function ircomm_state_waitr (self, event, skb)
  *
- *    IrCOMM has received an incomming connection request and is awaiting
+ *    IrCOMM has received an incoming connection request and is awaiting
  *    response from the user
  */
 static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, 
diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_lmp.c linux/net/irda/ircomm/ircomm_lmp.c
--- v2.4.2/linux/net/irda/ircomm/ircomm_lmp.c	Tue Dec 21 10:17:58 1999
+++ linux/net/irda/ircomm/ircomm_lmp.c	Fri Mar  2 11:12:12 2001
@@ -219,7 +219,7 @@
 /*
  * Function ircomm_lmp_data_indication (instance, sap, skb)
  *
- *    Incomming data which we must deliver to the state machine, to check
+ *    Incoming data which we must deliver to the state machine, to check
  *    we are still connected.
  */
 int ircomm_lmp_data_indication(void *instance, void *sap,
diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_ttp.c linux/net/irda/ircomm/ircomm_ttp.c
--- v2.4.2/linux/net/irda/ircomm/ircomm_ttp.c	Tue Dec 21 10:17:58 1999
+++ linux/net/irda/ircomm/ircomm_ttp.c	Fri Mar  2 11:12:12 2001
@@ -156,7 +156,7 @@
 /*
  * Function ircomm_ttp_data_indication (instance, sap, skb)
  *
- *    Incomming data
+ *    Incoming data
  *
  */
 int ircomm_ttp_data_indication(void *instance, void *sap,
diff -u --recursive --new-file v2.4.2/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- v2.4.2/linux/net/irda/ircomm/ircomm_tty.c	Mon Nov 27 18:07:31 2000
+++ linux/net/irda/ircomm/ircomm_tty.c	Fri Mar  2 11:12:12 2001
@@ -1106,7 +1106,7 @@
 /*
  * Function ircomm_tty_data_indication (instance, sap, skb)
  *
- *    Handle incomming data, and deliver it to the line discipline
+ *    Handle incoming data, and deliver it to the line discipline
  *
  */
 static int ircomm_tty_data_indication(void *instance, void *sap,
@@ -1155,7 +1155,7 @@
 /*
  * Function ircomm_tty_control_indication (instance, sap, skb)
  *
- *    Parse all incomming parameters (easy!)
+ *    Parse all incoming parameters (easy!)
  *
  */
 static int ircomm_tty_control_indication(void *instance, void *sap,
diff -u --recursive --new-file v2.4.2/linux/net/irda/irias_object.c linux/net/irda/irias_object.c
--- v2.4.2/linux/net/irda/irias_object.c	Mon Jan  1 09:54:07 2001
+++ linux/net/irda/irias_object.c	Fri Mar  2 11:12:12 2001
@@ -162,7 +162,7 @@
 	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
 	ASSERT(attrib != NULL, return -1;);
 
-	/* Remove atribute from object */
+	/* Remove attribute from object */
 	node = hashbin_remove(obj->attribs, 0, attrib->name);
 	if (!node)
 		return 0; /* Already removed or non-existent */
diff -u --recursive --new-file v2.4.2/linux/net/irda/irlan/irlan_provider.c linux/net/irda/irlan/irlan_provider.c
--- v2.4.2/linux/net/irda/irlan/irlan_provider.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/irlan/irlan_provider.c	Fri Mar  2 11:12:12 2001
@@ -162,7 +162,7 @@
 /*
  * Function irlan_provider_connect_response (handle)
  *
- *    Accept incomming connection
+ *    Accept incoming connection
  *
  */
 void irlan_provider_connect_response(struct irlan_cb *self,
@@ -371,7 +371,7 @@
 /*
  * Function irlan_provider_register(void)
  *
- *    Register provider support so we can accept incomming connections.
+ *    Register provider support so we can accept incoming connections.
  * 
  */
 int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
diff -u --recursive --new-file v2.4.2/linux/net/irda/irlap.c linux/net/irda/irlap.c
--- v2.4.2/linux/net/irda/irlap.c	Wed Feb 21 18:20:47 2001
+++ linux/net/irda/irlap.c	Fri Mar  2 11:12:12 2001
@@ -51,6 +51,7 @@
 hashbin_t *irlap = NULL;
 int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
 
+extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb);
 static void __irlap_close(struct irlap_cb *self);
 
 static char *lap_reasons[] = {
@@ -241,7 +242,7 @@
 /*
  * Function irlap_connect_response (self, skb)
  *
- *    Service user has accepted incomming connection
+ *    Service user has accepted incoming connection
  *
  */
 void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb) 
diff -u --recursive --new-file v2.4.2/linux/net/irda/irlap_comp.c linux/net/irda/irlap_comp.c
--- v2.4.2/linux/net/irda/irlap_comp.c	Sat Nov 11 18:11:22 2000
+++ linux/net/irda/irlap_comp.c	Fri Mar  2 11:12:12 2001
@@ -92,7 +92,7 @@
 /*
  * Function irda_set_compression (self, proto)
  *
- *    The the compression protocol to be used by this session
+ *    The compression protocol to be used by this session
  *
  */
 int irda_set_compression( struct irlap_cb *self, int proto)
diff -u --recursive --new-file v2.4.2/linux/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- v2.4.2/linux/net/irda/irlap_event.c	Wed Feb 21 18:20:47 2001
+++ linux/net/irda/irlap_event.c	Fri Mar  2 11:12:12 2001
@@ -546,7 +546,7 @@
 		break;
 	case SLOT_TIMER_EXPIRED:
 		/*
-		 * Wait a little longer if we detect an incomming frame. This
+		 * Wait a little longer if we detect an incoming frame. This
 		 * is not mentioned in the spec, but is a good thing to do, 
 		 * since we want to work even with devices that violate the
 		 * timing requirements.
diff -u --recursive --new-file v2.4.2/linux/net/irda/irlmp.c linux/net/irda/irlmp.c
--- v2.4.2/linux/net/irda/irlmp.c	Wed Feb 21 18:20:47 2001
+++ linux/net/irda/irlmp.c	Fri Mar  2 11:12:12 2001
@@ -450,7 +450,7 @@
 /*
  * Function irlmp_connect_indication (self)
  *
- *    Incomming connection
+ *    Incoming connection
  *
  */
 void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) 
diff -u --recursive --new-file v2.4.2/linux/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c
--- v2.4.2/linux/net/irda/irlmp_frame.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/irlmp_frame.c	Fri Mar  2 11:12:12 2001
@@ -470,7 +470,7 @@
 	lsap = (struct lsap_cb *) hashbin_get_first(queue);
 	while (lsap != NULL) {
 		/* 
-		 *  If this is an incomming connection, then the destination 
+		 *  If this is an incoming connection, then the destination 
 		 *  LSAP selector may have been specified as LM_ANY so that 
 		 *  any client can connect. In that case we only need to check
 		 *  if the source LSAP (in our view!) match!
diff -u --recursive --new-file v2.4.2/linux/net/irda/irnet/Config.in linux/net/irda/irnet/Config.in
--- v2.4.2/linux/net/irda/irnet/Config.in	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/irnet/Config.in	Fri Mar  2 11:12:12 2001
@@ -1 +1,4 @@
-dep_tristate '  IrNET protocol' CONFIG_IRNET $CONFIG_IRDA
+if [ "$CONFIG_NETDEVICES" != "n" ]; then
+   dep_tristate '  IrNET protocol' CONFIG_IRNET $CONFIG_IRDA $CONFIG_PPP
+fi
+
diff -u --recursive --new-file v2.4.2/linux/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h
--- v2.4.2/linux/net/irda/irnet/irnet.h	Mon Dec 11 13:33:14 2000
+++ linux/net/irda/irnet/irnet.h	Fri Mar  2 11:12:12 2001
@@ -9,7 +9,7 @@
  * what's in there...
  *
  * Note : as most part of the Linux kernel, this module is available
- * under the GNU Public License (GPL).
+ * under the GNU General Public License (GPL).
  */
 
 #ifndef IRNET_H
@@ -52,14 +52,14 @@
  *	o multipoint operation (limited by IrLAP specification)
  *	o information in /proc/net/irda/irnet
  *	o IrNET events on /dev/irnet (for user space daemon)
- *	o IrNET deamon (irnetd) to automatically handle incomming requests
+ *	o IrNET deamon (irnetd) to automatically handle incoming requests
  *	o Windows 2000 compatibility (tested, but need more work)
  * Currently missing :
  *	o Lot's of testing (that's your job)
  *	o Connection retries (may be too hard to do)
  *	o Check pppd persist mode
- *	o User space deamon (to automatically handle incomming requests)
- *	o A registered device number (comming, waiting from an answer) 
+ *	o User space deamon (to automatically handle incoming requests)
+ *	o A registered device number (coming, waiting from an answer) 
  *	o Final integration in Linux-IrDA (up to Dag) 
  *
  * The setup is not currently the most easy, but this should get much
@@ -109,16 +109,16 @@
  * and allow to offer the event channel, useful for other stuff like debug.
  *
  * On the other hand, this require a loose coordination between the
- * present module and irnetd. One critical area is how incomming request
+ * present module and irnetd. One critical area is how incoming request
  * are handled.
- * When irnet receive an incomming request, it send an event to irnetd and
- * drop the incomming IrNET socket.
+ * When irnet receive an incoming request, it send an event to irnetd and
+ * drop the incoming IrNET socket.
  * irnetd start a pppd instance, which create a new IrNET socket. This new
  * socket is then connected in the originating node to the pppd instance.
  * At this point, in the originating node, the first socket is closed.
  *
  * I admit, this is a bit messy and waste some ressources. The alternative
- * is caching incomming socket, and that's also quite messy and waste
+ * is caching incoming socket, and that's also quite messy and waste
  * ressources.
  * We also make connection time slower. For example, on a 115 kb/s link it
  * adds 60ms to the connection time (770 ms). However, this is slower than
diff -u --recursive --new-file v2.4.2/linux/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- v2.4.2/linux/net/irda/irnet/irnet_irda.c	Sun Nov 12 20:40:42 2000
+++ linux/net/irda/irnet/irnet_irda.c	Fri Mar  2 11:12:12 2001
@@ -523,7 +523,7 @@
 /*
  * The IrNET service is composed of one server socket and a variable
  * number of regular IrNET sockets. The server socket is supposed to
- * handle incomming connections and redirect them to one IrNET sockets.
+ * handle incoming connections and redirect them to one IrNET sockets.
  * It's a superset of the regular IrNET socket, but has a very distinct
  * behaviour...
  */
@@ -662,7 +662,7 @@
 /*
  * Function irda_connect_socket (self)
  *
- *    Connect an incomming connection to the socket
+ *    Connect an incoming connection to the socket
  *
  */
 static inline int
@@ -721,7 +721,7 @@
 /*
  * Function irda_disconnect_server (self)
  *
- *    Cleanup the server socket when the incomming connection abort
+ *    Cleanup the server socket when the incoming connection abort
  *
  */
 static inline void
@@ -1097,7 +1097,7 @@
 /*
  * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata)
  *
- *    Incomming connection
+ *    Incoming connection
  *
  * In theory, this function is called only on the server socket.
  * Some other node is attempting to connect to the IrNET service, and has
diff -u --recursive --new-file v2.4.2/linux/net/sched/Makefile linux/net/sched/Makefile
--- v2.4.2/linux/net/sched/Makefile	Fri Dec 29 14:07:24 2000
+++ linux/net/sched/Makefile	Tue Mar  6 22:44:15 2001
@@ -1,182 +1,34 @@
 #
 # Makefile for the Linux Traffic Control Unit.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := sched.o
 
 obj-y	:= sch_generic.o
 
-ifeq ($(CONFIG_NET_SCHED), y)
 
-obj-y += sch_api.o sch_fifo.o
-
-ifeq ($(CONFIG_NET_ESTIMATOR), y)
-obj-y += estimator.o
-endif
-
-ifeq ($(CONFIG_NET_CLS), y)
-obj-y += cls_api.o
-
-ifeq ($(CONFIG_NET_CLS_POLICE), y)
-obj-y += police.o
-endif
-
-endif
-
-ifeq ($(CONFIG_NET_SCH_INGRESS), y)
-obj-y += sch_ingress.o 
-else
-  ifeq ($(CONFIG_NET_SCH_INGRESS), m)
-	obj-m += sch_ingress.o 
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_CBQ), y)
-obj-y += sch_cbq.o
-else
-  ifeq ($(CONFIG_NET_SCH_CBQ), m)
-	obj-m += sch_cbq.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_CSZ), y)
-obj-y += sch_csz.o
-else
-  ifeq ($(CONFIG_NET_SCH_CSZ), m)
-	obj-m += sch_csz.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_HPFQ), y)
-obj-y += sch_hpfq.o
-else
-  ifeq ($(CONFIG_NET_SCH_HPFQ), m)
-	obj-m += sch_hpfq.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_HFSC), y)
-obj-y += sch_hfsc.o
-else
-  ifeq ($(CONFIG_NET_SCH_HFSC), m)
-	obj-m += sch_hfsc.o
-  endif
-endif
-
-
-ifeq ($(CONFIG_NET_SCH_SFQ), y)
-obj-y += sch_sfq.o
-else
-  ifeq ($(CONFIG_NET_SCH_SFQ), m)
-	obj-m += sch_sfq.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_RED), y)
-obj-y += sch_red.o
-else
-  ifeq ($(CONFIG_NET_SCH_RED), m)
-	obj-m += sch_red.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_TBF), y)
-obj-y += sch_tbf.o
-else
-  ifeq ($(CONFIG_NET_SCH_TBF), m)
-	obj-m += sch_tbf.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_PRIO), y)
-obj-y += sch_prio.o
-else
-  ifeq ($(CONFIG_NET_SCH_PRIO), m)
-	obj-m += sch_prio.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_TEQL), y)
-obj-y += sch_teql.o
-else
-  ifeq ($(CONFIG_NET_SCH_TEQL), m)
-	obj-m += sch_teql.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_GRED), y)
-obj-y += sch_gred.o
-else
-  ifeq ($(CONFIG_NET_SCH_GRED), m)
-       obj-m += sch_gred.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_DSMARK), y)
-obj-y += sch_dsmark.o
-else
-  ifeq ($(CONFIG_NET_SCH_DSMARK), m)
-       obj-m += sch_dsmark.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_CLS_TCINDEX), y)
-obj-y += cls_tcindex.o
-else
-  ifeq ($(CONFIG_NET_CLS_TCINDEX), m)
-       obj-m += cls_tcindex.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_SCH_ATM), y)
-obj-y += sch_atm.o
-endif
-
-ifeq ($(CONFIG_NET_CLS_U32), y)
-obj-y += cls_u32.o
-else
-  ifeq ($(CONFIG_NET_CLS_U32), m)
-	obj-m += cls_u32.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_CLS_RSVP), y)
-obj-y += cls_rsvp.o
-else
-  ifeq ($(CONFIG_NET_CLS_RSVP), m)
-	obj-m += cls_rsvp.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_CLS_RSVP6), y)
-obj-y += cls_rsvp6.o
-else
-  ifeq ($(CONFIG_NET_CLS_RSVP6), m)
-	obj-m += cls_rsvp6.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_CLS_ROUTE4), y)
-obj-y += cls_route.o
-else
-  ifeq ($(CONFIG_NET_CLS_ROUTE4), m)
-	obj-m += cls_route.o
-  endif
-endif
-
-ifeq ($(CONFIG_NET_CLS_FW), y)
-obj-y += cls_fw.o
-else
-  ifeq ($(CONFIG_NET_CLS_FW), m)
-	obj-m += cls_fw.o
-  endif
-endif
-
-endif
+obj-$(CONFIG_NET_SCHED)		+= sch_api.o sch_fifo.o
+obj-$(CONFIG_NET_ESTIMATOR)	+= estimator.o
+obj-$(CONFIG_NET_CLS)		+= cls_api.o
+obj-$(CONFIG_NET_CLS_POLICE)	+= police.o
+obj-$(CONFIG_NET_SCH_INGRESS)	+= sch_ingress.o 
+obj-$(CONFIG_NET_SCH_CBQ)	+= sch_cbq.o
+obj-$(CONFIG_NET_SCH_CSZ)	+= sch_csz.o
+obj-$(CONFIG_NET_SCH_HPFQ)	+= sch_hpfq.o
+obj-$(CONFIG_NET_SCH_HFSC)	+= sch_hfsc.o
+obj-$(CONFIG_NET_SCH_SFQ)	+= sch_sfq.o
+obj-$(CONFIG_NET_SCH_RED)	+= sch_red.o
+obj-$(CONFIG_NET_SCH_TBF)	+= sch_tbf.o
+obj-$(CONFIG_NET_SCH_PRIO)	+= sch_prio.o
+obj-$(CONFIG_NET_SCH_TEQL)	+= sch_teql.o
+obj-$(CONFIG_NET_SCH_GRED)	+= sch_gred.o
+obj-$(CONFIG_NET_SCH_DSMARK)	+= sch_dsmark.o
+obj-$(CONFIG_NET_CLS_TCINDEX)	+= cls_tcindex.o
+obj-$(CONFIG_NET_SCH_ATM)	+= sch_atm.o
+obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
+obj-$(CONFIG_NET_CLS_RSVP)	+= cls_rsvp.o
+obj-$(CONFIG_NET_CLS_RSVP6)	+= cls_rsvp6.o
+obj-$(CONFIG_NET_CLS_ROUTE4)	+= cls_route.o
+obj-$(CONFIG_NET_CLS_FW)	+= cls_fw.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.2/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c
--- v2.4.2/linux/net/sched/cls_tcindex.c	Fri Aug 18 10:26:25 2000
+++ linux/net/sched/cls_tcindex.c	Tue Mar  6 22:44:15 2001
@@ -339,7 +339,7 @@
 static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
 {
 	struct tcindex_data *p = PRIV(tp);
-	struct tcindex_filter *f;
+	struct tcindex_filter *f,*next;
 	int i;
 
 	DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p);
@@ -361,7 +361,8 @@
 	if (!p->h)
 		return;
 	for (i = 0; i < p->hash; i++) {
-		for (f = p->h[i]; f; f = f->next) {
+		for (f = p->h[i]; f; f = next) {
+			next = f->next;
 			if (walker->count >= walker->skip) {
 				if (walker->fn(tp,(unsigned long) &f->result,
 				    walker) < 0) {
diff -u --recursive --new-file v2.4.2/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c
--- v2.4.2/linux/net/sched/sch_cbq.c	Tue Jul 11 19:02:37 2000
+++ linux/net/sched/sch_cbq.c	Tue Mar  6 22:44:15 2001
@@ -506,7 +506,7 @@
 			}
 		}
 
-		q->wd_expires = delay;
+		q->wd_expires = base_delay;
 	}
 }
 
diff -u --recursive --new-file v2.4.2/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.4.2/linux/net/sunrpc/svcsock.c	Wed Feb 21 18:20:50 2001
+++ linux/net/sunrpc/svcsock.c	Wed Mar 14 14:37:36 2001
@@ -212,16 +212,20 @@
 svc_sock_release(struct svc_rqst *rqstp)
 {
 	struct svc_sock	*svsk = rqstp->rq_sock;
+	struct svc_serv	*serv = svsk->sk_server;
 
-	if (!svsk)
-		return;
 	svc_release_skb(rqstp);
 	rqstp->rq_sock = NULL;
+
+	spin_lock_bh(&serv->sv_lock);
 	if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+		spin_unlock_bh(&serv->sv_lock);
 		dprintk("svc: releasing dead socket\n");
 		sock_release(svsk->sk_sock);
 		kfree(svsk);
 	}
+	else
+		spin_unlock_bh(&serv->sv_lock);
 }
 
 /*
@@ -1034,14 +1038,15 @@
 	if (svsk->sk_qued)
 		rpc_remove_list(&serv->sv_sockets, svsk);
 
-	spin_unlock_bh(&serv->sv_lock);
 
 	svsk->sk_dead = 1;
 
 	if (!svsk->sk_inuse) {
+		spin_unlock_bh(&serv->sv_lock);
 		sock_release(svsk->sk_sock);
 		kfree(svsk);
 	} else {
+		spin_unlock_bh(&serv->sv_lock);
 		printk(KERN_NOTICE "svc: server socket destroy delayed\n");
 		/* svsk->sk_server = NULL; */
 	}
diff -u --recursive --new-file v2.4.2/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.4.2/linux/net/unix/af_unix.c	Wed Feb 21 18:20:50 2001
+++ linux/net/unix/af_unix.c	Tue Mar  6 19:44:37 2001
@@ -1852,8 +1852,8 @@
 extern void unix_sysctl_register(void);
 extern void unix_sysctl_unregister(void);
 #else
-static inline unix_sysctl_register() {};
-static inline unix_sysctl_unregister() {};
+static inline void unix_sysctl_register(void) {}
+static inline void unix_sysctl_unregister(void) {}
 #endif
 
 static const char banner[] __initdata = KERN_INFO "NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.\n";
diff -u --recursive --new-file v2.4.2/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.4.2/linux/scripts/mkdep.c	Wed Sep 27 14:09:30 2000
+++ linux/scripts/mkdep.c	Fri Mar  2 11:12:12 2001
@@ -2,7 +2,7 @@
  * Originally by Linus Torvalds.
  * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
  *
- * Usage: mkdep file ...
+ * Usage: mkdep cflags -- file ...
  * 
  * Read source files and output makefile dependency lines for them.
  * I make simple dependency lines for #include <*.h> and #include "*.h".
@@ -22,10 +22,17 @@
  * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
  * - Changed so that 'filename.o' depends upon 'filename.[cS]'.  This is so that
  *   missing source files are noticed, rather than silently ignored.
+ *
+ * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
+ * - Accept cflags followed by '--' followed by filenames.  mkdep extracts -I
+ *   options from cflags and looks in the specified directories as well as the
+ *   defaults.   Only -I is supported, no attempt is made to handle -idirafter,
+ *   -isystem, -I- etc.
  */
 
 #include <ctype.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -44,11 +51,10 @@
 
 struct path_struct {
 	int len;
-	char buffer[256-sizeof(int)];
-} path_array[2] = {
-	{  0, "" },
-	{  0, "" }
+	char *buffer;
 };
+struct path_struct *path_array;
+int paths;
 
 
 /* Current input file */
@@ -181,9 +187,10 @@
 /*
  * Handle an #include line.
  */
-void handle_include(int type, const char * name, int len)
+void handle_include(int start, const char * name, int len)
 {
-	struct path_struct *path = path_array+type;
+	struct path_struct *path;
+	int i;
 
 	if (len == 14 && !memcmp(name, "linux/config.h", len))
 		return;
@@ -191,13 +198,58 @@
 	if (len >= 7 && !memcmp(name, "config/", 7))
 		define_config(name+7, len-7-2);
 
-	memcpy(path->buffer+path->len, name, len);
-	path->buffer[path->len+len] = '\0';
-	if (access(path->buffer, F_OK) != 0)
-		return;
+	for (i = start, path = path_array+start; i < paths; ++i, ++path) {
+		memcpy(path->buffer+path->len, name, len);
+		path->buffer[path->len+len] = '\0';
+		if (access(path->buffer, F_OK) == 0) {
+			do_depname();
+			printf(" \\\n   %s", path->buffer);
+			return;
+		}
+	}
 
-	do_depname();
-	printf(" \\\n   %s", path->buffer);
+}
+
+
+
+/*
+ * Add a path to the list of include paths.
+ */
+void add_path(const char * name)
+{
+	struct path_struct *path;
+	char resolved_path[PATH_MAX+1];
+	const char *name2;
+
+	if (strcmp(name, ".")) {
+		name2 = realpath(name, resolved_path);
+		if (!name2) {
+			fprintf(stderr, "realpath(%s) failed, %m\n", name);
+			exit(1);
+		}
+	}
+	else {
+		name2 = "";
+	}
+
+	path_array = realloc(path_array, (++paths)*sizeof(*path_array));
+	if (!path_array) {
+		fprintf(stderr, "cannot expand path_arry\n");
+		exit(1);
+	}
+
+	path = path_array+paths-1;
+	path->len = strlen(name2);
+	path->buffer = malloc(path->len+1+256+1);
+	if (!path->buffer) {
+		fprintf(stderr, "cannot allocate path buffer\n");
+		exit(1);
+	}
+	strcpy(path->buffer, name2);
+	if (path->len && *(path->buffer+path->len-1) != '/') {
+		*(path->buffer+path->len) = '/';
+		*(path->buffer+(++(path->len))) = '\0';
+	}
 }
 
 
@@ -210,7 +262,7 @@
 	char *pc;
 	int i;
 
-	pc = path_array[0].buffer + path_array[0].len;
+	pc = path_array[paths-1].buffer + path_array[paths-1].len;
 	memcpy(pc, "config/", 7);
 	pc += 7;
 
@@ -228,7 +280,7 @@
 	define_config(pc, len);
 
 	do_depname();
-	printf(" \\\n   $(wildcard %s.h)", path_array[0].buffer);
+	printf(" \\\n   $(wildcard %s.h)", path_array[paths-1].buffer);
 }
 
 
@@ -387,7 +439,7 @@
 	GETNEXT
 	CASE('\n', start);
 	NOTCASE('"', pound_include_dquote);
-	handle_include(1, map_dot, next - map_dot - 1);
+	handle_include(0, map_dot, next - map_dot - 1);
 	goto start;
 
 /* #\s*include\s*<(.*)> */
@@ -395,7 +447,7 @@
 	GETNEXT
 	CASE('\n', start);
 	NOTCASE('>', pound_include_langle);
-	handle_include(0, map_dot, next - map_dot - 1);
+	handle_include(1, map_dot, next - map_dot - 1);
 	goto start;
 
 /* #\s*d */
@@ -524,7 +576,7 @@
 int main(int argc, char **argv)
 {
 	int len;
-	char *hpath;
+	const char *hpath;
 
 	hpath = getenv("HPATH");
 	if (!hpath) {
@@ -532,12 +584,26 @@
 		      "Don't bypass the top level Makefile.\n", stderr);
 		return 1;
 	}
-	len = strlen(hpath);
-	memcpy(path_array[0].buffer, hpath, len);
-	if (len && hpath[len-1] != '/')
-		path_array[0].buffer[len++] = '/';
-	path_array[0].buffer[len] = '\0';
-	path_array[0].len = len;
+
+	add_path(".");		/* for #include "..." */
+
+	while (++argv, --argc > 0) {
+		if (strncmp(*argv, "-I", 2) == 0) {
+			if (*((*argv)+2)) {
+				add_path((*argv)+2);
+			}
+			else {
+				++argv;
+				--argc;
+				add_path(*argv);
+			}
+		}
+		else if (strcmp(*argv, "--") == 0) {
+			break;
+		}
+	}
+
+	add_path(hpath);	/* must be last entry, for config files */
 
 	while (--argc > 0) {
 		const char * filename = *++argv;
diff -u --recursive --new-file v2.4.2/linux/scripts/ver_linux linux/scripts/ver_linux
--- v2.4.2/linux/scripts/ver_linux	Sun Sep 17 09:45:06 2000
+++ linux/scripts/ver_linux	Fri Mar  2 11:12:12 2001
@@ -5,30 +5,64 @@
 # differ on your system.
 #
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
-echo '-- Versions installed: (if some fields are empty or look'
-echo '-- unusual then possibly you have very old versions)'
+echo 'If some fields are empty or look unusual you may have an old version.'
+echo 'Compare to the current minimal requirements in Documentation/Changes.'
+echo ' '
+
 uname -a
-insmod -V  2>&1 | awk 'NR==1 {print "Kernel modules        ",$NF}'
+echo ' '
+
 echo "Gnu C                 " `gcc --version`
+
 make --version 2>&1 | awk -F, '{print $1}' | awk \
-      '/GNU Make/{print "Gnu Make              ",$NF}'
+      '/GNU Make/{print "Gnu make              ",$NF}'
+
 ld -v 2>&1 | awk -F\) '{print $1}' | awk \
-      '/BFD/{print "Binutils              ",$NF}'
-ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed -e 's/\.so$//' \
-  | awk -F'[.-]'   '{print "Linux C Library        " $(NF-2)"."$(NF-1)"."$NF}'
-echo -n "Dynamic linker         "
-ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1
+      '/BFD/{print "binutils              ",$NF}'
+
+mount --version | awk -F\- '{print "util-linux            ", $NF}'
+
+insmod -V  2>&1 | awk 'NR==1 {print "modutils              ",$NF}'
+
+tune2fs 2>&1 | grep tune2fs | sed 's/,//' |  awk \
+'NR==1 {print "e2fsprogs             ", $2}'
+
+reiserfsck 2>&1 | grep reiserfsprogs | awk \
+'NR==1{print "reiserfsprogs         ", $NF}'
+
+cardmgr -V 2>&1| grep version | awk \
+'NR==1{print "pcmcia-cs             ", $3}'
+
+pppd --version 2>&1| grep version | awk \
+'NR==1{print "PPP                   ", $3}'
+
+isdnctrl 2>&1 | grep version | awk \
+'NR==1{print "isdn4k-utils          ", $NF}'
+
+ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed \
+-e 's/\.so$//' | awk -F'[.-]'   '{print "Linux C Library        " \
+$(NF-2)"."$(NF-1)"."$NF}'
+
+ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 | awk \
+'NR==1{print "Dynamic linker (ldd)  ", $NF}'
+
 ls -l /usr/lib/lib{g,stdc}++.so  2>/dev/null | awk -F. \
        '{print "Linux C++ Library      " $4"."$5"."$6}'
+
 ps --version 2>&1 | awk 'NR==1{print "Procps                ", $NF}'
-mount --version | awk -F\- '{print "Mount                 ", $NF}'
-hostname -V 2>&1 | awk 'NR==1{print "Net-tools             ", $NF}'
+
+ifconfig --version 2>&1 | grep tools | awk \
+'NR==1{print "Net-tools             ", $NF}'
+
 # Kbd needs 'loadkeys -h',
 loadkeys -h 2>&1 | awk \
 '(NR==1 && ($3 !~ /option/)) {print "Kbd                   ", $3}'
+
 # while console-tools needs 'loadkeys -V'.
 loadkeys -V 2>&1 | awk \
 '(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools         ", $3}'
+
 expr --v 2>&1 | awk 'NR==1{print "Sh-utils              ", $NF}'
+
 X=`cat /proc/modules | sed -e "s/ .*$//"`
 echo "Modules Loaded         "$X
